Visualization Library

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

X:/dropbox/visualizationlibrary/src/vlGraphics/CoreText.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/CoreText.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 // mic fixme: implement me.
00043 
00044 // Goals:
00045 // - Run on OpenGL Core/ES.
00046 // - Achieve a much greater rendering speed.
00047 // - In order to do this we might sacrifice some of the usability of vl::Text
00048 
00049 // Guidelines:
00050 // - Viewport alignment, text transformation, transform tracking done externally.
00051 // - Does not manipulate the GL_PROJECTION and GL_MODELVIEW matrices.
00052 // - Text geometry and bounding boxes should be pre-computed on text change.
00053 // - Line splitting should not be done at rendering time.
00054 // - Should use only OpenGL Core routines.
00055 // - Should use texture atlases and perform lazy texture binding.
00056 // - Cleaner left to right / right to left text reversing.
00057 // - Outline rendering should use 2 pass with enlarged glyphs instead of 5 passes or precompute an high quality outline texture.
00058 // - Avoid using doubles and floats if possible, use integer and Rect rather floats and AABBs.
00059 
00060 //-----------------------------------------------------------------------------
00061 void CoreText::render_Implementation(const Actor* actor, const Shader*, const Camera* camera, OpenGLContext* gl_context) const
00062 {
00063   gl_context->bindVAS(NULL, false, false);
00064 
00065   VL_CHECK(font())
00066 
00067   if (!font() || !font()->mFT_Face)
00068     return;
00069 
00070   if ( text().empty() )
00071     return;
00072 
00073   // Lighting can be enabled or disabled.
00074   // glDisable(GL_LIGHTING);
00075 
00076   // Blending must be enabled explicity by the vl::Shader, also to perform z-sort.
00077   // glEnable(GL_BLEND);
00078 
00079   // Trucchetto che usiamo per evitare z-fighting:
00080   // Pass #1 - fill color and stencil
00081   // - disable depth write mask
00082   // - depth test can be enabled or not by the user
00083   // - depth func can be choosen by the user
00084   // - render in the order: background, border, shadow, outline, text
00085   // Pass #2 - fill z-buffer
00086   // - enable depth write mask
00087   // - disable color mask
00088   // - disable stencil
00089   // - drawing background and border
00090 
00091   // Pass #1
00092 
00093   // disable z-writing
00094   GLboolean depth_mask=0;
00095   glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask);
00096   glDepthMask(GL_FALSE);
00097 
00098   // background
00099   if (backgroundEnabled())
00100     renderBackground( actor, camera );
00101 
00102   // border
00103   if (borderEnabled())
00104     renderBorder( actor, camera );
00105 
00106   // to have the most correct results we should render the text twice one for color and stencil, the other for the z-buffer
00107 
00108   // shadow render
00109   if (shadowEnabled())
00110     renderText( actor, camera, shadowColor(), shadowVector() );
00111   // outline render
00112   if (outlineEnabled())
00113   {
00114     renderText( actor, camera, outlineColor(), fvec2(-1,0) );
00115     renderText( actor, camera, outlineColor(), fvec2(+1,0) );
00116     renderText( actor, camera, outlineColor(), fvec2(0,-1) );
00117     renderText( actor, camera, outlineColor(), fvec2(0,+1) );
00118   }
00119   // text render
00120   renderText( actor, camera, color(), fvec2(0,0) );
00121 
00122   // Pass #2
00123   // fills the z-buffer (not the stencil buffer): approximated to the text bbox
00124 
00125   // restores depth mask
00126   glDepthMask(depth_mask);
00127 
00128   if (depth_mask)
00129   {
00130     // disables writing to the color buffer
00131     GLboolean color_mask[4];
00132     glGetBooleanv(GL_COLOR_WRITEMASK, color_mask);
00133     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00134 
00135     // disable writing to the stencil buffer
00136     int stencil_front_mask=0;
00137     glGetIntegerv(GL_STENCIL_WRITEMASK, &stencil_front_mask);
00138     int stencil_back_mask=0;
00139     if (Has_GL_Version_2_0)
00140       glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &stencil_back_mask);
00141     glStencilMask(0);
00142 
00143     // background
00144     renderBackground( actor, camera );
00145 
00146     // border
00147     renderBorder( actor, camera );
00148 
00149     // restores color writing
00150     glColorMask(color_mask[0],color_mask[1],color_mask[2],color_mask[3]);
00151 
00152     // restore the stencil masks
00153     glStencilMask(stencil_front_mask);
00154     if (Has_GL_Version_2_0)
00155       glStencilMaskSeparate(GL_BACK, stencil_back_mask);
00156   }
00157 }
00158 //-----------------------------------------------------------------------------
00159 void CoreText::renderText(const Actor*, const Camera*, const fvec4& color, const fvec2& offset) const
00160 {
00161   if(!mFont)
00162   {
00163     Log::error("CoreText::renderText() error: no Font assigned to the CoreText object.\n");
00164     VL_TRAP()
00165     return;
00166   }
00167 
00168   if (!font()->mFT_Face)
00169   {
00170     Log::error("CoreText::renderText() error: invalid FT_Face: probably you tried to load an unsupported font format.\n");
00171     VL_TRAP()
00172     return;
00173   }
00174 
00175   // mic fixme: these should be pre-computed when the text is set!!!
00176 
00177   AABB rbbox = rawboundingRect( text() ); // for text alignment
00178   VL_CHECK(rbbox.maxCorner().z() == 0)
00179   VL_CHECK(rbbox.minCorner().z() == 0)
00180   AABB bbox = rbbox;
00181   bbox.setMaxCorner( bbox.maxCorner() + vec3(2.0f*margin(), 2.0f*margin(), 0) );
00182   VL_CHECK(bbox.maxCorner().z() == 0)
00183   VL_CHECK(bbox.minCorner().z() == 0)
00184 
00185   // basic render states
00186 
00187   // mic fixme: detect GLSLProgram and use VertexAttribPointer if present.
00188 
00189   float texc[] = { 0,0,0,0,0,0,0,0 };
00190   VL_glActiveTexture( GL_TEXTURE0 );
00191   VL_glClientActiveTexture( GL_TEXTURE0 );
00192   glEnable(GL_TEXTURE_2D);
00193   glEnableClientState( GL_TEXTURE_COORD_ARRAY );
00194   glTexCoordPointer(2, GL_FLOAT, 0, texc);
00195 
00196   // color
00197   glColor4fv(color.ptr());
00198 
00199   // Constant normal
00200   glNormal3fv( fvec3(0,0,1).ptr() );
00201 
00202   fvec3 vect[4];
00203   glEnableClientState( GL_VERTEX_ARRAY );
00204   glVertexPointer(3, GL_FLOAT, 0, vect[0].ptr());
00205 
00206   FT_Long use_kerning = FT_HAS_KERNING( font()->mFT_Face );
00207   FT_UInt previous = 0;
00208 
00209   fvec2 pen(0,0);
00210 
00211   // mic fixme:
00212   // - lines split and lines dimensions (linebox) should be precomputed on text set!
00213   // - or convert this function to generate a pre-computed rendering-list!
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 horz_text_align = 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         horz_text_align = 0;
00257       else
00258       if (textAlignment() == TextAlignLeft)
00259         horz_text_align = - int(rbbox.width() - linebox.width());
00260       else
00261       if (textAlignment() == TextAlignCenter)
00262         horz_text_align = - int((rbbox.width() - linebox.width()) / 2.0f);
00263     }
00264     if (layout() == LeftToRightText)
00265     {
00266       if (textAlignment() == TextAlignRight)
00267         horz_text_align = int(rbbox.width() - linebox.width());
00268       else
00269       if (textAlignment() == TextAlignLeft)
00270         horz_text_align = 0;
00271       else
00272       if (textAlignment() == TextAlignCenter)
00273         horz_text_align = + 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 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           vect[0].x() -= glyph->width()-1 +2;
00346           vect[1].x() -= glyph->width()-1 +2;
00347           vect[2].x() -= glyph->width()-1 +2;
00348           vect[3].x() -= glyph->width()-1 +2;
00349         }
00350 
00351         vect[0].y() -= mFont->mHeight;
00352         vect[1].y() -= mFont->mHeight;
00353         vect[2].y() -= mFont->mHeight;
00354         vect[3].y() -= mFont->mHeight;
00355 
00356         // normalize coordinate orgin to the bottom/left corner
00357         vect[0] -= (fvec3)bbox.minCorner();
00358         vect[1] -= (fvec3)bbox.minCorner();
00359         vect[2] -= (fvec3)bbox.minCorner();
00360         vect[3] -= (fvec3)bbox.minCorner();
00361 
00362         // margin & horz_text_align
00363         vect[0].x() += margin() + horz_text_align;
00364         vect[0].y() += margin();
00365         vect[1].x() += margin() + horz_text_align;
00366         vect[1].y() += margin();
00367         vect[2].x() += margin() + horz_text_align;
00368         vect[2].y() += margin();
00369         vect[3].x() += margin() + horz_text_align;
00370         vect[3].y() += margin();
00371 
00372         // apply offset for outline rendering
00373         vect[0].x() += offset.x();
00374         vect[0].y() += offset.y();
00375         vect[1].x() += offset.x();
00376         vect[1].y() += offset.y();
00377         vect[2].x() += offset.x();
00378         vect[2].y() += offset.y();
00379         vect[3].x() += offset.x();
00380         vect[3].y() += offset.y();
00381 
00382         // text pivot
00383         for(int i=0; i<4; ++i)
00384         {
00385           if (textOrigin() & AlignHCenter)
00386           {
00387             VL_CHECK( !(textOrigin() & AlignRight) )
00388             VL_CHECK( !(textOrigin() & AlignLeft) )
00389             vect[i].x() -= (int)(bbox.width() / 2.0f);
00390           }
00391 
00392           if (textOrigin() & AlignRight)
00393           {
00394             VL_CHECK( !(textOrigin() & AlignHCenter) )
00395             VL_CHECK( !(textOrigin() & AlignLeft) )
00396             vect[i].x() -= (int)bbox.width();
00397           }
00398 
00399           if (textOrigin() & AlignTop)
00400           {
00401             VL_CHECK( !(textOrigin() & AlignBottom) )
00402             VL_CHECK( !(textOrigin() & AlignVCenter) )
00403             vect[i].y() -= (int)bbox.height();
00404           }
00405 
00406           if (textOrigin() & AlignVCenter)
00407           {
00408             VL_CHECK( !(textOrigin() & AlignTop) )
00409             VL_CHECK( !(textOrigin() & AlignBottom) )
00410             vect[i].y() -= int(bbox.height() / 2.0);
00411           }
00412         }
00413 
00414         glDrawArrays(GL_QUADS, 0, 4);
00415 
00416         #if (0)
00417           glDisable(GL_TEXTURE_2D);
00418           glColor3fv(vec3(1,0,0).ptr());
00419           glDrawArrays(GL_LINE_LOOP, 0, 4);
00420           glColor4fv(color.ptr());
00421           glEnable(GL_TEXTURE_2D);
00422         #endif
00423       }
00424 
00425       if (just_space && lines[iline][c] == ' ' && iline != lines.size()-1)
00426       {
00427         if (layout() == LeftToRightText)
00428         {
00429           pen.x() += just_space + (just_remained_space?1:0);
00430           // pen.y() += glyph->advance().y();
00431         }
00432         else
00433         if (layout() == RightToLeftText)
00434         {
00435           pen.x() -= just_space + (just_remained_space?1:0);
00436           // pen.y() -= glyph->advance().y();
00437         }
00438         if(just_remained_space)
00439           just_remained_space--;
00440       }
00441 
00442       if (layout() == LeftToRightText)
00443       {
00444         pen.x() += glyph->advance().x();
00445         // pen.y() += glyph->advance().y();
00446       }
00447       else
00448       if (layout() == RightToLeftText)
00449       {
00450         pen.x() -= glyph->advance().x();
00451         // pen.y() -= glyph->advance().y();
00452       }
00453 
00454     }
00455   }
00456 
00457   glDisableClientState( GL_VERTEX_ARRAY );
00458   glDisableClientState( GL_TEXTURE_COORD_ARRAY );
00459 
00460   VL_CHECK_OGL();
00461 
00462   glDisable(GL_TEXTURE_2D);
00463   glBindTexture(GL_TEXTURE_2D, 0);
00464 }
00465 //-----------------------------------------------------------------------------
00466 // returns the raw bounding box of the string, i.e. without alignment, margin and matrix transform.
00467 AABB CoreText::rawboundingRect(const String& text) const
00468 {
00469   AABB aabb;
00470 
00471   if(!font())
00472   {
00473     Log::error("CoreText::rawboundingRect() error: no Font assigned to the CoreText object.\n");
00474     VL_TRAP()
00475     return aabb;
00476   }
00477 
00478   if (!font()->mFT_Face)
00479   {
00480     Log::error("CoreText::rawboundingRect() error: invalid FT_Face: probably you tried to load an unsupported font format.\n");
00481     VL_TRAP()
00482     return aabb;
00483   }
00484 
00485   fvec2 pen(0,0);
00486   fvec3 vect[4];
00487 
00488   FT_Long use_kerning = FT_HAS_KERNING( font()->mFT_Face );
00489   FT_UInt previous = 0;
00490 
00491   for(int c=0; c<(int)text.length(); c++)
00492   {
00493     if (text[c] == '\n')
00494     {
00495       pen.y() -= mFont->mHeight ? mFont->mHeight : mFont->mSize;
00496       pen.x()  = 0;
00497       continue;
00498     }
00499 
00500     const ref<Glyph>& glyph = mFont->glyph(text[c]);
00501 
00502     // if glyph == NULL there was an error during its creation...
00503     if (glyph.get() == NULL)
00504       continue;
00505 
00506     if ( kerningEnabled() && use_kerning && previous && glyph->glyphIndex())
00507     {
00508       FT_Vector delta; delta.y = 0;
00509       if (layout() == LeftToRightText)
00510       {
00511         FT_Get_Kerning( font()->mFT_Face, previous, glyph->glyphIndex(), FT_KERNING_DEFAULT, &delta );
00512         pen.x() += delta.x / 64.0f;
00513       }
00514       else
00515       if (layout() == RightToLeftText)
00516       {
00517         FT_Get_Kerning( font()->mFT_Face, glyph->glyphIndex(), previous, FT_KERNING_DEFAULT, &delta );
00518         pen.x() -= delta.x / 64.0f;
00519       }
00520       pen.y() += delta.y / 64.0f;
00521     }
00522     previous = glyph->glyphIndex();
00523 
00524     if ( glyph->textureHandle() )
00525     {
00526       int left = layout() == RightToLeftText ? -glyph->left() : +glyph->left();
00527 
00528       vect[0].x() = pen.x() + glyph->width()*0 + left -1;
00529       vect[0].y() = pen.y() + glyph->height()*0 + glyph->top() - glyph->height() -1;
00530 
00531       vect[1].x() = pen.x() + glyph->width()*1 + left +1;
00532       vect[1].y() = pen.y() + glyph->height()*0 + glyph->top() - glyph->height() -1;
00533 
00534       vect[2].x() = pen.x() + glyph->width()*1 + left +1;
00535       vect[2].y() = pen.y() + glyph->height()*1 + glyph->top() - glyph->height() +1;
00536 
00537       vect[3].x() = pen.x() + glyph->width()*0 + left -1;
00538       vect[3].y() = pen.y() + glyph->height()*1 + glyph->top() - glyph->height() +1;
00539 
00540       if (layout() == RightToLeftText)
00541       {
00542         vect[0].x() -= glyph->width()-1 +2;
00543         vect[1].x() -= glyph->width()-1 +2;
00544         vect[2].x() -= glyph->width()-1 +2;
00545         vect[3].x() -= glyph->width()-1 +2;
00546       }
00547 
00548       vect[0].y() -= mFont->mHeight;
00549       vect[1].y() -= mFont->mHeight;
00550       vect[2].y() -= mFont->mHeight;
00551       vect[3].y() -= mFont->mHeight;
00552     }
00553 
00554     aabb.addPoint( (vec3)vect[0] );
00555     aabb.addPoint( (vec3)vect[1] );
00556     aabb.addPoint( (vec3)vect[2] );
00557     aabb.addPoint( (vec3)vect[3] );
00558 
00559     if (layout() == LeftToRightText)
00560       pen += glyph->advance();
00561     else
00562     if (layout() == RightToLeftText)
00563       pen -= glyph->advance();
00564   }
00565 
00566   return aabb;
00567 }
00568 //-----------------------------------------------------------------------------
00569 void CoreText::renderBackground(const Actor*, const Camera*) const
00570 {
00571   // mic fixme:
00572   // rendering of border and background follows different rules in 3D compared from 2D: lines and polygons follow different rasterization rules!
00573 
00574   // Background color
00575   glColor4fv(mBackgroundColor.ptr());
00576 
00577   // Constant normal
00578   glNormal3fv( fvec3(0,0,1).ptr() );
00579 
00580   vec3 a,b,c,d;
00581   AABB bbox = boundingRect(); // mic fixme: this guy recomputes the bounds again instead of using the precomputed one!!
00582   a = bbox.minCorner();
00583   b.x() = (float)bbox.maxCorner().x();
00584   b.y() = (float)bbox.minCorner().y();
00585   c = bbox.maxCorner();
00586   d.x() = (float)bbox.minCorner().x();
00587   d.y() = (float)bbox.maxCorner().y();
00588   // set z to 0
00589   a.z() = b.z() = c.z() = d.z() = 0;
00590 
00591   fvec3 vect[] = { (fvec3)a, (fvec3)b, (fvec3)c, (fvec3)d };
00592   glEnableClientState( GL_VERTEX_ARRAY );
00593   glVertexPointer(3, GL_FLOAT, 0, vect);
00594 
00595   glDrawArrays(GL_QUADS,0,4);
00596 
00597   glDisableClientState( GL_VERTEX_ARRAY );
00598 }
00599 //-----------------------------------------------------------------------------
00600 void CoreText::renderBorder(const Actor*, const Camera*) const
00601 {
00602   // mic fixme:
00603   // rendering of border and background follows different rules in 3D compared from 2D: lines and polygons follow different rasterization rules!
00604 
00605   // Border color
00606   glColor4fv(mBorderColor.ptr());
00607 
00608   // Constant normal
00609   glNormal3fv( fvec3(0,0,1).ptr() );
00610 
00611   vec3 a,b,c,d;
00612   AABB bbox = boundingRect(); // mic fixme: this guy recomputes the bounds again instead of using the precomputed one!!
00613   a = bbox.minCorner();
00614   b.x() = (float)bbox.maxCorner().x();
00615   b.y() = (float)bbox.minCorner().y();
00616   c = bbox.maxCorner();
00617   d.x() = (float)bbox.minCorner().x();
00618   d.y() = (float)bbox.maxCorner().y();
00619   // set z to 0
00620   a.z() = b.z() = c.z() = d.z() = 0;
00621 
00622   fvec3 vect[] = { (fvec3)a, (fvec3)b, (fvec3)c, (fvec3)d };
00623   glEnableClientState( GL_VERTEX_ARRAY );
00624   glVertexPointer(3, GL_FLOAT, 0, vect);
00625 
00626   glDrawArrays(GL_LINE_LOOP,0,4);
00627 
00628   glDisableClientState( GL_VERTEX_ARRAY );
00629 }
00630 //-----------------------------------------------------------------------------
00631 AABB CoreText::boundingRect() const
00632 {
00633   return boundingRect(text());
00634 }
00635 //-----------------------------------------------------------------------------
00636 AABB CoreText::boundingRect(const String& text) const
00637 {
00638   AABB bbox = rawboundingRect( text );
00639   bbox.setMaxCorner( bbox.maxCorner() + vec3(2.0f*margin(), 2.0f*margin(), 0) );
00640 
00641   // normalize coordinate orgin to the bottom/left corner
00642   vec3 min = bbox.minCorner() - bbox.minCorner();
00643   vec3 max = bbox.maxCorner() - bbox.minCorner();
00644 
00645   // text pivot
00646 
00647   if (textOrigin() & AlignHCenter)
00648   {
00649     VL_CHECK( !(textOrigin() & AlignRight) )
00650     VL_CHECK( !(textOrigin() & AlignLeft) )
00651     min.x() -= int(bbox.width() / 2.0);
00652     max.x() -= int(bbox.width() / 2.0);
00653   }
00654 
00655   if (textOrigin() & AlignRight)
00656   {
00657     VL_CHECK( !(textOrigin() & AlignHCenter) )
00658     VL_CHECK( !(textOrigin() & AlignLeft) )
00659     min.x() -= (int)bbox.width();
00660     max.x() -= (int)bbox.width();
00661   }
00662 
00663   if (textOrigin() & AlignTop)
00664   {
00665     VL_CHECK( !(textOrigin() & AlignBottom) )
00666     VL_CHECK( !(textOrigin() & AlignVCenter) )
00667     min.y() -= (int)bbox.height();
00668     max.y() -= (int)bbox.height();
00669   }
00670 
00671   if (textOrigin() & AlignVCenter)
00672   {
00673     VL_CHECK( !(textOrigin() & AlignTop) )
00674     VL_CHECK( !(textOrigin() & AlignBottom) )
00675     min.y() -= int(bbox.height() / 2.0);
00676     max.y() -= int(bbox.height() / 2.0);
00677   }
00678 
00679   AABB aabb;
00680   aabb.setMinCorner(min);
00681   aabb.setMaxCorner(max);
00682   return aabb;
00683 }
00684 //-----------------------------------------------------------------------------

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