Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

text3d.cpp

Go to the documentation of this file.
00001 /* *************************************************************************************
00002         Writer:         Sebastien Bloc
00003         Copyright:      2003-2004
00004         eMail:          sebastien.bloc@free.fr
00005         URL:            http://mignonsoft.free.fr
00006 
00007         This program is free software; you can redistribute it and/or
00008         modify it under the terms of the GNU General Public License
00009         as published by the Free Software Foundation; either version 2
00010         of the License, or (at your option) any later version.
00011 
00012         This program is distributed in the hope that it will be useful,
00013         but WITHOUT ANY WARRANTY; without even the implied warranty of
00014         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015         GNU General Public License for more details.
00016         http://www.gnu.org/copyleft/gpl.html
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         //glPushName(idLetter);
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; // petit decalade dans les z pour eviter que le text soit caché par la face l'englobant
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                 // le contour des lettres doivent etre transparente
00124                 glEnable(GL_TEXTURE_2D); // bug de la ftgl ?! ca devrais etre automatique d'apres moi
00125                 {
00126                         FTGLTextureFont *curFont = (FTGLTextureFont *)font;
00127                         curFont->Render(text);
00128                 }
00129                 glDisable(GL_BLEND);
00130                 //font->Render(text);
00131                 break;
00132         case ft_extrude:
00133                 font->Depth(depth); // profondeur de l'extrude          
00134                 //glEnable(GL_DEPTH_TEST);
00135                 //glDisable(GL_BLEND);
00136                 //glNormal3f(0,0,1);
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; // erreur
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; // copie de la list des mots (a verrifié)
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; // si recopie le callList dois etre differentié
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; //  0=>0 , 1=>1 , 2=>1 , 3=>2, etc ...
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; // si la justification espace trop les mots alirs anule la justification
00358                 break; 
00359         }
00360         return line->deltaY;
00361 }
00362 
00363 void Text3D::ApplyRealClipping()
00364 {
00365         if (scale!=1)
00366         {
00367                 glScaled(scale,scale,1); // taille relative     
00368                 realClipping=clipping/scale; // agrandi le clipping pour coller au scalling
00369         }
00370         else realClipping=clipping;
00371 }
00372 
00383 BOOL Text3D::Draw()
00384 {
00385         //return TRUE;
00386         if (value.IsEmpty()) return TRUE;
00387         ce.monitor.Begin("text");
00388 
00389         glPushMatrix();
00390         ApplyRealClipping();    // calcul le clipping reel suivant le scale
00391         ComputeSize(&lines,TRUE); // calcul la taille des mots et des lignes
00392         double ySize=ComputeLayout();// calcul de la mise en page
00393 
00394         // alignement dans les Y
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         // affichage proprement dit
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; // si c'est la fin sans mots ==> finir
00505                 if (!line) line = lines.i.AddNewLast();
00506                 if (isReturn&&(indBegin==indEnd)) 
00507                 {       // ligne suivante sans mots
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         // mise a zero
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         {       // iteration sur les lignes
00535                 line = lines.i.GetElemPtr();
00536                 if (enableClipping)
00537                 {       // test du clipping, peut on affiché la ligne ?
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                 // on est sortie du clipping => gestion des wrapping
00552                 ParsingLine *layoutLine = NULL;
00553                 ParsingWord *newWord,*wordCutting;
00554                 double xPos;
00555                 int offsetLetter=0;
00556                 BOOL goNext = TRUE;
00557 
00558                 // remplie layoutLine du text affichable
00559                 // on arrive ici uniquement si la ligne deplace le clipping autorisé
00560                 for (line->words.i=0;line->words.i.More();line->words.i.GoIndex(list_current,goNext))
00561                 {       // iteration de tout les mots de la ligne
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                         {       // sort t'on du clipping en X
00584                                 if (wordWrap) 
00585                                 {       // affiche la ligne delimité et poursuis
00586                                         ComputeLineSize(layoutLine,FALSE);
00587                                         yPos+=AddLine(layoutLine);
00588                                         layoutLine=NULL;
00589                                         if (!lineWrap)
00590                                         {       // si retour a la ligne automatique active poursuivre
00591                                                 goNext=FALSE; // toujours sur le meme mots
00592                                                 continue;
00593                                         }
00594                                         else break;
00595                                 }
00596                                 else
00597                                 {       // si pas wordWrap cherché le caractere dans la ligne qui le delimite
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                                         {       // recherche du caracter qui fait sortir du clipping
00605                                                 deltaLetter = GetWidth(word->text[offsetLetter]);
00606                                                 sumDeltaLetter+=deltaLetter;
00607                                                 deltaNeed-=deltaLetter;
00608                                                 if (deltaNeed<=0) break;
00609                                         }
00610                                         // decoupage en 2 word pour le passage a la ligne
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                                         {       // si retour a la ligne automatique active poursuivre
00620                                                 goNext=FALSE; // toujours sur le meme mots
00621                                                 continue;
00622                                         }
00623                                         else 
00624                                         { 
00625                                                 offsetLetter=0; 
00626                                                 break; 
00627                                         }
00628                                 }
00629                         }
00630                         else layoutLine->words.i+=word; // si pas de probleme de clipping ajout le mots
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); // si le mots n'a pas de séparation
00664                                         xMove = word->deltaX;
00665                                 }
00666                                 else
00667                                 {       // si le mots a des separations
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);   // passe a la ligne suivante
00690 }
00691 
00692 BOOL Text3D::DrawPicking()
00693 {
00694         if (!usePicking) return FALSE;
00695         //glPushName(idLetter);
00696         //return Draw();
00697         return TRUE;
00698 }
00699 
00701 
00702 void Text3D::SetJustifyLimit(GLdouble x,GLdouble y)
00703 {
00704         xJustifyLimit = x;
00705         yJustifyLimit = y;
00706 }

Generated on Fri Aug 20 19:19:50 2004 for 3d Controls by doxygen 1.3.6