# Visualization Library

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

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

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

Visualization Library v2011.05.1142 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 26 2011 22:51:25.
Permission is granted to use this page to write and publish articles regarding Visualization Library.