# Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics

[Home] [Tutorials] [All Classes] [Grouped Classes]

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

# D:/VL/BuildSystem/VL_DISTRO/Visualization_Library_SDK/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 v2011.09.1162 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu Jan 26 2012 00:43:44.
Permission is granted to use this page to write and publish articles regarding Visualization Library.