Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlGraphics/Text.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include <vlGraphics/Text.hpp>
00033 #include <vlGraphics/OpenGLContext.hpp>
00034 #include <vlGraphics/Actor.hpp>
00035 #include <vlCore/Log.hpp>
00036 
00037 #include <ft2build.h>
00038 #include FT_FREETYPE_H
00039 
00040 using namespace vl;
00041 
00042 //-----------------------------------------------------------------------------
00043 void Text::render_Implementation(const Actor* actor, const Shader*, const Camera* camera, OpenGLContext* gl_context) const
00044 {
00045   gl_context->bindVAS(NULL, false, false);
00046 
00047   VL_CHECK(font())
00048 
00049   if (!font() || !font()->mFT_Face)
00050     return;
00051 
00052   if ( text().empty() )
00053     return;
00054 
00055   // Lighting can be enabled or disabled.
00056   // glDisable(GL_LIGHTING);
00057 
00058   // Blending must be enabled explicity by the vl::Shader, also to perform z-sort.
00059   // glEnable(GL_BLEND);
00060 
00061   // Trucchetto che usiamo per evitare z-fighting:
00062   // Pass #1 - fill color and stencil
00063   // - disable depth write mask
00064   // - depth test can be enabled or not by the user
00065   // - depth func can be choosen by the user
00066   // - render in the order: background, border, shadow, outline, text
00067   // Pass #2 - fill z-buffer
00068   // - enable depth write mask
00069   // - disable color mask
00070   // - disable stencil
00071   // - drawing background and border
00072 
00073   // Pass #1
00074 
00075   // disable z-writing
00076   GLboolean depth_mask=0;
00077   glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask);
00078   glDepthMask(GL_FALSE);
00079 
00080   // background
00081   if (backgroundEnabled())
00082     renderBackground( actor, camera );
00083 
00084   // border
00085   if (borderEnabled())
00086     renderBorder( actor, camera );
00087 
00088   // to have the most correct results we should render the text twice one for color and stencil, the other for the z-buffer
00089 
00090   // shadow render
00091   if (shadowEnabled())
00092     renderText( actor, camera, shadowColor(), shadowVector() );
00093   // outline render
00094   if (outlineEnabled())
00095   {
00096     renderText( actor, camera, outlineColor(), fvec2(-1,0) );
00097     renderText( actor, camera, outlineColor(), fvec2(+1,0) );
00098     renderText( actor, camera, outlineColor(), fvec2(0,-1) );
00099     renderText( actor, camera, outlineColor(), fvec2(0,+1) );
00100   }
00101   // text render
00102   renderText( actor, camera, color(), fvec2(0,0) );
00103 
00104   // Pass #2
00105   // fills the z-buffer (not the stencil buffer): approximated to the text bbox
00106 
00107   // restores depth mask
00108   glDepthMask(depth_mask);
00109 
00110   if (depth_mask)
00111   {
00112     // disables writing to the color buffer
00113     GLboolean color_mask[4];
00114     glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
00115     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00116 
00117     // disable writing to the stencil buffer
00118     int stencil_front_mask=0;
00119     glGetIntegerv(GL_STENCIL_WRITEMASK, &stencil_front_mask);
00120     int stencil_back_mask=0;
00121     if (Has_GL_Version_2_0)
00122       glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &stencil_back_mask);
00123     glStencilMask(0);
00124 
00125     // background
00126     renderBackground( actor, camera );
00127 
00128     // border
00129     renderBorder( actor, camera );
00130 
00131     // restores color writing
00132     glColorMask(color_mask[0],color_mask[1],color_mask[2],color_mask[3]);
00133 
00134     // restore the stencil masks
00135     glStencilMask(stencil_front_mask);
00136     if (Has_GL_Version_2_0)
00137       glStencilMaskSeparate(GL_BACK, stencil_back_mask);
00138   }
00139   
00140   // restore the right color and normal since we changed them
00141   glColor4fv( gl_context->color().ptr() );
00142   glNormal3fv( gl_context->normal().ptr() );
00143 }
00144 //-----------------------------------------------------------------------------
00145 void Text::renderText(const Actor* actor, const Camera* camera, const fvec4& color, const fvec2& offset) const
00146 {
00147   if(!mFont)
00148   {
00149     Log::error("Text::renderText() error: no Font assigned to the Text object.\n");
00150     VL_TRAP()
00151     return;
00152   }
00153 
00154   if (!font()->mFT_Face)
00155   {
00156     Log::error("Text::renderText() error: invalid FT_Face: probably you tried to load an unsupported font format.\n");
00157     VL_TRAP()
00158     return;
00159   }
00160 
00161   int viewport[] = { camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height() };
00162 
00163   if (viewport[2] < 1) viewport[2] = 1;
00164   if (viewport[3] < 1) viewport[3] = 1;
00165 
00166   // note that we only save and restore the server side states
00167 
00168   if (mode() == Text2D)
00169   {
00170     glMatrixMode(GL_MODELVIEW);
00171     glPushMatrix();
00172     glLoadIdentity();
00173     VL_CHECK_OGL();
00174 
00175     glMatrixMode(GL_PROJECTION);
00176     glPushMatrix();
00177     // glLoadIdentity();
00178     // gluOrtho2D( -0.5f, viewport[2]-0.5f, -0.5f, viewport[3]-0.5f );
00179 
00180     // clever trick part #1
00181     fmat4 mat = fmat4::getOrtho(-0.5f, viewport[2]-0.5f, -0.5f, viewport[3]-0.5f, -1, +1);
00182     mat.e(2,2) = 1.0f; // preserve the z value from the incoming vertex.
00183     mat.e(2,3) = 0.0f;
00184     glLoadMatrixf(mat.ptr());
00185 
00186     VL_CHECK_OGL();
00187   }
00188 
00189   AABB rbbox = rawboundingRect( text() ); // for text alignment
00190   VL_CHECK(rbbox.maxCorner().z() == 0)
00191   VL_CHECK(rbbox.minCorner().z() == 0)
00192   AABB bbox = rbbox;
00193   int applied_margin = backgroundEnabled() || borderEnabled() ? margin() : 0;
00194   bbox.setMaxCorner( bbox.maxCorner() + vec3(2.0f*applied_margin,2.0f*applied_margin,0) );
00195   VL_CHECK(bbox.maxCorner().z() == 0)
00196   VL_CHECK(bbox.minCorner().z() == 0)
00197 
00198   // basic render states
00199 
00200   fvec2 pen(0,0);
00201 
00202   float texc[] = { 0,0, 0,0, 0,0, 0,0 };
00203   VL_glActiveTexture( GL_TEXTURE0 );
00204   glEnable(GL_TEXTURE_2D);
00205   VL_glClientActiveTexture( GL_TEXTURE0 );
00206   glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00207   glTexCoordPointer(2, GL_FLOAT, 0, texc);
00208 
00209   // Constant color
00210   glColor4f( color.r(), color.g(), color.b(), color.a() );
00211 
00212   // Constant normal
00213   glNormal3f( 0, 0, 1 );
00214 
00215   fvec3 vect[4];
00216   glEnableClientState( GL_VERTEX_ARRAY );
00217   glVertexPointer(3, GL_FLOAT, 0, vect[0].ptr());
00218 
00219   FT_Long has_kerning = FT_HAS_KERNING( font()->mFT_Face );
00220   FT_UInt previous = 0;
00221 
00222   // viewport alignment
00223   fmat4 m = mMatrix;
00224 
00225   int w = camera->viewport()->width();
00226   int h = camera->viewport()->height();
00227 
00228   if (w < 1) w = 1;
00229   if (h < 1) h = 1;
00230 
00231   if ( !(actor && actor->transform()) && mode() == Text2D )
00232   {
00233     if (viewportAlignment() & AlignHCenter)
00234     {
00235       VL_CHECK( !(viewportAlignment() & AlignRight) )
00236       VL_CHECK( !(viewportAlignment() & AlignLeft) )
00237       // vect[i].x() += int((viewport[2]-1.0f) / 2.0f);
00238       m.translate( (float)int((w-1.0f) / 2.0f), 0, 0);
00239     }
00240 
00241     if (viewportAlignment() & AlignRight)
00242     {
00243       VL_CHECK( !(viewportAlignment() & AlignHCenter) )
00244       VL_CHECK( !(viewportAlignment() & AlignLeft) )
00245       // vect[i].x() += int(viewport[2]-1.0f);
00246       m.translate( (float)int(w-1.0f), 0, 0);
00247     }
00248 
00249     if (viewportAlignment() & AlignTop)
00250     {
00251       VL_CHECK( !(viewportAlignment() & AlignBottom) )
00252       VL_CHECK( !(viewportAlignment() & AlignVCenter) )
00253       // vect[i].y() += int(viewport[3]-1.0f);
00254       m.translate( 0, (float)int(h-1.0f), 0);
00255     }
00256 
00257     if (viewportAlignment() & AlignVCenter)
00258     {
00259       VL_CHECK( !(viewportAlignment() & AlignTop) )
00260       VL_CHECK( !(viewportAlignment() & AlignBottom) )
00261       // vect[i].y() += int((viewport[3]-1.0f) / 2.0f);
00262       m.translate( 0, (float)int((h-1.0f) / 2.0f), 0);
00263     }
00264   }
00265 
00266   // split the text in different lines
00267 
00268   VL_CHECK(text().length())
00269 
00270   std::vector< String > lines;
00271   lines.push_back( String() );
00272   for(int i=0; i<text().length(); ++i)
00273   {
00274     if (text()[i] == '\n')
00275     {
00276       // start new line
00277       lines.push_back( String() );
00278     }
00279     else
00280       lines.back() += text()[i];
00281   }
00282 
00283   for(unsigned iline=0; iline<lines.size(); iline++)
00284   {
00285     // strip spaces at the beginning and at the end of the line
00286     if (textAlignment() == TextAlignJustify)
00287       lines[iline].trim();
00288 
00289     AABB linebox = rawboundingRect( lines[iline] );
00290     int displace = 0;
00291     int just_space = 0;
00292     int just_remained_space = 0;
00293     int space_count = 0;
00294     for(int c=0; c<(int)lines[iline].length(); c++)
00295       if ( lines[iline][c] == ' ' )
00296         space_count++;
00297 
00298     if (space_count && textAlignment() == TextAlignJustify)
00299     {
00300       just_space          = int(rbbox.width() - linebox.width()) / space_count;
00301       just_remained_space = int(rbbox.width() - linebox.width()) % space_count;
00302     }
00303 
00304     if (layout() == RightToLeftText)
00305     {
00306       if (textAlignment() == TextAlignRight)
00307         displace = 0;
00308       else
00309       if (textAlignment() == TextAlignLeft)
00310         displace = - int(rbbox.width() - linebox.width());
00311       else
00312       if (textAlignment() == TextAlignCenter)
00313         displace = - int((rbbox.width() - linebox.width()) / 2.0f);
00314     }
00315     if (layout() == LeftToRightText)
00316     {
00317       if (textAlignment() == TextAlignRight)
00318         displace = int(rbbox.width() - linebox.width());
00319       else
00320       if (textAlignment() == TextAlignLeft)
00321         displace = 0;
00322       else
00323       if (textAlignment() == TextAlignCenter)
00324         displace = + int((rbbox.width() - linebox.width()) / 2.0f);
00325     }
00326 
00327     // this is needed so that empty strings generate empty lines
00328     // note that puttig '\n\n\n\n' at the beginning of a text generates
00329     // a wrong rendering (see it with background box activated).
00330     if (iline != 0 && !lines[iline].length())
00331     {
00332       pen.y() -= mFont->mHeight;
00333       pen.x()  = 0;
00334     }
00335     else
00336     for(int c=0; c<(int)lines[iline].length(); c++)
00337     {
00338       if (c == 0 && iline != 0)
00339       {
00340         pen.y() -= mFont->mHeight;
00341         pen.x()  = 0;
00342       }
00343 
00344       const Glyph* glyph = mFont->glyph( lines[iline][c] );
00345 
00346       if (!glyph)
00347         continue;
00348 
00349       if ( kerningEnabled() && has_kerning && previous && glyph->glyphIndex() )
00350       {
00351         FT_Vector delta; delta.y = 0;
00352         if (layout() == LeftToRightText)
00353         {
00354           FT_Get_Kerning( font()->mFT_Face, previous, glyph->glyphIndex(), FT_KERNING_DEFAULT, &delta );
00355           pen.x() += delta.x / 64.0f;
00356         }
00357         else
00358         if (layout() == RightToLeftText)
00359         {
00360           FT_Get_Kerning( font()->mFT_Face, glyph->glyphIndex(), previous, FT_KERNING_DEFAULT, &delta );
00361           pen.x() -= delta.x / 64.0f;
00362         }
00363         pen.y() += delta.y / 64.0f;
00364       }
00365       previous = glyph->glyphIndex();
00366 
00367       if (glyph->textureHandle())
00368       {
00369         glBindTexture( GL_TEXTURE_2D, glyph->textureHandle() );
00370 
00371         texc[0] = glyph->s0();
00372         texc[1] = glyph->t1();
00373         
00374         texc[2] = glyph->s1();
00375         texc[3] = glyph->t1();
00376 
00377         texc[4] = glyph->s1();
00378         texc[5] = glyph->t0();
00379         
00380         texc[6] = glyph->s0();
00381         texc[7] = glyph->t0();
00382 
00383         int left = layout() == RightToLeftText ? -glyph->left() : +glyph->left();
00384 
00385         // triangle strip layout
00386 
00387         vect[0].x() = pen.x() + glyph->width()*0 + left -1;
00388         vect[0].y() = pen.y() + glyph->height()*0 + glyph->top() - glyph->height() -1;
00389 
00390         vect[1].x() = pen.x() + glyph->width()*1 + left +1;
00391         vect[1].y() = pen.y() + glyph->height()*0 + glyph->top() - glyph->height() -1;
00392 
00393         vect[2].x() = pen.x() + glyph->width()*1 + left +1;
00394         vect[2].y() = pen.y() + glyph->height()*1 + glyph->top() - glyph->height() +1;
00395 
00396         vect[3].x() = pen.x() + glyph->width()*0 + left -1;
00397         vect[3].y() = pen.y() + glyph->height()*1 + glyph->top() - glyph->height() +1;
00398 
00399         if (layout() == RightToLeftText)
00400         {
00401   #if (1)
00402           vect[0].x() -= glyph->width()-1 +2;
00403           vect[1].x() -= glyph->width()-1 +2;
00404           vect[2].x() -= glyph->width()-1 +2;
00405           vect[3].x() -= glyph->width()-1 +2;
00406   #endif
00407         }
00408 
00409         vect[0].y() -= mFont->mHeight;
00410         vect[1].y() -= mFont->mHeight;
00411         vect[2].y() -= mFont->mHeight;
00412         vect[3].y() -= mFont->mHeight;
00413 
00414   #if (1)
00415         // normalize coordinate orgin to the bottom/left corner
00416         vect[0] -= (fvec3)bbox.minCorner();
00417         vect[1] -= (fvec3)bbox.minCorner();
00418         vect[2] -= (fvec3)bbox.minCorner();
00419         vect[3] -= (fvec3)bbox.minCorner();
00420   #endif
00421 
00422   #if (1)
00423         vect[0].x() += applied_margin + displace;
00424         vect[1].x() += applied_margin + displace;
00425         vect[2].x() += applied_margin + displace;
00426         vect[3].x() += applied_margin + displace;
00427 
00428         vect[0].y() += applied_margin;
00429         vect[1].y() += applied_margin;
00430         vect[2].y() += applied_margin;
00431         vect[3].y() += applied_margin;
00432   #endif
00433 
00434         // apply offset for outline rendering
00435         vect[0].x() += offset.x();
00436         vect[0].y() += offset.y();
00437         vect[1].x() += offset.x();
00438         vect[1].y() += offset.y();
00439         vect[2].x() += offset.x();
00440         vect[2].y() += offset.y();
00441         vect[3].x() += offset.x();
00442         vect[3].y() += offset.y();
00443 
00444         // alignment
00445         for(int i=0; i<4; ++i)
00446         {
00447           if (alignment() & AlignHCenter)
00448           {
00449             VL_CHECK( !(alignment() & AlignRight) )
00450             VL_CHECK( !(alignment() & AlignLeft) )
00451             vect[i].x() -= (int)(bbox.width() / 2.0f);
00452           }
00453 
00454           if (alignment() & AlignRight)
00455           {
00456             VL_CHECK( !(alignment() & AlignHCenter) )
00457             VL_CHECK( !(alignment() & AlignLeft) )
00458             vect[i].x() -= (int)bbox.width();
00459           }
00460 
00461           if (alignment() & AlignTop)
00462           {
00463             VL_CHECK( !(alignment() & AlignBottom) )
00464             VL_CHECK( !(alignment() & AlignVCenter) )
00465             vect[i].y() -= (int)bbox.height();
00466           }
00467 
00468           if (alignment() & AlignVCenter)
00469           {
00470             VL_CHECK( !(alignment() & AlignTop) )
00471             VL_CHECK( !(alignment() & AlignBottom) )
00472             vect[i].y() -= int(bbox.height() / 2.0);
00473           }
00474         }
00475 
00476         // apply text transform
00477         vect[0] = m * vect[0];
00478         vect[1] = m * vect[1];
00479         vect[2] = m * vect[2];
00480         vect[3] = m * vect[3];
00481 
00482         // actor's transform following in Text2D
00483         if ( actor->transform() && mode() == Text2D )
00484         {
00485           vec4 v(0,0,0,1);
00486           v = actor->transform()->worldMatrix() * v;
00487 
00488           camera->project(v,v);
00489 
00490           // from screen space to viewport space
00491           v.x() -= viewport[0];
00492           v.y() -= viewport[1];
00493 
00494           v.x() = (float)int(v.x());
00495           v.y() = (float)int(v.y());
00496 
00497           vect[0].x() += (float)v.x();
00498           vect[0].y() += (float)v.y();
00499           vect[1].x() += (float)v.x();
00500           vect[1].y() += (float)v.y();
00501           vect[2].x() += (float)v.x();
00502           vect[2].y() += (float)v.y();
00503           vect[3].x() += (float)v.x();
00504           vect[3].y() += (float)v.y();
00505 
00506           // clever trick part #2
00507           vect[0].z() = 
00508           vect[1].z() = 
00509           vect[2].z() = 
00510           vect[3].z() = float((v.z() - 0.5f) / 0.5f);
00511         }
00512 
00513         glDrawArrays(GL_TRIANGLE_FAN, 0, 4); VL_CHECK_OGL();
00514 
00515         #if (0)
00516           glDisable(GL_TEXTURE_2D);
00517           glColor3fv(vec3(1,0,0).ptr());
00518           glDrawArrays(GL_LINE_LOOP, 0, 4);
00519           glColor4fv(color.ptr());
00520           glEnable(GL_TEXTURE_2D);
00521         #endif
00522       }
00523 
00524       if (just_space && lines[iline][c] == ' ' && iline != lines.size()-1)
00525       {
00526         if (layout() == LeftToRightText)
00527         {
00528           pen.x() += just_space + (just_remained_space?1:0);
00529           // pen.y() += glyph->advance().y();
00530         }
00531         else
00532         if (layout() == RightToLeftText)
00533         {
00534           pen.x() -= just_space + (just_remained_space?1:0);
00535           // pen.y() -= glyph->advance().y();
00536         }
00537         if(just_remained_space)
00538           just_remained_space--;
00539       }
00540 
00541       if (layout() == LeftToRightText)
00542       {
00543         pen.x() += glyph->advance().x();
00544         // pen.y() += glyph->advance().y();
00545       }
00546       else
00547       if (layout() == RightToLeftText)
00548       {
00549         pen.x() -= glyph->advance().x();
00550         // pen.y() -= glyph->advance().y();
00551       }
00552 
00553     }
00554   }
00555 
00556   glDisableClientState( GL_VERTEX_ARRAY ); VL_CHECK_OGL();
00557   glDisableClientState( GL_TEXTURE_COORD_ARRAY ); VL_CHECK_OGL();
00558 
00559   VL_CHECK_OGL();
00560 
00561   if (mode() == Text2D)
00562   {
00563     glMatrixMode(GL_MODELVIEW);
00564     glPopMatrix(); VL_CHECK_OGL()
00565 
00566     glMatrixMode(GL_PROJECTION);
00567     glPopMatrix(); VL_CHECK_OGL()
00568   }
00569 
00570   glDisable(GL_TEXTURE_2D);
00571   glBindTexture(GL_TEXTURE_2D,0);
00572 }
00573 //-----------------------------------------------------------------------------
00574 // returns the raw bounding box of the string, i.e. without alignment, margin and matrix transform.
00575 AABB Text::rawboundingRect(const String& text) const
00576 {
00577   AABB aabb;
00578 
00579   if(!font())
00580   {
00581     Log::error("Text::rawboundingRect() error: no Font assigned to the Text object.\n");
00582     VL_TRAP()
00583     return aabb;
00584   }
00585 
00586   if (!font()->mFT_Face)
00587   {
00588     Log::error("Text::rawboundingRect() error: invalid FT_Face: probably you tried to load an unsupported font format.\n");
00589     VL_TRAP()
00590     return aabb;
00591   }
00592 
00593   fvec2 pen(0,0);
00594   fvec3 vect[4];
00595 
00596   FT_Long has_kerning = FT_HAS_KERNING( font()->mFT_Face );
00597   FT_UInt previous = 0;
00598 
00599   for(int c=0; c<(int)text.length(); c++)
00600   {
00601     if (text[c] == '\n')
00602     {
00603       pen.y() -= mFont->mHeight ? mFont->mHeight : mFont->mSize;
00604       pen.x()  = 0;
00605       continue;
00606     }
00607 
00608     const ref<Glyph>& glyph = mFont->glyph(text[c]);
00609 
00610     // if glyph == NULL there was an error during its creation...
00611     if (glyph.get() == NULL)
00612       continue;
00613 
00614     if ( kerningEnabled() && has_kerning && previous && glyph->glyphIndex())
00615     {
00616       FT_Vector delta; delta.y = 0;
00617       if (layout() == LeftToRightText)
00618       {
00619         FT_Get_Kerning( font()->mFT_Face, previous, glyph->glyphIndex(), FT_KERNING_DEFAULT, &delta );
00620         pen.x() += delta.x / 64.0f;
00621       }
00622       else
00623       if (layout() == RightToLeftText)
00624       {
00625         FT_Get_Kerning( font()->mFT_Face, glyph->glyphIndex(), previous, FT_KERNING_DEFAULT, &delta );
00626         pen.x() -= delta.x / 64.0f;
00627       }
00628       pen.y() += delta.y / 64.0f;
00629     }
00630     previous = glyph->glyphIndex();
00631 
00632     if ( glyph->textureHandle() )
00633     {
00634       int left = layout() == RightToLeftText ? -glyph->left() : +glyph->left();
00635 
00636       vect[0].x() = pen.x() + glyph->width()*0 + left -1;
00637       vect[0].y() = pen.y() + glyph->height()*0 + glyph->top() - glyph->height() -1;
00638 
00639       vect[1].x() = pen.x() + glyph->width()*1 + left +1;
00640       vect[1].y() = pen.y() + glyph->height()*0 + glyph->top() - glyph->height() -1;
00641 
00642       vect[2].x() = pen.x() + glyph->width()*1 + left +1;
00643       vect[2].y() = pen.y() + glyph->height()*1 + glyph->top() - glyph->height() +1;
00644 
00645       vect[3].x() = pen.x() + glyph->width()*0 + left -1;
00646       vect[3].y() = pen.y() + glyph->height()*1 + glyph->top() - glyph->height() +1;
00647 
00648       if (layout() == RightToLeftText)
00649       {
00650 #if (1)
00651         vect[0].x() -= glyph->width()-1 +2;
00652         vect[1].x() -= glyph->width()-1 +2;
00653         vect[2].x() -= glyph->width()-1 +2;
00654         vect[3].x() -= glyph->width()-1 +2;
00655 #endif
00656       }
00657 
00658       vect[0].y() -= mFont->mHeight;
00659       vect[1].y() -= mFont->mHeight;
00660       vect[2].y() -= mFont->mHeight;
00661       vect[3].y() -= mFont->mHeight;
00662 
00663 #if(0)
00664       // apply margin
00665       //if (layout() == LeftToRightText)
00666       //{
00667         vect[0].x() += margin();
00668         vect[1].x() += margin();
00669         vect[2].x() += margin();
00670         vect[3].x() += margin();
00671       //}
00672       //else
00673       //if (layout() == RightToLeftText)
00674       //{
00675       //  vect[0].x() -= margin();
00676       //  vect[1].x() -= margin();
00677       //  vect[2].x() -= margin();
00678       //  vect[3].x() -= margin();
00679       //}
00680 
00681       vect[0].y() += margin();
00682       vect[1].y() += margin();
00683       vect[2].y() += margin();
00684       vect[3].y() += margin();
00685 #endif
00686 
00687     }
00688 
00689     aabb.addPoint( (vec3)vect[0] );
00690     aabb.addPoint( (vec3)vect[1] );
00691     aabb.addPoint( (vec3)vect[2] );
00692     aabb.addPoint( (vec3)vect[3] );
00693 
00694     if (layout() == LeftToRightText)
00695       pen += glyph->advance();
00696     else
00697     if (layout() == RightToLeftText)
00698       pen -= glyph->advance();
00699   }
00700 
00701   return aabb;
00702 }
00703 //-----------------------------------------------------------------------------
00704 void Text::renderBackground(const Actor* actor, const Camera* camera) const
00705 {
00706   int viewport[] = { camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height() };
00707 
00708   if (viewport[2] < 1) viewport[2] = 1;
00709   if (viewport[3] < 1) viewport[3] = 1;
00710 
00711   if (mode() == Text2D)
00712   {
00713     glMatrixMode(GL_MODELVIEW);
00714     glPushMatrix();
00715     glLoadIdentity();
00716     VL_CHECK_OGL();
00717 
00718     glMatrixMode(GL_PROJECTION);
00719     glPushMatrix();
00720     //glLoadIdentity();
00721     //gluOrtho2D( -0.5f, viewport[2]-0.5f, -0.5f, viewport[3]-0.5f );
00722 
00723     // clever trick part #1
00724     fmat4 mat = fmat4::getOrtho(-0.5f, viewport[2]-0.5f, -0.5f, viewport[3]-0.5f, -1, +1);
00725     mat.e(2,2) = 1.0f;
00726     mat.e(2,3) = 0.0f;
00727     glLoadMatrixf(mat.ptr());
00728     VL_CHECK_OGL();
00729   }
00730 
00731   // Constant color
00732   glColor4f(mBackgroundColor.r(),mBackgroundColor.g(), mBackgroundColor.b(), mBackgroundColor.a());
00733 
00734   // Constant normal
00735   glNormal3f(0, 0, 1);
00736 
00737   vec3 a,b,c,d;
00738   boundingRectTransformed( a, b, c, d, camera, mode() == Text2D ? actor : NULL );
00739   fvec3 vect[] = { (fvec3)a, (fvec3)b, (fvec3)c, (fvec3)d };
00740   glEnableClientState( GL_VERTEX_ARRAY );
00741   glVertexPointer(3, GL_FLOAT, 0, vect);
00742 
00743   glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
00744 
00745   glDisableClientState( GL_VERTEX_ARRAY );
00746 
00747   if (mode() == Text2D)
00748   {
00749     glMatrixMode(GL_MODELVIEW);
00750     glPopMatrix(); VL_CHECK_OGL()
00751 
00752     glMatrixMode(GL_PROJECTION);
00753     glPopMatrix(); VL_CHECK_OGL()
00754   }
00755 }
00756 //-----------------------------------------------------------------------------
00757 void Text::renderBorder(const Actor* actor, const Camera* camera) const
00758 {
00759   int viewport[] = { camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height() };
00760 
00761   if (viewport[2] < 1) viewport[2] = 1;
00762   if (viewport[3] < 1) viewport[3] = 1;
00763 
00764   if (mode() == Text2D)
00765   {
00766     glMatrixMode(GL_MODELVIEW);
00767     glPushMatrix();
00768     glLoadIdentity();
00769     VL_CHECK_OGL();
00770 
00771     glMatrixMode(GL_PROJECTION);
00772     glPushMatrix();
00773     //glLoadIdentity();
00774     //gluOrtho2D( -0.5f, viewport[2]-0.5f, -0.5f, viewport[3]-0.5f );
00775 
00776     // clever trick part #1
00777     fmat4 mat = fmat4::getOrtho(-0.5f, viewport[2]-0.5f, -0.5f, viewport[3]-0.5f, -1, +1);
00778     mat.e(2,2) = 1.0f;
00779     mat.e(2,3) = 0.0f;
00780     glLoadMatrixf(mat.ptr());
00781     VL_CHECK_OGL();
00782   }
00783 
00784   // Constant color
00785   glColor4f(mBorderColor.r(), mBorderColor.g(), mBorderColor.b(), mBorderColor.a());
00786 
00787   // Constant normal
00788   glNormal3f( 0, 0, 1 );
00789 
00790   vec3 a,b,c,d;
00791   boundingRectTransformed( a, b, c, d, camera, mode() == Text2D ? actor : NULL );
00792   fvec3 vect[] = { (fvec3)a, (fvec3)b, (fvec3)c, (fvec3)d };
00793   glEnableClientState( GL_VERTEX_ARRAY );
00794   glVertexPointer(3, GL_FLOAT, 0, vect);
00795 
00796   glDrawArrays(GL_LINE_LOOP, 0, 4);
00797 
00798   glDisableClientState( GL_VERTEX_ARRAY );
00799 
00800   if (mode() == Text2D)
00801   {
00802     glMatrixMode(GL_MODELVIEW);
00803     glPopMatrix(); VL_CHECK_OGL()
00804 
00805     glMatrixMode(GL_PROJECTION);
00806     glPopMatrix(); VL_CHECK_OGL()
00807   }
00808 }
00809 //-----------------------------------------------------------------------------
00812 AABB Text::boundingRect() const
00813 {
00814   return boundingRect(text());
00815 }
00816 //-----------------------------------------------------------------------------
00817 AABB Text::boundingRect(const String& text) const
00818 {
00819   int applied_margin = backgroundEnabled() || borderEnabled() ? margin() : 0;
00820   AABB bbox = rawboundingRect( text );
00821   bbox.setMaxCorner( bbox.maxCorner() + vec3(2.0f*applied_margin,2.0f*applied_margin,0) );
00822 
00823   // normalize coordinate orgin to the bottom/left corner
00824   vec3 min = bbox.minCorner() - bbox.minCorner();
00825   vec3 max = bbox.maxCorner() - bbox.minCorner();
00826 
00827   // normalize coordinate orgin to the bottom/left corner
00828 
00829   // alignment
00830 
00831   if (alignment() & AlignHCenter)
00832   {
00833     VL_CHECK( !(alignment() & AlignRight) )
00834     VL_CHECK( !(alignment() & AlignLeft) )
00835     min.x() -= int(bbox.width() / 2.0);
00836     max.x() -= int(bbox.width() / 2.0);
00837   }
00838 
00839   if (alignment() & AlignRight)
00840   {
00841     VL_CHECK( !(alignment() & AlignHCenter) )
00842     VL_CHECK( !(alignment() & AlignLeft) )
00843     min.x() -= (int)bbox.width();
00844     max.x() -= (int)bbox.width();
00845   }
00846 
00847   if (alignment() & AlignTop)
00848   {
00849     VL_CHECK( !(alignment() & AlignBottom) )
00850     VL_CHECK( !(alignment() & AlignVCenter) )
00851     min.y() -= (int)bbox.height();
00852     max.y() -= (int)bbox.height();
00853   }
00854 
00855   if (alignment() & AlignVCenter)
00856   {
00857     VL_CHECK( !(alignment() & AlignTop) )
00858     VL_CHECK( !(alignment() & AlignBottom) )
00859     min.y() -= int(bbox.height() / 2.0);
00860     max.y() -= int(bbox.height() / 2.0);
00861   }
00862 
00863   // no matrix transform applied
00864   // ...
00865 
00866   // no actor's transform applied
00867   // ...
00868 
00869   AABB aabb;
00870   aabb.setMinCorner(min);
00871   aabb.setMaxCorner(max);
00872   return aabb;
00873 }
00874 //-----------------------------------------------------------------------------
00888 AABB Text::boundingRectTransformed(const Camera* camera, const Actor* actor) const
00889 {
00890   vec3 a, b, c, d;
00891   return boundingRectTransformed(a, b, c, d, camera, actor);
00892 }
00893 //-----------------------------------------------------------------------------
00894 AABB Text::boundingRectTransformed(vec3& a, vec3& b, vec3& c, vec3& d, const Camera* camera, const Actor* actor) const
00895 {
00896   AABB bbox = boundingRect();
00897 
00898   a = bbox.minCorner();
00899   b.x() = (float)bbox.maxCorner().x();
00900   b.y() = (float)bbox.minCorner().y();
00901   c = bbox.maxCorner();
00902   d.x() = (float)bbox.minCorner().x();
00903   d.y() = (float)bbox.maxCorner().y();
00904   // set z to 0
00905   a.z() = b.z() = c.z() = d.z() = 0;
00906 
00907   // viewport alignment
00908   fmat4 m = mMatrix;
00909 
00910   int w = camera->viewport()->width();
00911   int h = camera->viewport()->height();
00912 
00913   if (w < 1) w = 1;
00914   if (h < 1) h = 1;
00915 
00916   if ( !(actor && actor->transform()) && mode() == Text2D )
00917   {
00918     if (viewportAlignment() & AlignHCenter)
00919     {
00920       VL_CHECK( !(viewportAlignment() & AlignRight) )
00921       VL_CHECK( !(viewportAlignment() & AlignLeft) )
00922       // vect[i].x() += int((viewport[2]-1.0f) / 2.0f);
00923       m.translate( (float)int((w-1.0f) / 2.0f), 0, 0);
00924     }
00925 
00926     if (viewportAlignment() & AlignRight)
00927     {
00928       VL_CHECK( !(viewportAlignment() & AlignHCenter) )
00929       VL_CHECK( !(viewportAlignment() & AlignLeft) )
00930       // vect[i].x() += int(viewport[2]-1.0f);
00931       m.translate( (float)int(w-1.0f), 0, 0);
00932     }
00933 
00934     if (viewportAlignment() & AlignTop)
00935     {
00936       VL_CHECK( !(viewportAlignment() & AlignBottom) )
00937       VL_CHECK( !(viewportAlignment() & AlignVCenter) )
00938       // vect[i].y() += int(viewport[3]-1.0f);
00939       m.translate( 0, (float)int(h-1.0f), 0);
00940     }
00941 
00942     if (viewportAlignment() & AlignVCenter)
00943     {
00944       VL_CHECK( !(viewportAlignment() & AlignTop) )
00945       VL_CHECK( !(viewportAlignment() & AlignBottom) )
00946       // vect[i].y() += int((viewport[3]-1.0f) / 2.0f);
00947       m.translate( 0, (float)int((h-1.0f) / 2.0f), 0);
00948     }
00949   }
00950 
00951   // ??? mix fixme: remove all these castings!
00952   // apply matrix transform
00953   a = (mat4)m * a;
00954   b = (mat4)m * b;
00955   c = (mat4)m * c;
00956   d = (mat4)m * d;
00957 
00958   // apply actor's transform
00959   if ( actor && actor->transform() )
00960   {
00961     if ( mode() == Text3D )
00962     {
00963       a = actor->transform()->worldMatrix() * a;
00964       b = actor->transform()->worldMatrix() * b;
00965       c = actor->transform()->worldMatrix() * c;
00966       d = actor->transform()->worldMatrix() * d;
00967     }
00968     else
00969     if ( mode() == Text2D )
00970     {
00971       // transform v
00972       vec4 v(0,0,0,1);
00973       v = actor->transform()->worldMatrix() * v;
00974 
00975       // project to screen
00976       camera->project(v,v);
00977 
00978       // from screen space to viewport space
00979       int viewport[] = { camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height() };
00980       v.x() -= viewport[0];
00981       v.y() -= viewport[1];
00982 
00983       v.x() = (float)int(v.x());
00984       v.y() = (float)int(v.y());
00985 
00986       a += v.xyz();
00987       b += v.xyz();
00988       c += v.xyz();
00989       d += v.xyz();
00990 
00991       // clever trick part #2
00992       a.z() = 
00993       b.z() = 
00994       c.z() = 
00995       d.z() = (v.z() - 0.5f) / 0.5f;
00996     }
00997   }
00998 
00999   bbox.setNull();
01000   bbox.addPoint(a);
01001   bbox.addPoint(b);
01002   bbox.addPoint(c);
01003   bbox.addPoint(d);
01004   return bbox;
01005 }
01006 //-----------------------------------------------------------------------------
01007 void Text::translate(float x, float y, float z)
01008 {
01009   mMatrix.translate(x,y,z);
01010 }
01011 //-----------------------------------------------------------------------------
01012 void Text::rotate(float degrees, float x, float y, float z)
01013 {
01014   mMatrix.rotate(degrees,x,y,z);
01015 }
01016 //-----------------------------------------------------------------------------
01017 void Text::resetMatrix()
01018 {
01019   mMatrix.setIdentity();
01020 }
01021 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:42.
Permission is granted to use this page to write and publish articles regarding Visualization Library.