Back to index

unity  6.0.0
IconRenderer.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Canonical Ltd
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License version 3 as
00006  * published by the Free Software Foundation.
00007  *
00008  * This program is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Authored by: Jason Smith <jason.smith@canonical.com>
00017  */
00018 
00019 #include "config.h"
00020 #include <math.h>
00021 
00022 #include <Nux/Nux.h>
00023 #include <Nux/WindowCompositor.h>
00024 #include <NuxGraphics/NuxGraphics.h>
00025 #include <NuxGraphics/GpuDevice.h>
00026 #include <NuxGraphics/GLTextureResourceManager.h>
00027 
00028 #include <NuxGraphics/CairoGraphics.h>
00029 
00030 #include <gtk/gtk.h>
00031 
00032 #include <pango/pango.h>
00033 #include <pango/pangocairo.h>
00034 
00035 #include "IconRenderer.h"
00036 
00037 namespace unity
00038 {
00039 namespace ui
00040 {
00041 
00042 #ifdef USE_GLES
00043   #define VertexShaderHeader   "#version 100\n"
00044   #define FragmentShaderHeader "#version 100\n precision mediump float;\n"
00045 #else
00046   #define VertexShaderHeader   "#version 120\n"
00047   #define FragmentShaderHeader "#version 110\n"
00048 #endif
00049 
00050 /*
00051   Use this shader to pass vertices in screen coordinates in the C++ code and compute use
00052   the fragment shader to perform the texture perspective correct division.
00053   This shader assume the following:
00054     - the projection matrix is orthogonal: glOrtho(0, ScreenWidth, ScreenWidth, 0, Near, Far)
00055     - vertices x and y are in screen coordinates: Vertex(x_screen, y_screen, 0, 1.0)
00056     - the vertices w coordinates has been computed 'manually'
00057     - vertices uv textture coordinates are passed to the shader as:  (u/w, v/w, 0, 1/w)
00058 
00059   The texture coordinates s=u/w, t=v/w and q=1w are interpolated linearly in screen coordinates.
00060   In the fragment shader we get the texture coordinates used for the sampling by dividing
00061   s and t resulting from the interpolation by q.
00062 
00063 */
00064 
00065 // halfed lumin values to provide darkening while desaturating in shader
00066 #define LUMIN_RED "0.30"
00067 #define LUMIN_GREEN "0.59"
00068 #define LUMIN_BLUE "0.11"
00069 
00070 nux::NString gPerspectiveCorrectShader = TEXT(
00071 "[Vertex Shader]                                    \n"
00072 VertexShaderHeader
00073 "uniform mat4 ViewProjectionMatrix;                 \n\
00074                                                     \n\
00075 attribute vec4 iTexCoord0;                          \n\
00076 attribute vec4 iVertex;                             \n\
00077                                                     \n\
00078 varying vec4 varyTexCoord0;                         \n\
00079                                                     \n\
00080 void main()                                         \n\
00081 {                                                   \n\
00082     varyTexCoord0 = iTexCoord0;                     \n\
00083     gl_Position =  ViewProjectionMatrix * iVertex;  \n\
00084 }                                                   \n\
00085                                                     \n\
00086 [Fragment Shader]                                   \n"
00087 FragmentShaderHeader
00088 "                                                   \n\
00089 varying vec4 varyTexCoord0;                         \n\
00090                                                     \n\
00091 uniform sampler2D TextureObject0;                   \n\
00092 uniform vec4 color0;                                \n\
00093 uniform vec4 desat_factor;                          \n\
00094 uniform vec4 colorify_color;                        \n\
00095 vec4 SampleTexture(sampler2D TexObject, vec4 TexCoord) \n\
00096 {                                                   \n\
00097   return texture2D(TexObject, TexCoord.st);         \n\
00098 }                                                   \n\
00099                                                     \n\
00100 void main()                                         \n\
00101 {                                                   \n\
00102   vec4 tex = varyTexCoord0;                         \n\
00103   tex.s = tex.s/varyTexCoord0.w;                    \n\
00104   tex.t = tex.t/varyTexCoord0.w;                    \n\
00105                                                     \n\
00106   vec4 texel = color0 * SampleTexture(TextureObject0, tex);  \n\
00107   vec4 desat = vec4 (" LUMIN_RED "*texel.r + " LUMIN_GREEN "*texel.g + " LUMIN_BLUE "*texel.b);  \n\
00108   vec4 final_color = (vec4 (1.0, 1.0, 1.0, 1.0) - desat_factor) * desat + desat_factor * texel; \n\
00109   final_color = colorify_color * final_color;       \n\
00110   final_color.a = texel.a;                          \n\
00111   gl_FragColor = final_color;                       \n\
00112 }                                                   \n\
00113 ");
00114 
00115 nux::NString PerspectiveCorrectVtx = TEXT(
00116 "!!ARBvp1.0                                 \n\
00117 ATTRIB iPos         = vertex.position;      \n\
00118 ATTRIB iColor       = vertex.attrib[3];     \n\
00119 PARAM  mvp[4]       = {state.matrix.mvp};   \n\
00120 OUTPUT oPos         = result.position;      \n\
00121 OUTPUT oColor       = result.color;         \n\
00122 OUTPUT oTexCoord0   = result.texcoord[0];   \n\
00123 # Transform the vertex to clip coordinates. \n\
00124 DP4   oPos.x, mvp[0], iPos;                 \n\
00125 DP4   oPos.y, mvp[1], iPos;                 \n\
00126 DP4   oPos.z, mvp[2], iPos;                 \n\
00127 DP4   oPos.w, mvp[3], iPos;                 \n\
00128 MOV   oColor, iColor;                       \n\
00129 MOV   oTexCoord0, vertex.attrib[8];         \n\
00130 END");
00131 
00132 nux::NString PerspectiveCorrectTexFrg = TEXT(
00133 "!!ARBfp1.0                                                   \n\
00134 PARAM color0 = program.local[0];                              \n\
00135 PARAM factor = program.local[1];                              \n\
00136 PARAM colorify_color = program.local[2];                      \n\
00137 PARAM luma = {" LUMIN_RED ", " LUMIN_GREEN ", " LUMIN_BLUE ", 0.0}; \n\
00138 TEMP temp;                                                    \n\
00139 TEMP pcoord;                                                  \n\
00140 TEMP tex0;                                                    \n\
00141 TEMP desat;                                                   \n\
00142 TEMP color;                                                   \n\
00143 MOV pcoord, fragment.texcoord[0].w;                           \n\
00144 RCP temp, fragment.texcoord[0].w;                             \n\
00145 MUL pcoord.xy, fragment.texcoord[0], temp;                    \n\
00146 TEX tex0, pcoord, texture[0], 2D;                             \n\
00147 MUL color, color0, tex0;                                      \n\
00148 DP4 desat, luma, color;                                       \n\
00149 LRP temp, factor.x, color, desat;                             \n\
00150 MUL result.color.rgb, temp, colorify_color;                   \n\
00151 MOV result.color.a, color;                                    \n\
00152 END");
00153 
00154 nux::NString PerspectiveCorrectTexRectFrg = TEXT(
00155 "!!ARBfp1.0                                                   \n\
00156 PARAM color0 = program.local[0];                              \n\
00157 PARAM factor = program.local[1];                              \n\
00158 PARAM colorify_color = program.local[2];                      \n\
00159 PARAM luma = {" LUMIN_RED ", " LUMIN_GREEN ", " LUMIN_BLUE ", 0.0}; \n\
00160 TEMP temp;                                                    \n\
00161 TEMP pcoord;                                                  \n\
00162 TEMP tex0;                                                    \n\
00163 MOV pcoord, fragment.texcoord[0].w;                           \n\
00164 RCP temp, fragment.texcoord[0].w;                             \n\
00165 MUL pcoord.xy, fragment.texcoord[0], temp;                    \n\
00166 TEX tex0, pcoord, texture[0], RECT;                           \n\
00167 MUL color, color0, tex0;                                      \n\
00168 DP4 desat, luma, color;                                       \n\
00169 LRP temp, factor.x, color, desat;                             \n\
00170 MUL result.color.rgb, temp, colorify_color;                   \n\
00171 MOV result.color.a, color;                                    \n\
00172 END");
00173 
00174 // The local namespace is purely for namespacing the file local variables below.
00175 namespace local
00176 {
00177 namespace
00178 {
00179 enum IconSize
00180 {
00181   SMALL = 0,
00182   BIG,
00183   LAST,
00184 };
00185 
00186 bool textures_created = false;
00187 nux::BaseTexture* progress_bar_trough = 0;
00188 nux::BaseTexture* progress_bar_fill = 0;
00189 nux::BaseTexture* pip_ltr = 0;
00190 nux::BaseTexture* pip_rtl = 0;
00191 nux::BaseTexture* arrow_ltr = 0;
00192 nux::BaseTexture* arrow_rtl = 0;
00193 nux::BaseTexture* arrow_empty_ltr = 0;
00194 nux::BaseTexture* arrow_empty_rtl = 0;
00195 
00196 nux::BaseTexture* squircle_base = 0;
00197 nux::BaseTexture* squircle_base_selected = 0;
00198 nux::BaseTexture* squircle_edge = 0;
00199 nux::BaseTexture* squircle_glow = 0;
00200 nux::BaseTexture* squircle_shadow = 0;
00201 nux::BaseTexture* squircle_shine = 0;
00202 
00203 std::vector<nux::BaseTexture*> icon_background;
00204 std::vector<nux::BaseTexture*> icon_selected_background;
00205 std::vector<nux::BaseTexture*> icon_edge;
00206 std::vector<nux::BaseTexture*> icon_glow;
00207 std::vector<nux::BaseTexture*> icon_shadow;
00208 std::vector<nux::BaseTexture*> icon_shine;
00209 nux::ObjectPtr<nux::IOpenGLBaseTexture> offscreen_progress_texture;
00210 nux::ObjectPtr<nux::IOpenGLShaderProgram> shader_program_uv_persp_correction;
00211 nux::ObjectPtr<nux::IOpenGLAsmShaderProgram> asm_shader;
00212 std::map<char, nux::BaseTexture*> label_map;
00213 
00214 void generate_textures();
00215 void destroy_textures();
00216 }
00217 }
00218 
00219 IconRenderer::IconRenderer()
00220 {
00221   pip_style = OUTSIDE_TILE;
00222 
00223   if (!local::textures_created)
00224     local::generate_textures();
00225 }
00226 
00227 IconRenderer::~IconRenderer()
00228 {
00229 }
00230 
00231 void IconRenderer::SetTargetSize(int tile_size, int image_size_, int spacing_)
00232 {
00233   icon_size = tile_size;
00234   image_size = image_size_;
00235   spacing = spacing_;
00236 }
00237 
00238 void IconRenderer::PreprocessIcons(std::list<RenderArg>& args, nux::Geometry const& geo)
00239 {
00240   nux::Matrix4 ObjectMatrix;
00241   nux::Matrix4 ViewMatrix;
00242   nux::Matrix4 ProjectionMatrix;
00243   nux::Matrix4 ViewProjectionMatrix;
00244 
00245   _stored_projection_matrix = nux::GetWindowThread()->GetGraphicsEngine().GetOpenGLModelViewProjectionMatrix();
00246 
00247   GetInverseScreenPerspectiveMatrix(ViewMatrix, ProjectionMatrix, geo.width, geo.height, 0.1f, 1000.0f, DEGTORAD(90));
00248 
00249   nux::Matrix4 PremultMatrix = ProjectionMatrix * ViewMatrix;
00250 
00251   std::list<RenderArg>::iterator it;
00252   int i;
00253   for (it = args.begin(), i = 0; it != args.end(); it++, i++)
00254   {
00255 
00256     IconTextureSource* launcher_icon = it->icon;
00257 
00258     float w = icon_size;
00259     float h = icon_size;
00260     float x = it->render_center.x - w / 2.0f; // x: top left corner
00261     float y = it->render_center.y - h / 2.0f; // y: top left corner
00262     float z = it->render_center.z;
00263 
00264     if (it->skip)
00265     {
00266       w = 1;
00267       h = 1;
00268       x = -100;
00269       y = -100;
00270     }
00271 
00272     ObjectMatrix = nux::Matrix4::TRANSLATE(geo.width / 2.0f, geo.height / 2.0f, z) * // Translate the icon to the center of the viewport
00273                    nux::Matrix4::ROTATEX(it->x_rotation) *              // rotate the icon
00274                    nux::Matrix4::ROTATEY(it->y_rotation) *
00275                    nux::Matrix4::ROTATEZ(it->z_rotation) *
00276                    nux::Matrix4::TRANSLATE(-x - w / 2.0f, -y - h / 2.0f, -z); // Put the center the icon to (0, 0)
00277 
00278     ViewProjectionMatrix = PremultMatrix * ObjectMatrix;
00279 
00280     UpdateIconTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, ui::IconTextureSource::TRANSFORM_TILE);
00281 
00282     w = image_size;
00283     h = image_size;
00284     x = it->render_center.x - icon_size / 2.0f + (icon_size - image_size) / 2.0f;
00285     y = it->render_center.y - icon_size / 2.0f + (icon_size - image_size) / 2.0f;
00286     z = it->render_center.z;
00287 
00288     UpdateIconTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, ui::IconTextureSource::TRANSFORM_IMAGE);
00289 
00290     // hardcode values for now until SVG's are in place and we can remove this
00291     // 200 == size of large glow
00292     // 150 == size of large tile
00293     // 62 == size of small glow
00294     // 54 == size of small tile
00295     float icon_glow_size = 0.0f;
00296     if (icon_size > 100)
00297       icon_glow_size = icon_size * (200.0f / 150.0f);
00298     else
00299       icon_glow_size = icon_size * (62.0f / 54.0f);
00300     w = icon_glow_size;
00301     h = icon_glow_size;
00302     x = it->render_center.x - icon_glow_size / 2.0f;
00303     y = it->render_center.y - icon_glow_size / 2.0f;
00304     z = it->render_center.z;
00305 
00306     UpdateIconTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, ui::IconTextureSource::TRANSFORM_GLOW);
00307 
00308     w = geo.width + 2;
00309     h = icon_size + spacing;
00310     if (i == (int) args.size() - 1)
00311       h += 4;
00312     x = it->logical_center.x - w / 2.0f;
00313     y = it->logical_center.y - h / 2.0f;
00314     z = it->logical_center.z;
00315 
00316     UpdateIconTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, ui::IconTextureSource::TRANSFORM_HIT_AREA);
00317 
00318     if (launcher_icon->Emblem())
00319     {
00320       nux::BaseTexture* emblem = launcher_icon->Emblem();
00321 
00322       float w = icon_size;
00323       float h = icon_size;
00324 
00325       float emb_w = emblem->GetWidth();
00326       float emb_h = emblem->GetHeight();
00327 
00328       x = it->render_center.x + (icon_size * 0.50f - emb_w - icon_size * 0.05f); // puts right edge of emblem just over the edge of the launcher icon
00329       y = it->render_center.y - icon_size * 0.50f;     // y = top left corner position of emblem
00330       z = it->render_center.z;
00331 
00332       ObjectMatrix = nux::Matrix4::TRANSLATE(geo.width / 2.0f, geo.height / 2.0f, z) * // Translate the icon to the center of the viewport
00333                      nux::Matrix4::ROTATEX(it->x_rotation) *              // rotate the icon
00334                      nux::Matrix4::ROTATEY(it->y_rotation) *
00335                      nux::Matrix4::ROTATEZ(it->z_rotation) *
00336                      nux::Matrix4::TRANSLATE(-(it->render_center.x - w / 2.0f) - w / 2.0f, -(it->render_center.y - h / 2.0f) - h / 2.0f, -z); // Put the center the icon to (0, 0)
00337 
00338       ViewProjectionMatrix = PremultMatrix * ObjectMatrix;
00339 
00340       UpdateIconSectionTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, emb_w, emb_h, z,
00341                                  it->render_center.x - w / 2.0f, it->render_center.y - h / 2.0f, w, h, ui::IconTextureSource::TRANSFORM_EMBLEM);
00342     }
00343   }
00344 }
00345 
00346 void IconRenderer::UpdateIconTransform(ui::IconTextureSource* icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry const& geo,
00347                                        float x, float y, float w, float h, float z, ui::IconTextureSource::TransformIndex index)
00348 {
00349   UpdateIconSectionTransform (icon, ViewProjectionMatrix, geo, x, y, w, h, z, x, y, w, h, index);
00350 }
00351 
00352 void IconRenderer::UpdateIconSectionTransform(ui::IconTextureSource* icon, nux::Matrix4 ViewProjectionMatrix, nux::Geometry const& geo,
00353                                               float x, float y, float w, float h, float z, float xx, float yy, float ww, float hh, ui::IconTextureSource::TransformIndex index)
00354 {
00355   nux::Vector4 v0 = nux::Vector4(x,     y,     z, 1.0f);
00356   nux::Vector4 v1 = nux::Vector4(x,     y + h, z, 1.0f);
00357   nux::Vector4 v2 = nux::Vector4(x + w, y + h, z, 1.0f);
00358   nux::Vector4 v3 = nux::Vector4(x + w, y,     z, 1.0f);
00359 
00360   v0 = ViewProjectionMatrix * v0;
00361   v1 = ViewProjectionMatrix * v1;
00362   v2 = ViewProjectionMatrix * v2;
00363   v3 = ViewProjectionMatrix * v3;
00364 
00365   v0.divide_xyz_by_w();
00366   v1.divide_xyz_by_w();
00367   v2.divide_xyz_by_w();
00368   v3.divide_xyz_by_w();
00369 
00370   // normalize to the viewport coordinates and translate to the correct location
00371   v0.x =  geo.width  * (v0.x + 1.0f) / 2.0f - geo.width  / 2.0f + xx + ww / 2.0f;
00372   v0.y = -geo.height * (v0.y - 1.0f) / 2.0f - geo.height / 2.0f + yy + hh / 2.0f;
00373   v1.x =  geo.width  * (v1.x + 1.0f) / 2.0f - geo.width  / 2.0f + xx + ww / 2.0f;;
00374   v1.y = -geo.height * (v1.y - 1.0f) / 2.0f - geo.height / 2.0f + yy + hh / 2.0f;
00375   v2.x =  geo.width  * (v2.x + 1.0f) / 2.0f - geo.width  / 2.0f + xx + ww / 2.0f;
00376   v2.y = -geo.height * (v2.y - 1.0f) / 2.0f - geo.height / 2.0f + yy + hh / 2.0f;
00377   v3.x =  geo.width  * (v3.x + 1.0f) / 2.0f - geo.width  / 2.0f + xx + ww / 2.0f;
00378   v3.y = -geo.height * (v3.y - 1.0f) / 2.0f - geo.height / 2.0f + yy + hh / 2.0f;
00379 
00380 
00381   std::vector<nux::Vector4>& vectors = icon->GetTransform(index, monitor);
00382 
00383   vectors[0] = v0;
00384   vectors[1] = v1;
00385   vectors[2] = v2;
00386   vectors[3] = v3;
00387 }
00388 
00389 void IconRenderer::RenderIcon(nux::GraphicsEngine& GfxContext, RenderArg const& arg, nux::Geometry const& geo, nux::Geometry const& owner_geo)
00390 {
00391   // This check avoids a crash when the icon is not available on the system.
00392   if (arg.icon->TextureForSize(image_size) == 0 || arg.skip)
00393     return;
00394 
00395   local::IconSize size = icon_size > 100 ? local::IconSize::BIG : local::IconSize::SMALL;
00396 
00397   GfxContext.GetRenderStates().SetBlend(true);
00398   GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER);
00399   GfxContext.GetRenderStates().SetColorMask(true, true, true, true);
00400 
00401   nux::Color background_tile_color = arg.icon->BackgroundColor();
00402   nux::Color glow_color = arg.icon->GlowColor();
00403   nux::Color edge_color(0x55555555);
00404   nux::Color colorify = arg.colorify;
00405   nux::Color background_tile_colorify = arg.colorify;
00406   float backlight_intensity = arg.backlight_intensity;
00407   float glow_intensity = arg.glow_intensity;
00408   float shadow_intensity = 0.6f;
00409 
00410   nux::BaseTexture* background = local::icon_background[size];
00411   nux::BaseTexture* edge = local::icon_edge[size];
00412   nux::BaseTexture* glow = local::icon_glow[size];
00413   nux::BaseTexture* shine = local::icon_shine[size];
00414   nux::BaseTexture* shadow = local::icon_shadow[size];
00415 
00416   bool force_filter = icon_size != background->GetWidth();
00417 
00418   if (arg.keyboard_nav_hl)
00419   {
00420     background_tile_color = nux::color::White;
00421     glow_color = nux::color::White;
00422     edge_color = nux::color::White;
00423     colorify = nux::color::White;
00424     background_tile_colorify = nux::color::White;
00425     backlight_intensity = 0.95f;
00426     glow_intensity = 1.0f;
00427     shadow_intensity = 0.0f;
00428 
00429     background = local::icon_selected_background[size];
00430   }
00431   else
00432   {
00433     colorify.red +=   (0.5f + 0.5f * arg.saturation) * (1.0f - colorify.red);
00434     colorify.blue +=  (0.5f + 0.5f * arg.saturation) * (1.0f - colorify.blue);
00435     colorify.green += (0.5f + 0.5f * arg.saturation) * (1.0f - colorify.green);
00436 
00437     if (arg.colorify_background)
00438     {
00439       background_tile_colorify = background_tile_colorify * 0.7f;
00440     }
00441     else
00442     {
00443       background_tile_colorify.red +=   (0.5f + 0.5f * arg.saturation) * (1.0f - background_tile_colorify.red);
00444       background_tile_colorify.green += (0.5f + 0.5f * arg.saturation) * (1.0f - background_tile_colorify.green);
00445       background_tile_colorify.blue +=  (0.5f + 0.5f * arg.saturation) * (1.0f - background_tile_colorify.blue);
00446     }
00447   }
00448 
00449   if (arg.system_item)
00450   {
00451     // 0.9f is BACKLIGHT_STRENGTH in Launcher.cpp
00452     backlight_intensity = (arg.keyboard_nav_hl) ? 0.95f : 0.9f;
00453     glow_intensity = (arg.keyboard_nav_hl) ? 1.0f : 0.0f ;
00454 
00455     background = local::squircle_base_selected;
00456     edge = local::squircle_edge;
00457     glow = local::squircle_glow;
00458     shine = local::squircle_shine;
00459     shadow = local::squircle_shadow;
00460   }
00461 
00462   // draw shadow
00463   if (shadow_intensity > 0)
00464   {
00465     nux::Color shadow_color = background_tile_colorify * 0.3f;
00466 
00467     // FIXME it is using the same transformation of the glow,
00468     // should have its own transformation.
00469     RenderElement(GfxContext,
00470                   arg,
00471                   shadow->GetDeviceTexture(),
00472                   nux::color::White,
00473                   shadow_color,
00474                   shadow_intensity * arg.alpha,
00475                   force_filter,
00476                   arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_GLOW, monitor));
00477   }
00478 
00479   auto tile_transform = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor);
00480 
00481   // draw tile
00482   if (backlight_intensity > 0 && !arg.draw_edge_only)
00483   {
00484     RenderElement(GfxContext,
00485                   arg,
00486                   background->GetDeviceTexture(),
00487                   background_tile_color,
00488                   background_tile_colorify,
00489                   backlight_intensity * arg.alpha,
00490                   force_filter,
00491                   tile_transform);
00492   }
00493 
00494   edge_color = edge_color + ((background_tile_color - edge_color) * backlight_intensity);
00495   nux::Color edge_tile_colorify = background_tile_colorify;
00496 
00497   if (arg.colorify_background && !arg.keyboard_nav_hl)
00498   {
00499     // Mix edge_tile_colorify with plain white (1.0f).
00500     // Would be nicer to tweak value from HSV colorspace, instead.
00501     float mix_factor = (arg.system_item) ? 0.2f : 0.16f;
00502 
00503     edge_tile_colorify.red =   edge_tile_colorify.red   * (1.0f - mix_factor) + 1.0f * mix_factor;
00504     edge_tile_colorify.green = edge_tile_colorify.green * (1.0f - mix_factor) + 1.0f * mix_factor;
00505     edge_tile_colorify.blue =  edge_tile_colorify.blue  * (1.0f - mix_factor) + 1.0f * mix_factor;
00506   }
00507 
00508   RenderElement(GfxContext,
00509                 arg,
00510                 edge->GetDeviceTexture(),
00511                 edge_color,
00512                 edge_tile_colorify,
00513                 arg.alpha * arg.alpha, // Dim edges of semi-transparent tiles
00514                 force_filter,
00515                 tile_transform);
00516   // end tile draw
00517 
00518   // draw icon
00519   RenderElement(GfxContext,
00520                 arg,
00521                 arg.icon->TextureForSize(image_size)->GetDeviceTexture(),
00522                 nux::color::White,
00523                 colorify,
00524                 arg.alpha,
00525                 false,
00526                 arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_IMAGE, monitor));
00527 
00528   // draw overlay shine
00529   RenderElement(GfxContext,
00530                 arg,
00531                 shine->GetDeviceTexture(),
00532                 nux::color::White,
00533                 colorify,
00534                 arg.alpha,
00535                 force_filter,
00536                 tile_transform);
00537 
00538   // draw glow
00539   if (glow_intensity > 0)
00540   {
00541     RenderElement(GfxContext,
00542                   arg,
00543                   glow->GetDeviceTexture(),
00544                   glow_color,
00545                   nux::color::White,
00546                   glow_intensity * arg.alpha,
00547                   force_filter,
00548                   arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_GLOW, monitor));
00549   }
00550 
00551   // draw shimmer
00552   if (arg.shimmer_progress > 0 && arg.shimmer_progress < 1.0f)
00553   {
00554     int x1 = owner_geo.x + owner_geo.width;
00555     int x2 = owner_geo.x + owner_geo.width;
00556     float shimmer_constant = 1.9f;
00557 
00558     x1 -= geo.width * arg.shimmer_progress * shimmer_constant;
00559     GfxContext.PushClippingRectangle(nux::Geometry(x1, geo.y, x2 - x1, geo.height));
00560 
00561     float fade_out = 1.0f - CLAMP(((x2 - x1) - geo.width) / (geo.width * (shimmer_constant - 1.0f)), 0.0f, 1.0f);
00562 
00563     RenderElement(GfxContext,
00564                   arg,
00565                   local::icon_glow[size]->GetDeviceTexture(),
00566                   arg.icon->GlowColor(),
00567                   nux::color::White,
00568                   fade_out * arg.alpha,
00569                   force_filter,
00570                   arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_GLOW, monitor));
00571 
00572     GfxContext.PopClippingRectangle();
00573   }
00574 
00575   // draw progress bar
00576   if (arg.progress_bias > -1.0f && arg.progress_bias < 1.0f)
00577   {
00578     if (local::offscreen_progress_texture->GetWidth() != icon_size ||
00579         local::offscreen_progress_texture->GetHeight() != icon_size)
00580     {
00581       local::offscreen_progress_texture = nux::GetGraphicsDisplay()->GetGpuDevice()
00582         ->CreateSystemCapableDeviceTexture(icon_size, icon_size, 1, nux::BITFMT_R8G8B8A8);
00583     }
00584     RenderProgressToTexture(GfxContext, local::offscreen_progress_texture, arg.progress, arg.progress_bias);
00585 
00586     RenderElement(GfxContext,
00587                   arg,
00588                   local::offscreen_progress_texture,
00589                   nux::color::White,
00590                   nux::color::White,
00591                   arg.alpha,
00592                   force_filter,
00593                   tile_transform);
00594   }
00595 
00596   if (arg.icon->Emblem())
00597   {
00598     RenderElement(GfxContext,
00599                   arg,
00600                   arg.icon->Emblem()->GetDeviceTexture(),
00601                   nux::color::White,
00602                   nux::color::White,
00603                   arg.alpha,
00604                   force_filter,
00605                   arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_EMBLEM, monitor));
00606   }
00607 
00608   // draw indicators
00609   RenderIndicators(GfxContext,
00610                    arg,
00611                    arg.running_arrow ? arg.window_indicators : 0,
00612                    arg.active_arrow ? 1 : 0,
00613                    arg.alpha,
00614                    geo);
00615 
00616   // draw superkey-shortcut label
00617   if (arg.draw_shortcut && arg.shortcut_label)
00618   {
00619     char shortcut = (char) arg.shortcut_label;
00620 
00621     if (local::label_map.find(shortcut) == local::label_map.end())
00622       local::label_map[shortcut] = RenderCharToTexture(shortcut, icon_size, icon_size);
00623 
00624     RenderElement(GfxContext,
00625                   arg,
00626                   local::label_map[shortcut]->GetDeviceTexture(),
00627                   nux::Color(0xFFFFFFFF),
00628                   nux::color::White,
00629                   arg.alpha,
00630                   false,
00631                   tile_transform);
00632   }
00633 }
00634 
00635 nux::BaseTexture* IconRenderer::RenderCharToTexture(const char label, int width, int height)
00636 {
00637   nux::BaseTexture*     texture  = NULL;
00638   nux::CairoGraphics*   cg       = new nux::CairoGraphics(CAIRO_FORMAT_ARGB32,
00639                                                           width,
00640                                                           height);
00641   cairo_t*              cr       = cg->GetContext();
00642   PangoLayout*          layout   = NULL;
00643   PangoFontDescription* desc     = NULL;
00644   GtkSettings*          settings = gtk_settings_get_default();  // not ref'ed
00645   gchar*                fontName = NULL;
00646 
00647   double label_pos = double(icon_size / 3.0f);
00648   double text_size = double(icon_size / 4.0f);
00649   double label_x = label_pos;
00650   double label_y = label_pos;
00651   double label_w = label_pos;
00652   double label_h = label_pos;
00653   double label_r = 3.0f;
00654 
00655   cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
00656   cairo_paint(cr);
00657   cairo_scale(cr, 1.0f, 1.0f);
00658   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
00659   cg->DrawRoundedRectangle(cr, 1.0f, label_x, label_y, label_r, label_w, label_h);
00660   cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.65f);
00661   cairo_fill(cr);
00662 
00663   layout = pango_cairo_create_layout(cr);
00664   g_object_get(settings, "gtk-font-name", &fontName, NULL);
00665   desc = pango_font_description_from_string(fontName);
00666   pango_font_description_set_absolute_size(desc, text_size * PANGO_SCALE);
00667   pango_layout_set_font_description(layout, desc);
00668   pango_layout_set_text(layout, &label, 1);
00669 
00670   PangoRectangle logRect;
00671   PangoRectangle inkRect;
00672   pango_layout_get_extents(layout, &inkRect, &logRect);
00673 
00674   // position and paint text
00675   cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 1.0f);
00676   double x = label_x - ((logRect.width / PANGO_SCALE) - label_w) / 2.0f;
00677   double y = label_y - ((logRect.height / PANGO_SCALE) - label_h) / 2.0f - 1;
00678   cairo_move_to(cr, x, y);
00679   pango_cairo_show_layout(cr, layout);
00680 
00681   nux::NBitmapData* bitmap = cg->GetBitmap();
00682   texture = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture();
00683   texture->Update(bitmap);
00684   delete bitmap;
00685   delete cg;
00686   g_object_unref(layout);
00687   pango_font_description_free(desc);
00688   g_free(fontName);
00689 
00690   return texture;
00691 }
00692 
00693 void IconRenderer::RenderElement(nux::GraphicsEngine& GfxContext,
00694                                  RenderArg const& arg,
00695                                  nux::ObjectPtr<nux::IOpenGLBaseTexture> icon,
00696                                  nux::Color bkg_color,
00697                                  nux::Color colorify,
00698                                  float alpha,
00699                                  bool force_filter,
00700                                  std::vector<nux::Vector4>& xform_coords)
00701 {
00702   if (icon.IsNull())
00703     return;
00704 
00705   if (nux::Abs(arg.x_rotation) < 0.01f &&
00706       nux::Abs(arg.y_rotation) < 0.01f &&
00707       nux::Abs(arg.z_rotation) < 0.01f &&
00708       !force_filter)
00709     icon->SetFiltering(GL_NEAREST, GL_NEAREST);
00710   else
00711     icon->SetFiltering(GL_LINEAR, GL_LINEAR);
00712 
00713   nux::Vector4 const& v0 = xform_coords[0];
00714   nux::Vector4 const& v1 = xform_coords[1];
00715   nux::Vector4 const& v2 = xform_coords[2];
00716   nux::Vector4 const& v3 = xform_coords[3];
00717 
00718   float s0, t0, s1, t1, s2, t2, s3, t3;
00719 
00720   if (icon->GetResourceType() == nux::RTTEXTURERECTANGLE)
00721   {
00722     s0 = 0.0f;
00723     t0 = 0.0f;
00724     s1 = 0.0f;
00725     t1 = icon->GetHeight();
00726     s2 = icon->GetWidth();
00727     t2 = t1;
00728     s3 = s2;
00729     t3 = 0.0f;
00730   }
00731   else
00732   {
00733     s0 = 0.0f;
00734     t0 = 0.0f;
00735     s1 = 0.0f;
00736     t1 = 1.0f;
00737     s2 = 1.0f;
00738     t2 = 1.0f;
00739     s3 = 1.0f;
00740     t3 = 0.0f;
00741   }
00742 
00743   float VtxBuffer[] =
00744   {
00745     // Perspective correct
00746     v0.x, v0.y, 0.0f, 1.0f,     s0 / v0.w, t0 / v0.w, 0.0f, 1.0f / v0.w,
00747     v1.x, v1.y, 0.0f, 1.0f,     s1 / v1.w, t1 / v1.w, 0.0f, 1.0f / v1.w,
00748 #ifdef USE_MODERN_COMPIZ_GL
00749     v3.x, v3.y, 0.0f, 1.0f,     s3 / v3.w, t3 / v3.w, 0.0f, 1.0f / v3.w,
00750     v2.x, v2.y, 0.0f, 1.0f,     s2 / v2.w, t2 / v2.w, 0.0f, 1.0f / v2.w,
00751 #else
00752     v2.x, v2.y, 0.0f, 1.0f,     s2 / v2.w, t2 / v2.w, 0.0f, 1.0f / v2.w,
00753     v3.x, v3.y, 0.0f, 1.0f,     s3 / v3.w, t3 / v3.w, 0.0f, 1.0f / v3.w,
00754 #endif
00755   };
00756 
00757   CHECKGL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
00758   CHECKGL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
00759 
00760   int TextureObjectLocation;
00761   int VertexLocation;
00762   int TextureCoord0Location;
00763   int FragmentColor;
00764   int ColorifyColor;
00765   int DesatFactor;
00766 
00767   if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath())
00768   {
00769     local::shader_program_uv_persp_correction->Begin();
00770 
00771     TextureObjectLocation   = local::shader_program_uv_persp_correction->GetUniformLocationARB("TextureObject0");
00772     VertexLocation          = local::shader_program_uv_persp_correction->GetAttributeLocation("iVertex");
00773     TextureCoord0Location   = local::shader_program_uv_persp_correction->GetAttributeLocation("iTexCoord0");
00774     FragmentColor           = local::shader_program_uv_persp_correction->GetUniformLocationARB("color0");
00775     ColorifyColor           = local::shader_program_uv_persp_correction->GetUniformLocationARB("colorify_color");
00776     DesatFactor             = local::shader_program_uv_persp_correction->GetUniformLocationARB("desat_factor");
00777 
00778     if (TextureObjectLocation != -1)
00779       CHECKGL(glUniform1iARB(TextureObjectLocation, 0));
00780 
00781     int VPMatrixLocation = local::shader_program_uv_persp_correction->GetUniformLocationARB("ViewProjectionMatrix");
00782     if (VPMatrixLocation != -1)
00783     {
00784       local::shader_program_uv_persp_correction->SetUniformLocMatrix4fv((GLint)VPMatrixLocation, 1, false, (GLfloat*) & (_stored_projection_matrix.m));
00785     }
00786   }
00787 #ifndef USE_MODERN_COMPIZ_GL
00788   else
00789   {
00790     local::asm_shader->Begin();
00791 
00792     VertexLocation        = nux::VTXATTRIB_POSITION;
00793     TextureCoord0Location = nux::VTXATTRIB_TEXCOORD0;
00794 
00795     nux::GetWindowThread()->GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon);
00796 
00797     // Set the model-view matrix
00798     CHECKGL(glMatrixMode(GL_MODELVIEW));
00799     CHECKGL(glLoadMatrixf((float*) GfxContext.GetOpenGLModelViewMatrix().m));
00800 
00801     // Set the projection matrix
00802     CHECKGL(glMatrixMode(GL_PROJECTION));
00803     CHECKGL(glLoadMatrixf((float*) GfxContext.GetOpenGLProjectionMatrix().m));
00804   }
00805 #endif
00806 
00807   CHECKGL(glEnableVertexAttribArrayARB(VertexLocation));
00808   CHECKGL(glVertexAttribPointerARB((GLuint)VertexLocation, 4, GL_FLOAT, GL_FALSE, 32, VtxBuffer));
00809 
00810   if (TextureCoord0Location != -1)
00811   {
00812     CHECKGL(glEnableVertexAttribArrayARB(TextureCoord0Location));
00813     CHECKGL(glVertexAttribPointerARB((GLuint)TextureCoord0Location, 4, GL_FLOAT, GL_FALSE, 32, VtxBuffer + 4));
00814   }
00815 
00816   nux::Color bg_color = bkg_color * alpha;
00817 
00818   if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath())
00819   {
00820     CHECKGL(glUniform4fARB(FragmentColor, bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha));
00821     CHECKGL(glUniform4fARB(ColorifyColor, colorify.red, colorify.green, colorify.blue, colorify.alpha));
00822     CHECKGL(glUniform4fARB(DesatFactor, arg.saturation, arg.saturation, arg.saturation, arg.saturation));
00823 
00824     nux::GetWindowThread()->GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon);
00825 #ifdef USE_MODERN_COMPIZ_GL
00826     CHECKGL(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
00827 #else
00828     CHECKGL(glDrawArrays(GL_QUADS, 0, 4));
00829 #endif
00830   }
00831 #ifndef USE_MODERN_COMPIZ_GL
00832   else
00833   {
00834     CHECKGL(glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, bg_color.red, bg_color.green, bg_color.blue, bg_color.alpha));
00835     CHECKGL(glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, arg.saturation, arg.saturation, arg.saturation, arg.saturation));
00836     CHECKGL(glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, colorify.red, colorify.green, colorify.blue, colorify.alpha));
00837 
00838     nux::GetWindowThread()->GetGraphicsEngine().SetTexture(GL_TEXTURE0, icon);
00839     CHECKGL(glDrawArrays(GL_QUADS, 0, 4));
00840   }
00841 #endif
00842 
00843   if (VertexLocation != -1)
00844     CHECKGL(glDisableVertexAttribArrayARB(VertexLocation));
00845   if (TextureCoord0Location != -1)
00846     CHECKGL(glDisableVertexAttribArrayARB(TextureCoord0Location));
00847 //   if(VertexColorLocation != -1)
00848 //     CHECKGL( glDisableVertexAttribArrayARB(VertexColorLocation) );
00849 
00850   if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath())
00851   {
00852     local::shader_program_uv_persp_correction->End();
00853   }
00854   else
00855   {
00856     local::asm_shader->End();
00857   }
00858 }
00859 
00860 void IconRenderer::RenderIndicators(nux::GraphicsEngine& GfxContext,
00861                                     RenderArg const& arg,
00862                                     int running,
00863                                     int active,
00864                                     float alpha,
00865                                     nux::Geometry const& geo)
00866 {
00867   int markerCenter = (int) arg.render_center.y;
00868   markerCenter -= (int)(arg.x_rotation / (2 * M_PI) * icon_size);
00869 
00870 
00871   if (running > 0)
00872   {
00873     int scale = 1;
00874 
00875     int markerX;
00876     if (pip_style == OUTSIDE_TILE)
00877     {
00878       markerX = geo.x;
00879     }
00880     else
00881     {
00882       auto bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor);
00883       markerX = bounds[0].x + 2;
00884       scale = 2;
00885     }
00886 
00887     nux::TexCoordXForm texxform;
00888     nux::Color color = nux::color::LightGrey;
00889 
00890     if (arg.keyboard_nav_hl && pip_style == OVER_TILE)
00891       color = nux::color::Gray;
00892 
00893     if (arg.running_colored)
00894       color = nux::color::SkyBlue;
00895 
00896     color = color * alpha;
00897 
00898     nux::BaseTexture* texture;
00899 
00900     // markers are well outside screen bounds to start
00901     int markers [3] = {-100, -100, -100};
00902 
00903     if (!arg.running_on_viewport)
00904     {
00905       markers[0] = markerCenter;
00906       texture = local::arrow_empty_ltr;
00907     }
00908     else if (running == 1)
00909     {
00910       markers[0] = markerCenter;
00911       texture = local::arrow_ltr;
00912     }
00913     else if (running == 2)
00914     {
00915       markers[0] = markerCenter - 2 * scale;
00916       markers[1] = markerCenter + 2 * scale;
00917       texture = local::pip_ltr;
00918     }
00919     else
00920     {
00921       markers[0] = markerCenter - 4 * scale;
00922       markers[1] = markerCenter;
00923       markers[2] = markerCenter + 4 * scale;
00924       texture = local::pip_ltr;
00925     }
00926 
00927 
00928     for (int i = 0; i < 3; i++)
00929     {
00930       int center = markers[i];
00931       if (center == -100)
00932         break;
00933       
00934       GfxContext.QRP_1Tex(markerX,
00935                           center - ((texture->GetHeight() * scale) / 2) - 1,
00936                           (float) texture->GetWidth() * scale,
00937                           (float) texture->GetHeight() * scale,
00938                           texture->GetDeviceTexture(),
00939                           texxform,
00940                           color);
00941     }
00942   }
00943 
00944   if (active > 0)
00945   {
00946     nux::TexCoordXForm texxform;
00947 
00948     nux::Color color = nux::color::LightGrey * alpha;
00949     GfxContext.QRP_1Tex((geo.x + geo.width) - local::arrow_rtl->GetWidth(),
00950                         markerCenter - (local::arrow_rtl->GetHeight() / 2) - 1,
00951                         (float) local::arrow_rtl->GetWidth(),
00952                         (float) local::arrow_rtl->GetHeight(),
00953                         local::arrow_rtl->GetDeviceTexture(),
00954                         texxform,
00955                         color);
00956   }
00957 }
00958 
00959 void IconRenderer::RenderProgressToTexture(nux::GraphicsEngine& GfxContext,
00960                                            nux::ObjectPtr<nux::IOpenGLBaseTexture> texture,
00961                                            float progress_fill,
00962                                            float bias)
00963 {
00964   int width = texture->GetWidth();
00965   int height = texture->GetHeight();
00966 
00967   int progress_width =  icon_size;
00968   int progress_height = local::progress_bar_trough->GetHeight();
00969 
00970   int fill_width = image_size - (icon_size - image_size);
00971   int fill_height = local::progress_bar_fill->GetHeight();
00972 
00973   int fill_offset = (progress_width - fill_width) / 2;
00974 
00975   // We need to perform a barn doors effect to acheive the slide in and out
00976 
00977   int left_edge = width / 2 - progress_width / 2;
00978   int right_edge = width / 2 + progress_width / 2;
00979 
00980   if (bias < 0.0f)
00981   {
00982     // pulls the right edge in
00983     right_edge -= (int)(-bias * (float) progress_width);
00984   }
00985   else if (bias > 0.0f)
00986   {
00987     // pulls the left edge in
00988     left_edge += (int)(bias * progress_width);
00989   }
00990 
00991   int fill_y = (height - fill_height) / 2;
00992   int progress_y = fill_y + (fill_height - progress_height) / 2;
00993   int half_size = (right_edge - left_edge) / 2;
00994 
00995   SetOffscreenRenderTarget(texture);
00996 
00997   // FIXME
00998   glClear(GL_COLOR_BUFFER_BIT);
00999   nux::TexCoordXForm texxform;
01000 
01001   fill_width *= progress_fill;
01002 
01003   // left door
01004   GfxContext.PushClippingRectangle(nux::Geometry(left_edge, 0, half_size, height));
01005   GfxContext.QRP_1Tex(left_edge, progress_y, progress_width, progress_height,
01006                       local::progress_bar_trough->GetDeviceTexture(), texxform,
01007                       nux::color::White);
01008   GfxContext.QRP_1Tex(left_edge + fill_offset, fill_y, fill_width, fill_height,
01009                       local::progress_bar_fill->GetDeviceTexture(), texxform,
01010                       nux::color::White);
01011   GfxContext.PopClippingRectangle();
01012 
01013   // right door
01014   GfxContext.PushClippingRectangle(nux::Geometry(left_edge + half_size, 0, half_size, height));
01015   GfxContext.QRP_1Tex(right_edge - progress_width, progress_y,
01016                       progress_width, progress_height,
01017                       local::progress_bar_trough->GetDeviceTexture(), texxform,
01018                       nux::color::White);
01019   GfxContext.QRP_1Tex(right_edge - progress_width + fill_offset, fill_y,
01020                       fill_width, fill_height,
01021                       local::progress_bar_fill->GetDeviceTexture(), texxform,
01022                       nux::color::White);
01023 
01024   GfxContext.PopClippingRectangle();
01025 
01026   RestoreSystemRenderTarget();
01027 }
01028 
01029 void IconRenderer::DestroyTextures()
01030 {
01031   local::destroy_textures();
01032 }
01033 
01034 void IconRenderer::GetInverseScreenPerspectiveMatrix(nux::Matrix4& ViewMatrix, nux::Matrix4& PerspectiveMatrix,
01035                                                      int ViewportWidth,
01036                                                      int ViewportHeight,
01037                                                      float NearClipPlane,
01038                                                      float FarClipPlane,
01039                                                      float Fovy)
01040 {
01041   /*
01042     Objective:
01043     Given a perspective matrix defined by (Fovy, AspectRatio, NearPlane, FarPlane), we want to compute
01044     the ModelView matrix that transform a quad defined by its top-left coord (0, 0) and its
01045     bottom-right coord (WindowWidth, WindowHeight) into a full screen quad that covers the entire viewport (one to one).
01046     Any quad that is facing the camera and whose 4 points are on the 4 guiding line of the view frustum (pyramid)
01047     will always cover the entire viewport one to one (when projected on the screen).
01048     So all we have to do is to define a quad with x:[-x_cs, x_cs] and y:[-y_cs, y_cs] and find the z distance in eye space (z_cs) so that
01049     the quad touches the 4 guiding lines of the view frustum.
01050     We consider a well centered projection view (no skewing, no oblique clipping plane, ...) and derive the following equations:
01051        x_cs = AspectRatio*y_cs
01052        y_cs/z_cs = tanf(Fovy/2) ==> z_cs = y_cs*1/tanf(Fovy/2) (this is the absolute value the quad depth value will be -z_cs since we are using OpenGL right hand coord system).
01053 
01054     The quad (in camera space) facing the camera and centered around the camera view axis is defined by the points (-x_cs, y_cs) (top-left)
01055     and the point (x_cs, -y_cs) (bottom-right). If we move that quad along the camera view axis and place it at a distance z_cs of the camera,
01056     then its 4 corners are each on the 4 lines of the view frustum.
01057 
01058       (-x_cs, y_cs)          Camera Space
01059                    ^
01060          __________|__________
01061         |          |          |
01062         |          |          |
01063         |          |(0, 0)    |
01064         |----------|----------|->
01065         |          |          |
01066         |          |          |
01067         |__________|__________|
01068                            (x_cs, -y_cs)
01069 
01070     The full-screen quad (in screen space) is defined by the point (0, 0) (top-left) and (WindowWidth, WindowHeight) (bottom-right).
01071     We can choose and arbitrary value y_cs and compute the z_cs position in camera space that will produce a quad in camera space that projects into
01072     the full-screen space.
01073 
01074       (0, 0)            Screen Space
01075          _____________________->
01076         |          |          |
01077         |          |          |
01078         |          |          |
01079         |----------|----------|
01080         |          |          |
01081         |          |          |
01082         |__________|__________|
01083         v                   (WindowWidth, WindowHeight)
01084 
01085     The model view matrix is the succession of transformation that convert the quad (0, 0, WindowWidth, WindowHeight) into
01086     the quad (-x_cs, y_cs, x_cs, -y_cs)
01087 
01088     Screen Space           Camera Space
01089          x        ---->    x_ = x*2*x_cs/WindowWidth - x_cs
01090          y        ---->    y_ = -y*2*y_cs/WindowHeight + y_cs
01091          z        ---->    z_ = A*z -y_cs*1/tanf(Fovy/2)
01092        where A is a coefficient that can attenuate the rate of change in depth when the quad moves along the camera axis
01093 
01094     If the following is the projection matrix:
01095 
01096     (a, 0,  0, 0)     a = 1/(AspectRatio*tan(Fovy/2))
01097     (0, b,  0, 0)     b = 1/tan(Fovy/2)
01098     (0, 0,  c, d)
01099     (0, 0, -1, 0)
01100 
01101     and the camera space vertex is (x_cs, y_cs, z_cs, w_cs) projects to the top left corner of the view port on the screen ((-1, 1) in clip space), then
01102       x_cs*a/(-z_cs) = -1; |        z_cs = x_cs*a           x_cs*a = -y_cs*b  ==> x_cs = y_cs*AspectRatio
01103                            |  ==>                     ==>
01104       y_cs*b/(-z_cs) = +1; |        z_cs = -y_cs*b          z_cs = -y_cs*1/tanf(Fovy/2)
01105   */
01106 
01107 
01108   float AspectRatio = (float)ViewportWidth / (float)ViewportHeight;
01109   float CameraToScreenDistance = -1.0f;
01110   float y_cs = -CameraToScreenDistance * tanf(0.5f * Fovy/* *M_PI/180.0f*/);
01111   float x_cs = y_cs * AspectRatio;
01112 
01113   ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) *
01114                nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * 3 * y_cs / ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/);
01115 
01116   PerspectiveMatrix.Perspective(Fovy, AspectRatio, NearClipPlane, FarClipPlane);
01117 }
01118 
01119 void
01120 IconRenderer::SetOffscreenRenderTarget(nux::ObjectPtr<nux::IOpenGLBaseTexture> texture)
01121 {
01122   int width = texture->GetWidth();
01123   int height = texture->GetHeight();
01124 
01125   nux::GetGraphicsDisplay()->GetGpuDevice()->FormatFrameBufferObject(width, height, nux::BITFMT_R8G8B8A8);
01126   nux::GetGraphicsDisplay()->GetGpuDevice()->SetColorRenderTargetSurface(0, texture->GetSurfaceLevel(0));
01127   nux::GetGraphicsDisplay()->GetGpuDevice()->ActivateFrameBuffer();
01128 
01129   nux::GetGraphicsDisplay()->GetGraphicsEngine()->SetContext(0, 0, width, height);
01130   nux::GetGraphicsDisplay()->GetGraphicsEngine()->SetViewport(0, 0, width, height);
01131   nux::GetGraphicsDisplay()->GetGraphicsEngine()->Push2DWindow(width, height);
01132   nux::GetGraphicsDisplay()->GetGraphicsEngine()->EmptyClippingRegion();
01133 }
01134 
01135 void
01136 IconRenderer::RestoreSystemRenderTarget()
01137 {
01138   nux::GetWindowCompositor().RestoreRenderingSurface();
01139 }
01140 
01141 
01142 // The local namespace is purely for namespacing the file local variables below.
01143 namespace local
01144 {
01145 namespace
01146 {
01147 void setup_shaders()
01148 {
01149   if (nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath())
01150   {
01151     shader_program_uv_persp_correction = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateShaderProgram();
01152     shader_program_uv_persp_correction->LoadIShader(gPerspectiveCorrectShader.GetTCharPtr());
01153     shader_program_uv_persp_correction->Link();
01154   }
01155   else
01156   {
01157     asm_shader = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateAsmShaderProgram();
01158     asm_shader->LoadVertexShader(TCHAR_TO_ANSI(*PerspectiveCorrectVtx));
01159 
01160     if ((nux::GetGraphicsDisplay()->GetGpuDevice()->SUPPORT_GL_ARB_TEXTURE_NON_POWER_OF_TWO() == false) &&
01161         (nux::GetGraphicsDisplay()->GetGpuDevice()->SUPPORT_GL_EXT_TEXTURE_RECTANGLE() ||
01162          nux::GetGraphicsDisplay()->GetGpuDevice()->SUPPORT_GL_ARB_TEXTURE_RECTANGLE()))
01163     {
01164       // No support for non power of two textures but support for rectangle textures
01165       asm_shader->LoadPixelShader(TCHAR_TO_ANSI(*PerspectiveCorrectTexRectFrg));
01166     }
01167     else
01168     {
01169       asm_shader->LoadPixelShader(TCHAR_TO_ANSI(*PerspectiveCorrectTexFrg));
01170     }
01171 
01172     asm_shader->Link();
01173   }
01174 }
01175 
01176 
01177 inline nux::BaseTexture* load_texture(const char* filename)
01178 {
01179   return nux::CreateTexture2DFromFile(filename, -1, true);
01180 }
01181 
01182 void generate_textures(std::vector<nux::BaseTexture*>& icons, const char* big_file, const char* small_file)
01183 {
01184   icons.resize(IconSize::LAST);
01185   icons[IconSize::BIG] = load_texture(big_file);
01186   icons[IconSize::SMALL] = load_texture(small_file);
01187 }
01188 
01189 void generate_textures()
01190 {
01191   progress_bar_trough = load_texture(PKGDATADIR"/progress_bar_trough.png");
01192   progress_bar_fill = load_texture(PKGDATADIR"/progress_bar_fill.png");
01193 
01194   generate_textures(icon_background,
01195                     PKGDATADIR"/launcher_icon_back_150.png",
01196                     PKGDATADIR"/launcher_icon_back_54.png");
01197   generate_textures(icon_selected_background,
01198                     PKGDATADIR"/launcher_icon_selected_back_150.png",
01199                     PKGDATADIR"/launcher_icon_back_54.png");
01200   generate_textures(icon_edge,
01201                     PKGDATADIR"/launcher_icon_edge_150.png",
01202                     PKGDATADIR"/launcher_icon_edge_54.png");
01203   generate_textures(icon_glow,
01204                     PKGDATADIR"/launcher_icon_glow_200.png",
01205                     PKGDATADIR"/launcher_icon_glow_62.png");
01206   generate_textures(icon_shadow,
01207                     PKGDATADIR"/launcher_icon_shadow_200.png",
01208                     PKGDATADIR"/launcher_icon_shadow_62.png");
01209   generate_textures(icon_shine,
01210                     PKGDATADIR"/launcher_icon_shine_150.png",
01211                     PKGDATADIR"/launcher_icon_shine_54.png");
01212 
01213   squircle_base = load_texture(PKGDATADIR"/squircle_base_54.png");
01214   squircle_base_selected = load_texture(PKGDATADIR"/squircle_base_selected_54.png");
01215   squircle_edge = load_texture(PKGDATADIR"/squircle_edge_54.png");
01216   squircle_glow = load_texture(PKGDATADIR"/squircle_glow_62.png");
01217   squircle_shadow = load_texture(PKGDATADIR"/squircle_shadow_62.png");
01218   squircle_shine = load_texture(PKGDATADIR"/squircle_shine_54.png");
01219 
01220   pip_ltr = load_texture(PKGDATADIR"/launcher_pip_ltr.png");
01221   arrow_ltr = load_texture(PKGDATADIR"/launcher_arrow_ltr.png");
01222   arrow_empty_ltr = load_texture(PKGDATADIR"/launcher_arrow_outline_ltr.png");
01223 
01224   pip_rtl = load_texture(PKGDATADIR"/launcher_pip_rtl.png");
01225   arrow_rtl = load_texture(PKGDATADIR"/launcher_arrow_rtl.png");
01226   arrow_empty_rtl = load_texture(PKGDATADIR"/launcher_arrow_outline_rtl.png");
01227 
01228   offscreen_progress_texture = nux::GetGraphicsDisplay()->GetGpuDevice()
01229     ->CreateSystemCapableDeviceTexture(2, 2, 1, nux::BITFMT_R8G8B8A8);
01230 
01231   setup_shaders();
01232   textures_created = true;
01233 }
01234 
01235 void destroy_textures(std::vector<nux::BaseTexture*>& icons)
01236 {
01237   icons[SMALL]->UnReference();
01238   icons[BIG]->UnReference();
01239   icons.clear();
01240 }
01241 
01242 void destroy_textures()
01243 {
01244   if (!textures_created)
01245     return;
01246 
01247   progress_bar_trough->UnReference();
01248   progress_bar_fill->UnReference();
01249   pip_ltr->UnReference();
01250   pip_rtl->UnReference();
01251   arrow_ltr->UnReference();
01252   arrow_rtl->UnReference();
01253   arrow_empty_ltr->UnReference();
01254   arrow_empty_rtl->UnReference();
01255 
01256   destroy_textures(icon_background);
01257   destroy_textures(icon_selected_background);
01258   destroy_textures(icon_edge);
01259   destroy_textures(icon_glow);
01260   destroy_textures(icon_shadow);
01261   destroy_textures(icon_shine);
01262 
01263   squircle_base->UnReference();
01264   squircle_base_selected->UnReference();
01265   squircle_edge->UnReference();
01266   squircle_glow->UnReference();
01267   squircle_shadow->UnReference();
01268   squircle_shine->UnReference();
01269 
01270   for (auto it = label_map.begin(), end = label_map.end(); it != end; ++it)
01271     it->second->UnReference();
01272   label_map.clear();
01273 
01274   textures_created = false;
01275 }
01276 
01277 } // anon namespace
01278 } // namespace local
01279 
01280 } // namespace ui
01281 } // namespace unity