00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
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
00059
00060
00061
00062
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
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
00083 if (backgroundEnabled())
00084 renderBackground( actor, camera );
00085
00086 if (borderEnabled())
00087 renderBorder( actor, camera );
00088
00089
00090
00091
00092 if (shadowEnabled())
00093 renderText( actor, camera, shadowColor(), shadowVector() );
00094
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
00103 renderText( actor, camera, color(), fvec2(0,0) );
00104
00105
00106
00107
00108
00109 glDepthMask(depth_mask);
00110
00111 glStencilMask(0);
00112
00113
00114 glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
00115
00116
00117 renderBackground( actor, camera );
00118
00119 renderBorder( actor, camera );
00120
00121
00122 glColorMask(color_mask[0],color_mask[1],color_mask[2],color_mask[3]);
00123
00124
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
00132
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
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
00169
00170
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() );
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
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
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
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
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
00277
00278
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
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
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
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
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
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
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
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
00455 m.translate( 0, (float)int((viewport[3]-1.0f) / 2.0f), 0);
00456 }
00457 }
00458 #endif
00459
00460
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
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
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
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
00515 }
00516 else
00517 if (layout() == RightToLeftText)
00518 {
00519 pen.x() -= just_space + (just_remained_space?1:0);
00520
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
00531 }
00532 else
00533 if (layout() == RightToLeftText)
00534 {
00535 pen.x() -= glyph->advance().x();
00536
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
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
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
00654
00655
00656 vect[0].x() += margin();
00657 vect[1].x() += margin();
00658 vect[2].x() += margin();
00659 vect[3].x() += margin();
00660
00661
00662
00663
00664
00665
00666
00667
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
00710
00711
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
00766
00767
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
00819 vec3 min = bbox.minCorner() - bbox.minCorner();
00820 vec3 max = bbox.maxCorner() - bbox.minCorner();
00821
00822
00823
00824
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
00859
00860
00861
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
00900 a.z() = b.z() = c.z() = d.z() = 0;
00901
00902
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
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
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
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
00943 m.translate( 0, (float)int((h-1.0f) / 2.0f), 0);
00944 }
00945 }
00946 #endif
00947
00948
00949 a = (mat4)m * a;
00950 b = (mat4)m * b;
00951 c = (mat4)m * c;
00952 d = (mat4)m * d;
00953
00954
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
00968 vec4 v(0,0,0,1);
00969 v = actor->transform()->worldMatrix() * v;
00970
00971
00972 camera->project(v,v);
00973
00974
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
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