00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "3d.h"
00020 #include "MyString.h"
00021 #include "text3d.h"
00022 #include "controlEngine.h"
00023
00024 extern ControlEngine ce;
00025
00026 BasicText3D::BasicText3D()
00027 {
00028 xCenter=0;
00029 yCenter=0;
00030 usePicking=FALSE;
00031 font=NULL;
00032 type=ft_unknown;
00033 material.SetFull();
00034 depth=0.1f;
00035 scale=1;
00036 zCenter=1;
00037 SetRatioXY(1);
00038 }
00039
00040 void BasicText3D::SetRatioXY(GLdouble value)
00041 {
00042 ratioXY=value;
00043 ratioYX=1.0/value;
00044 }
00045
00046 void BasicText3D::Setup(FTFont *f,FontType t,int x,int y)
00047 {
00048 font=f;
00049 type=t;
00050 xCenter=x;
00051 yCenter=y;
00052 }
00053
00054 void BasicText3D::operator=(BasicText3D &src)
00055 {
00056 material=src.material;
00057 font=src.font;
00058 type=src.type;
00059 xCenter=src.xCenter;
00060 yCenter=src.yCenter;
00061 depth=src.depth;
00062 scale=src.scale;
00063 zCenter=src.zCenter;
00064 usePicking=src.usePicking;
00065 }
00066
00078 BOOL BasicText3D::DrawPicking(char *text)
00079 {
00080
00081 return usePicking?Draw(text):FALSE;
00082 }
00083
00084 BOOL BasicText3D::Draw(char letter)
00085 {
00086 char valueCur[2]={0,0};
00087 valueCur[0]=letter;
00088 return Draw(valueCur);
00089 }
00090
00091 BOOL BasicText3D::Draw(char *text)
00092 {
00093 if (!font) return FALSE;
00094 ce.monitor.End("draw");
00095 BOOL result = TRUE;
00096 material.Use();
00097 glPushMatrix();
00098 Point3D<float> decal;
00099 decal.z=(float)zCenter+(type==ft_extrude)?depth:0;
00100
00101 ce.monitor.Begin("textRenderCenter");
00102 switch (xCenter)
00103 {
00104 case -1: break;
00105 case 0: decal.x= -GetWidth(text)/2.0f; break;
00106 case 1: decal.x= -GetWidth(text); break;
00107 }
00108
00109 switch (yCenter)
00110 {
00111 case -1: decal.y= -GetAscender(); break;
00112 case 0: break;
00113 case 1: decal.y= -GetDescender(); break;
00114 }
00115
00116 if (ratioXY!=1) glScaled(1.0/ratioXY,1,1);
00117 decal.glTranslated();
00118 ce.monitor.End("textRenderCenter");
00119 ce.monitor.Begin("textRender");
00120 switch(type)
00121 {
00122 case ft_texture:
00123
00124 glEnable(GL_TEXTURE_2D);
00125 {
00126 FTGLTextureFont *curFont = (FTGLTextureFont *)font;
00127 curFont->Render(text);
00128 }
00129 glDisable(GL_BLEND);
00130
00131 break;
00132 case ft_extrude:
00133 font->Depth(depth);
00134
00135
00136
00137 font->Render(text);
00138 break;
00139 case ft_bitmap:
00140 case ft_pixmap:
00141 glRasterPos2f(0,0);
00142 font->Render(text);
00143 break;
00144 case ft_outline:
00145 case ft_polygon:
00146 glDisable(GL_BLEND);
00147 font->Render(text);
00148 break;
00149 case ft_unknown: result = FALSE;
00150 }
00151 ce.monitor.End("textRender");
00152 glPopMatrix();
00153 ce.monitor.Begin("draw");
00154 return result;
00155 }
00156
00157 Point3D<float> BasicText3D::GetBox(char *text)
00158 {
00159 Point3D<float> start,end,delta;
00160 if (!font) return delta;
00161 font->BBox(text, start.x,start.y,start.z, end.x,end.y,end.z);
00162 delta.Set(end.x-start.x,end.y-start.y,end.z-start.z);
00163 return end;
00164 }
00165
00166 float BasicText3D::GetAscender()
00167 {
00168 return font->Ascender();
00169 }
00170
00171 float BasicText3D::GetDescender()
00172 {
00173 return font->Descender();
00174 }
00175
00176 float BasicText3D::GetHeight()
00177 {
00178 return GetAscender()-GetDescender();
00179 }
00180
00181 float BasicText3D::GetWidth(char letter)
00182 {
00183 char valueCur[2]={0,0};
00184 valueCur[0]=letter;
00185 return GetWidth(valueCur);
00186 }
00187
00189 float BasicText3D::GetWidth(char *text)
00190 {
00191 return font->Advance(text);
00192 }
00193
00194
00195
00196 ParsingLine::ParsingLine() : ParsingElem()
00197 {
00198 nbChar=0;
00199 deltaY=0;
00200 align=align_begin;
00201 }
00202
00203 void ParsingLine::operator=(ParsingLine &src)
00204 {
00205 ParsingElem::operator=(src);
00206 nbChar=src.nbChar;
00207 deltaY=src.deltaY;
00208 align=src.align;
00209 words=src.words;
00210 }
00211
00212
00213
00214 ParsingElem::ParsingElem()
00215 {
00216 deltaX=0;
00217 isWord=FALSE;
00218 }
00219
00220 void ParsingElem::operator=(ParsingElem &src)
00221 {
00222 deltaX=src.deltaX;
00223 isWord=src.isWord;
00224 }
00225
00226
00227
00228 ParsingWord::ParsingWord() : ParsingElem()
00229 {
00230 deltaX=0;
00231 }
00232
00233 void ParsingWord::operator=(ParsingWord &src)
00234 {
00235 ParsingElem::operator=(src);
00236 text=src.text;
00237 }
00238
00239
00240
00241 Text3D::Text3D()
00242 {
00243 idCallList=0;
00244 xAlign=align_begin;
00245 yAlign=align_begin;
00246 SetJustifyLimit(10,10);
00247 enableClipping=FALSE;
00248 isChanged=FALSE;
00249 SetWrapping(FALSE,TRUE,TRUE);
00250 }
00251
00252 Text3D::~Text3D()
00253 {
00254 if (idCallList) glDeleteLists(idCallList,1);
00255 }
00256 void Text3D::operator=(Text3D &src)
00257 {
00258 BasicText3D::operator=(src);
00259 clipping=src.clipping;
00260 xAlign=src.xAlign;
00261 yAlign=src.yAlign;
00262 enableClipping=src.enableClipping;
00263 idCallList=0;
00264 isChanged=TRUE;
00265 wordWrap=src.wordWrap;
00266 lineWrap=src.lineWrap;
00267 letterWrap=src.letterWrap;
00268 xJustifyLimit=src.xJustifyLimit;
00269 }
00270
00271 void Text3D::SetWrapping(BOOL line,BOOL word,BOOL letter)
00272 {
00273 wordWrap=word;
00274 lineWrap=line;
00275 letterWrap=letter;
00276 }
00277
00278 void Text3D::SetClipping(double xClipping,double yClipping)
00279 {
00280 isChanged=isChanged||clipping.x!=xClipping||clipping.y!=yClipping;
00281 enableClipping=TRUE;
00282 clipping.Set(xClipping,yClipping);
00283 }
00284
00285 void Text3D::SetClipping(Point2D<double> newClipping)
00286 {
00287 isChanged=isChanged||clipping.x!=newClipping.x||clipping.y!=newClipping.y;
00288 enableClipping=TRUE;
00289 clipping=newClipping;
00290 }
00291
00292 void Text3D::SetAlign(TextAlign x,TextAlign y)
00293 {
00294 isChanged=isChanged||xAlign!=x||yAlign!=y;
00295 xAlign=x;
00296 yAlign=y;
00297 }
00298
00299 void Text3D::Setup(FTFont *f,FontType t)
00300 {
00301 isChanged=isChanged||font!=f||type!=t;
00302 BasicText3D::Setup(f,t,-1,-1);
00303 }
00304
00305 void Text3D::ComputeSize(MyList<ParsingLine> *linesCur,BOOL isWordSizeCompute)
00306 {
00307 ParsingLine *line;
00308 for (linesCur->i=0;linesCur->i.More();linesCur->i++)
00309 {
00310 line = linesCur->i.GetElemPtr();
00311 ComputeLineSize(line,isWordSizeCompute);
00312 }
00313 }
00314
00315 void Text3D::ComputeLineSize(ParsingLine *line,BOOL isWordSizeCompute)
00316 {
00317 ParsingWord *word;
00318 line->nbChar=0;
00319 line->deltaX=0;
00320 line->deltaY=GetHeight();
00321 line->align=xAlign;
00322 for (line->words.i=0;line->words.i.More();line->words.i++)
00323 {
00324 word = line->words.i.GetElem();
00325 if (isWordSizeCompute) word->deltaX=GetWidth(word->text);
00326 line->deltaX+=word->deltaX;
00327 line->nbChar+=word->text.GetSize();
00328 }
00329 }
00330
00336 float Text3D::AddLine(ParsingLine *line)
00337 {
00338 ParsingLine **lineOutPtr = linesUses.i.AddNewLast();
00339 *lineOutPtr=line;
00340
00341 int nbObject;
00342 line->xPos=0;
00343 line->xJustify=0;
00344 switch(line->align)
00345 {
00346 case align_begin: break;
00347 case align_center:
00348 line->xPos=(realClipping.x-line->deltaX)/2.0;
00349 break;
00350 case align_end:
00351 line->xPos=realClipping.x-line->deltaX;
00352 break;
00353 case align_justify:
00354 if (wordWrap) nbObject = (line->words.GetNbElem()+1)/2;
00355 else nbObject = line->nbChar;
00356 if (nbObject>1) line->xJustify=(realClipping.x-line->deltaX)/(GLdouble)(nbObject-1);
00357 if (line->xJustify>xJustifyLimit) line->xJustify=0;
00358 break;
00359 }
00360 return line->deltaY;
00361 }
00362
00363 void Text3D::ApplyRealClipping()
00364 {
00365 if (scale!=1)
00366 {
00367 glScaled(scale,scale,1);
00368 realClipping=clipping/scale;
00369 }
00370 else realClipping=clipping;
00371 }
00372
00383 BOOL Text3D::Draw()
00384 {
00385
00386 if (value.IsEmpty()) return TRUE;
00387 ce.monitor.Begin("text");
00388
00389 glPushMatrix();
00390 ApplyRealClipping();
00391 ComputeSize(&lines,TRUE);
00392 double ySize=ComputeLayout();
00393
00394
00395 yJustify = 0;
00396 switch(yAlign)
00397 {
00398 case align_begin: break;
00399 case align_center: glTranslated(0,-(realClipping.y-ySize)/2.0,0); break;
00400 case align_end: glTranslated(0,-(realClipping.y-ySize),0); break;
00401 case align_justify:
00402 if (linesUses.GetNbElem()>1)
00403 {
00404 yJustify=(realClipping.y-ySize)/(double)(linesUses.GetNbElem()-1);
00405 if (yJustify>yJustifyLimit) yJustify=0;
00406 }
00407 }
00408
00409
00410 for (linesUses.i=0;linesUses.i.More();linesUses.i++)
00411 DrawLine(linesUses.i.GetElem());
00412 glPopMatrix();
00413 ce.monitor.End("text");
00414 return TRUE;
00415 }
00416
00417
00418 void Text3D::SetText(char *text)
00419 {
00420 value=text;
00421 AnalyseGram();
00422 }
00423
00443 BOOL Text3D::AnalyseLex(int indBegin,int *indEnd,BOOL *isEnd,BOOL *isReturn)
00444 {
00445 char letter;
00446 BOOL isSeparator = FALSE;
00447 BOOL isWord = FALSE;
00448 *isReturn=FALSE;
00449 *isEnd=FALSE;
00450 int i;
00451 for (i=indBegin;i<value.GetSize();i++)
00452 {
00453 letter=value[i];
00454 switch (letter)
00455 {
00456 case '\n':
00457 *indEnd=i;
00458 *isReturn=TRUE;
00459 return isWord;
00460 case ' ':
00461 case '\t':
00462 if (isWord)
00463 {
00464 *indEnd=i;
00465 return isWord;
00466 }
00467 isSeparator=TRUE;
00468 break;
00469 default:
00470 if (isSeparator)
00471 {
00472 *indEnd=i;
00473 return isWord;
00474 }
00475 isWord=TRUE;
00476 }
00477 }
00478 *indEnd=i;
00479 *isEnd=TRUE;
00480 return isWord;
00481 }
00482
00488 void Text3D::AnalyseGram()
00489 {
00490 lines.i.SuprAll();
00491 words.i.SuprAll();
00492
00493 ParsingLine *line = NULL;
00494 ParsingWord *word = NULL;
00495
00496 BOOL isEnd;
00497 BOOL isReturn;
00498 BOOL isWord;
00499 int indBegin = 0;
00500 int indEnd;
00501 do
00502 {
00503 isWord = AnalyseLex(indBegin,&indEnd,&isEnd,&isReturn);
00504 if (isEnd&&(indBegin==indEnd)) break;
00505 if (!line) line = lines.i.AddNewLast();
00506 if (isReturn&&(indBegin==indEnd))
00507 {
00508 line=NULL;
00509 indBegin++;
00510 continue;
00511 }
00512 word = words.i.AddNewLast();
00513 word->text=value.Mids(indBegin,indEnd-indBegin);
00514 indBegin=indEnd;
00515 word->isWord=isWord;
00516 line->words.i+=word;
00517 if (isReturn) { indBegin++; line = NULL; }
00518 } while (!isEnd);
00519 }
00520
00521 float Text3D::ComputeLayout()
00522 {
00523
00524 layoutLines.i.SuprAll();
00525 layoutWords.i.SuprAll();
00526 linesUses.i.SuprAll();
00527
00528 ParsingLine *line;
00529 ParsingWord *word;
00530 BOOL testDeltaX=FALSE;
00531
00532 GLfloat yPos=0;
00533 for (lines.i=0;lines.i.More();lines.i++)
00534 {
00535 line = lines.i.GetElemPtr();
00536 if (enableClipping)
00537 {
00538 if ((line->deltaY+yPos)>realClipping.y) return yPos;
00539 if (line->deltaX<=realClipping.x)
00540 {
00541 yPos+=AddLine(line);
00542 continue;
00543 }
00544 }
00545 else
00546 {
00547 yPos+=AddLine(line);
00548 continue;
00549 }
00550
00551
00552 ParsingLine *layoutLine = NULL;
00553 ParsingWord *newWord,*wordCutting;
00554 double xPos;
00555 int offsetLetter=0;
00556 BOOL goNext = TRUE;
00557
00558
00559
00560 for (line->words.i=0;line->words.i.More();line->words.i.GoIndex(list_current,goNext))
00561 {
00562 goNext=TRUE;
00563 if (!layoutLine)
00564 {
00565 if ((yPos+line->deltaY)>realClipping.y) return yPos;
00566 layoutLine = layoutLines.i.AddNewLast();
00567 layoutLine->deltaY=line->deltaY;
00568 xPos=0;
00569 }
00570 if (offsetLetter)
00571 {
00572 wordCutting = layoutWords.i.AddNewLast();
00573 *wordCutting=*word;
00574 wordCutting->text=word->text.Mids(offsetLetter,word->text.GetSize()-offsetLetter);
00575 wordCutting->deltaX=GetWidth(wordCutting->text);
00576 word=wordCutting;
00577 offsetLetter=0;
00578 }
00579 else word = line->words.i.GetElem();
00580
00581 xPos+=word->deltaX;
00582 if (xPos>realClipping.x)
00583 {
00584 if (wordWrap)
00585 {
00586 ComputeLineSize(layoutLine,FALSE);
00587 yPos+=AddLine(layoutLine);
00588 layoutLine=NULL;
00589 if (!lineWrap)
00590 {
00591 goNext=FALSE;
00592 continue;
00593 }
00594 else break;
00595 }
00596 else
00597 {
00598 newWord = layoutWords.i.AddNewLast();
00599 *newWord = *word;
00600 double deltaLetter;
00601 double deltaNeed = xPos-realClipping.x;
00602 double sumDeltaLetter = 0;
00603 for (offsetLetter=word->text.GetSize()-1;offsetLetter>=0;offsetLetter--)
00604 {
00605 deltaLetter = GetWidth(word->text[offsetLetter]);
00606 sumDeltaLetter+=deltaLetter;
00607 deltaNeed-=deltaLetter;
00608 if (deltaNeed<=0) break;
00609 }
00610
00611 newWord->deltaX=word->deltaX-(GLfloat)sumDeltaLetter;
00612 newWord->text= word->text.Mids(0,offsetLetter);
00613 layoutLine->words.i+=newWord;
00614 xPos=0;
00615 ComputeLineSize(layoutLine,FALSE);
00616 yPos+=AddLine(layoutLine);
00617 layoutLine=NULL;
00618 if (!lineWrap)
00619 {
00620 goNext=FALSE;
00621 continue;
00622 }
00623 else
00624 {
00625 offsetLetter=0;
00626 break;
00627 }
00628 }
00629 }
00630 else layoutLine->words.i+=word;
00631 }
00632 if (layoutLine)
00633 {
00634 ComputeLineSize(layoutLine,FALSE);
00635 yPos+=AddLine(layoutLine);
00636 layoutLine=NULL;
00637 }
00638 }
00639 return yPos;
00640 }
00641
00642 char * Text3D::GetText()
00643 {
00644 return value.GetValue();
00645 }
00646
00647 void Text3D::DrawLine(ParsingLine *line)
00648 {
00649 GLdouble xMove = line->xPos;
00650 GLdouble xPos=0;
00651 ParsingWord *word;
00652 for (line->words.i=0;line->words.i.More();line->words.i++)
00653 {
00654 word = line->words.i.GetElem();
00655 if (word->isWord)
00656 {
00657 if (!wordWrap)
00658 {
00659 if (!line->xJustify)
00660 {
00661 xPos+=xMove;
00662 glTranslated(xMove,0,0);
00663 BasicText3D::Draw(word->text);
00664 xMove = word->deltaX;
00665 }
00666 else
00667 {
00668 char letter;
00669 for (int i=0;i<word->text.GetSize();i++)
00670 {
00671 letter=word->text[i];
00672 xPos+=xMove;
00673 glTranslated(xMove,0,0);
00674 BasicText3D::Draw(letter);
00675 xMove=GetWidth(letter)+line->xJustify;
00676 }
00677 }
00678 }
00679 else
00680 {
00681 xPos+=xMove;
00682 glTranslated(xMove,0,0);
00683 BasicText3D::Draw(word->text);
00684 xMove = word->deltaX+line->xJustify;
00685 }
00686 }
00687 else xMove+=word->deltaX;
00688 }
00689 glTranslated(-xPos,-line->deltaY-yJustify,0);
00690 }
00691
00692 BOOL Text3D::DrawPicking()
00693 {
00694 if (!usePicking) return FALSE;
00695
00696
00697 return TRUE;
00698 }
00699
00701
00702 void Text3D::SetJustifyLimit(GLdouble x,GLdouble y)
00703 {
00704 xJustifyLimit = x;
00705 yJustifyLimit = y;
00706 }