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