Font.cpp
Go to the documentation of this file.00001 //*** Font.cpp ** 00002 00003 #include "Font.h" 00004 #include "Image.h" 00005 #include "StandardLibrary.h" 00006 #include "Bitmap_RLE8.h" 00007 #include "ColorHelper.h" 00008 #include "Asset.h" 00009 #include "Bitmap.h" 00010 #include "Filename.h" 00011 00012 00013 //*** Constructor *** 00014 00015 Font::Font(): 00016 size_(0), 00017 lineSpacing_(0), 00018 baseline_(0), 00019 layerCount_(0) 00020 { 00021 } 00022 00023 00024 //*** Constructor *** 00025 00026 Font::Font(const Asset& asset): 00027 size_(0), 00028 lineSpacing_(0), 00029 baseline_(0), 00030 layerCount_(0) 00031 { 00032 if (asset.Open()) 00033 { 00034 char header[8]; 00035 asset.Read(header,8); 00036 if (StrNCmp(header,"PIXIE_FN",8)==0) 00037 { 00038 char h; 00039 asset.Read(&h); 00040 Assert(h=='T',"Invalid header"); 00041 if (h!='T') 00042 { 00043 asset.Close(); 00044 return; 00045 } 00046 int version=0; 00047 asset.Read(&version); 00048 if (version==0) 00049 { 00050 ReadFromAsset(&asset); 00051 } 00052 } 00053 else if (StrNCmp(header,"FNTRLE8B",8)==0) 00054 { 00055 int version=0; 00056 asset.Read(&version); 00057 if (version==0) 00058 { 00059 ReadFromAssetNew(&asset); 00060 } 00061 } 00062 else 00063 { 00064 Assert(false,"Invalid header"); 00065 } 00066 asset.Close(); 00067 } 00068 // Report missing file 00069 #ifdef _DEBUG 00070 else 00071 { 00072 const char* filename=asset.GetFilename().GetString(); 00073 if (filename) 00074 { 00075 char errorMessage[1024]; 00076 SNPrintF(errorMessage,1024,"File not found: %s",filename); 00077 Assert(false,errorMessage); 00078 } 00079 else 00080 { 00081 Assert(false,"An asset could not be accessed."); 00082 } 00083 } 00084 #endif 00085 } 00086 00087 00088 //*** Constructor *** 00089 00090 Font::Font(const Filename& filename): 00091 size_(0), 00092 lineSpacing_(0), 00093 baseline_(0), 00094 layerCount_(0) 00095 { 00096 LoadFont(filename); 00097 } 00098 00099 00100 //*** LoadFont *** 00101 00102 void Font::LoadFont(const Filename& filename) 00103 { 00104 int length=StrLen(filename.GetString()); 00105 if (ToLower(filename.GetString()[length-3])=='f' && ToLower(filename.GetString()[length-2])=='n' && ToLower(filename.GetString()[length-1])=='t') 00106 { 00107 Asset asset(filename); 00108 if (asset.Open()) 00109 { 00110 char header[8]; 00111 asset.Read(header,8); 00112 if (StrNCmp(header,"PIXIE_FN",8)==0) 00113 { 00114 char h; 00115 asset.Read(&h); 00116 Assert(h=='T',"Invalid header"); 00117 if (h!='T') 00118 { 00119 asset.Close(); 00120 return; 00121 } 00122 int version=0; 00123 asset.Read(&version); 00124 if (version==0) 00125 { 00126 ReadFromAsset(&asset); 00127 } 00128 } 00129 else if (StrNCmp(header,"FNTRLE8B",8)==0) 00130 { 00131 int version=0; 00132 asset.Read(&version); 00133 if (version==0) 00134 { 00135 ReadFromAssetNew(&asset); 00136 } 00137 } 00138 else 00139 { 00140 Assert(false,"Invalid header"); 00141 } 00142 asset.Close(); 00143 } 00144 // Report missing file 00145 #ifdef _DEBUG 00146 else 00147 { 00148 const char* filename=asset.GetFilename().GetString(); 00149 if (filename) 00150 { 00151 char errorMessage[1024]; 00152 SNPrintF(errorMessage,1024,"File not found: %s",filename); 00153 Assert(false,errorMessage); 00154 } 00155 else 00156 { 00157 Assert(false,"An asset could not be accessed."); 00158 } 00159 } 00160 #endif 00161 return; 00162 } 00163 00164 // Load font definition 00165 LoadXML(filename); 00166 00167 layerCount_=layers_.GetItemCount(); 00168 00169 // Find path 00170 const char* l1=StrRChr(filename.GetString(),'/'); 00171 const char* l2=StrRChr(filename.GetString(),'\\'); 00172 const char* l=l1; 00173 if (l2>l) 00174 { 00175 l=l2; 00176 } 00177 char path[1024]; 00178 if (l>0) 00179 { 00180 int len=(int)(l-filename.GetString()+1); 00181 StrNCpy(path,filename.GetString(),len); 00182 path[len]=0; 00183 } 00184 else 00185 { 00186 StrCpy(path,""); 00187 } 00188 00189 00190 // Create RLE bitmaps 00191 for (int i=0; i<layers_.GetItemCount(); i++) 00192 { 00193 const char* filename=layers_.Get(i); 00194 char filenameFullPath[1024]; 00195 SNPrintF(filenameFullPath,1024,"%s%s",path,filename); 00196 Image layer(filenameFullPath); 00197 00198 for (int i=0; i<256; i++) 00199 { 00200 Character& character=characters_[i]; 00201 if (!character.isBlank && character.width>0 && character.height>0) 00202 { 00203 Image image(character.width,character.height); 00204 for (int y=0; y<character.height; y++) 00205 { 00206 for (int x=0; x<character.width; x++) 00207 { 00208 image.SetPixel(x,y,layer.GetPixel(character.x+x,character.y+y)); 00209 } 00210 } 00211 Bitmap* bitmap= new Bitmap_RLE8(image); 00212 character.layers.Add(bitmap); 00213 00214 } 00215 else 00216 { 00217 character.isBlank=true; 00218 } 00219 } 00220 } 00221 00222 // Delete layer names 00223 for (int i=0; i<layers_.GetItemCount(); i++) 00224 { 00225 char* filename=layers_.Get(i); 00226 delete filename; 00227 } 00228 layers_.Clear(true); 00229 } 00230 00231 00232 //*** Destructor *** 00233 00234 Font::~Font() 00235 { 00236 for (int i=0; i<256; i++) 00237 { 00238 Character& character=characters_[i]; 00239 for (int i=0; i<character.layers.GetItemCount(); i++) 00240 { 00241 Bitmap* bitmap=character.layers.Get(i); 00242 delete bitmap; 00243 } 00244 } 00245 } 00246 00247 00248 //*** GetCharacter *** 00249 00250 const Font::Character& Font::GetCharacter(int ascii) const 00251 { 00252 if (size_==0 || ascii<0 || ascii>255) 00253 { 00254 static Character defaultValue; 00255 return defaultValue; 00256 } 00257 00258 return characters_[ascii]; 00259 } 00260 00261 00262 //*** Blit *** 00263 00264 void Font::Blit(Bitmap& bitmap, int x, int y, const char* text, int spacing, unsigned short modulate, unsigned char alpha) const 00265 { 00266 if (size_==0) 00267 { 00268 return; 00269 } 00270 int textLength=StrLen(text); 00271 int previousCharacter=0; 00272 for (int i=0; i<layerCount_; i++) 00273 { 00274 int xp=x; 00275 for (int j=0; j<textLength; j++) 00276 { 00277 const Character& character=GetCharacter(text[j]); 00278 int kerning=0; 00279 if (j>0) 00280 { 00281 kerning=GetKerning(text[j-1],text[j]); 00282 } 00283 if (!character.isBlank && character.layers.GetItemCount()>i) 00284 { 00285 Bitmap* charBitmap=character.layers.Get(i); 00286 charBitmap->Blit(bitmap,xp+character.xoffset+kerning,y+character.yoffset,modulate,alpha); 00287 } 00288 00289 xp+=character.spacing+spacing+kerning; 00290 } 00291 } 00292 } 00293 00294 00295 //*** GetKerning *** 00296 00297 int Font::GetKerning(int first, int second) const 00298 { 00299 if (size_==0 || first<0 || first>255 || second<0 || second>255) 00300 { 00301 return 0; 00302 } 00303 00304 const Kerning& kerning=kerning_[first]; 00305 if (kerning.first==first && kerning.second==second) 00306 { 00307 return kerning.amount; 00308 } 00309 00310 return 0; 00311 } 00312 00313 00314 //**** WillWordFit *** 00315 00316 bool Font::WillWordFit(int xp, int maxX, const char* text, int hspacing) const 00317 { 00318 if (size_==0) 00319 { 00320 return false; 00321 } 00322 00323 int i=0; 00324 while (text[i]!=0 && text[i]!=' ') 00325 { 00326 const Character& character=GetCharacter(text[i]); 00327 xp+=character.spacing+hspacing; 00328 if (xp>=maxX) 00329 { 00330 return false; 00331 } 00332 i++; 00333 } 00334 00335 return xp<maxX; 00336 } 00337 00338 00339 //*** BlitWrap *** 00340 00341 void Font::BlitWrap(Bitmap& bitmap, int x, int y, const char* text, int width, int hspacing, int vspacing, unsigned short modulate, unsigned char alpha) const 00342 { 00343 if (size_==0) 00344 { 00345 return; 00346 } 00347 00348 int textLength=StrLen(text); 00349 for (int i=0; i<layerCount_; i++) 00350 { 00351 int xp=x; 00352 int yp=y; 00353 for (int j=0; j<textLength; j++) 00354 { 00355 if (text[j]=='\n' || xp>=x+width) 00356 { 00357 xp=x; 00358 yp+=size_+vspacing; 00359 } 00360 00361 // Will next word fit? 00362 if (text[j]==' ') 00363 { 00364 if (!WillWordFit(xp,x+width,&text[j+1],hspacing)) 00365 { 00366 xp=x; 00367 yp+=size_+vspacing; 00368 continue; 00369 } 00370 } 00371 00372 const Character& character=GetCharacter(text[j]); 00373 if (!character.isBlank && character.layers.GetItemCount()>i) 00374 { 00375 Bitmap* charBitmap=character.layers.Get(i); 00376 charBitmap->Blit(bitmap,xp+character.xoffset,yp+character.yoffset,modulate,alpha); 00377 } 00378 00379 xp+=character.spacing+hspacing; 00380 } 00381 } 00382 } 00383 00384 //*** GetBaseline *** 00385 00386 int Font::GetBaseline() const 00387 { 00388 return baseline_; 00389 } 00390 00391 00392 //*** GetSize *** 00393 00394 int Font::GetSize() const 00395 { 00396 return size_; 00397 } 00398 00399 00400 //*** GetGlyphHeight *** 00401 00402 int Font::GetGlyphHeight() const 00403 { 00404 return lineSpacing_; 00405 } 00406 00407 //*** GetBounds *** 00408 00409 Font::Bounds Font::GetBounds(const char* text, int spacing) const 00410 { 00411 if (size_==0) 00412 { 00413 Bounds bounds; 00414 bounds.width=0; 00415 bounds.height=0; 00416 00417 return bounds; 00418 } 00419 00420 int textLength=StrLen(text); 00421 int xp=0; 00422 for (int j=0; j<textLength; j++) 00423 { 00424 const Character& character=GetCharacter(text[j]); 00425 int kerning=0; 00426 if (j>0) 00427 { 00428 kerning=GetKerning(text[j-1],text[j]); 00429 } 00430 00431 xp+=character.spacing+spacing+kerning; 00432 } 00433 00434 Bounds bounds; 00435 bounds.width=xp; 00436 bounds.height=lineSpacing_+1; 00437 00438 return bounds; 00439 } 00440 00441 00442 //*** GetBoundsWrap *** 00443 00444 Font::Bounds Font::GetBoundsWrap(const char* text, int width, int hspacing, int vspacing) const 00445 { 00446 if (size_==0) 00447 { 00448 Bounds bounds; 00449 bounds.width=0; 00450 bounds.height=0; 00451 00452 return bounds; 00453 } 00454 00455 int textLength=StrLen(text); 00456 int xp=0; 00457 int yp=0; 00458 for (int j=0; j<textLength; j++) 00459 { 00460 if (text[j]=='\n' || xp>=width) 00461 { 00462 xp=0; 00463 yp+=size_+vspacing; 00464 } 00465 00466 // Will next word fit? 00467 if (text[j]==' ') 00468 { 00469 if (!WillWordFit(xp,width,&text[j+1],hspacing)) 00470 { 00471 xp=0; 00472 yp+=size_+vspacing; 00473 continue; 00474 } 00475 } 00476 00477 const Character& character=GetCharacter(text[j]); 00478 00479 xp+=character.spacing+hspacing; 00480 } 00481 00482 Bounds bounds; 00483 bounds.width=width; 00484 bounds.height=yp+size_+vspacing; 00485 00486 return bounds; 00487 } 00488 00489 00490 //*** XML_Element *** 00491 00492 XMLObject* Font::XML_Element(StringId _name, const XMLAttributeList& _attributes) 00493 { 00494 xmlCase(Character) 00495 { 00496 int ascii=xmlAttributeValue("ascii"); 00497 if (ascii>=0 && ascii<=255) 00498 { 00499 Character& character=characters_[ascii]; 00500 character.ascii=ascii; 00501 character.spacing=xmlAttributeValue("spacing"); 00502 character.x=xmlAttributeValue("x"); 00503 character.y=xmlAttributeValue("y"); 00504 character.width=xmlAttributeValue("width"); 00505 character.height=xmlAttributeValue("height"); 00506 character.xoffset=xmlAttributeValue("xoffset"); 00507 character.yoffset=xmlAttributeValue("yoffset"); 00508 character.isBlank=xmlAttributeValue("blank"); 00509 } 00510 } 00511 00512 xmlCase(Layer) 00513 { 00514 char* filename=StrDup(xmlAttributeValue("filename")); 00515 layers_.Add(filename); 00516 } 00517 00518 return 0; 00519 } 00520 00521 00522 //*** XML_Attribute *** 00523 00524 void Font::XML_Attribute(StringId _name, const XMLVariant& _value) 00525 { 00526 xmlCase(name) 00527 { 00528 name_=StringId(xmlValue); 00529 } 00530 00531 xmlCase(size) 00532 { 00533 size_=xmlValue; 00534 } 00535 00536 xmlCase(lineSpacing) 00537 { 00538 lineSpacing_=xmlValue; 00539 } 00540 } 00541 00542 00543 //*** ReadFromAsset *** 00544 00545 void Font::ReadFromAsset(const Asset* asset) 00546 { 00547 int nameLength=0; 00548 asset->Read(&nameLength); 00549 char* name=new char[nameLength+1]; 00550 asset->Read(name,nameLength); 00551 name[nameLength]=0; 00552 name_=StringId(name); 00553 delete name; 00554 asset->Read(&size_); 00555 asset->Read(&lineSpacing_); 00556 asset->Read(&layerCount_); 00557 int characterCount=0; 00558 asset->Read(&characterCount); 00559 00560 for (int i=0; i<characterCount; i++) 00561 { 00562 Character character; 00563 asset->Read(&character.ascii); 00564 asset->Read(&character.spacing); 00565 asset->Read(&character.x); 00566 asset->Read(&character.y); 00567 asset->Read(&character.width); 00568 asset->Read(&character.height); 00569 asset->Read(&character.xoffset); 00570 asset->Read(&character.yoffset); 00571 character.yoffset=-character.yoffset; 00572 asset->Read(&character.isBlank); 00573 00574 if (!character.isBlank) 00575 { 00576 for (int i=0; i<layerCount_; i++) 00577 { 00578 Bitmap* bitmap=new Bitmap_RLE8(); 00579 bitmap->ReadFromAsset(asset); 00580 character.layers.Add(bitmap); 00581 } 00582 } 00583 00584 if (character.ascii>=0 && character.ascii<=255) 00585 { 00586 characters_[character.ascii]=character; 00587 } 00588 } 00589 } 00590 00591 00592 //*** WriteToAsset *** 00593 00594 void Font::WriteToAsset(Asset* asset) 00595 { 00596 int nameLength=StrLen(name_.GetString()); 00597 asset->Write(&nameLength); 00598 asset->Write(name_.GetString(),nameLength); 00599 asset->Write(&size_); 00600 asset->Write(&lineSpacing_); 00601 asset->Write(&layerCount_); 00602 int characterCount=256; 00603 asset->Write(&characterCount); 00604 00605 for (int i=0; i<256; i++) 00606 { 00607 const Character& character=characters_[i]; 00608 asset->Write(&i); 00609 asset->Write(&character.spacing); 00610 asset->Write(&character.x); 00611 asset->Write(&character.y); 00612 asset->Write(&character.width); 00613 asset->Write(&character.height); 00614 asset->Write(&character.xoffset); 00615 asset->Write(&character.yoffset); 00616 asset->Write(&character.isBlank); 00617 00618 if (!character.isBlank) 00619 { 00620 for (int i=0; i<layerCount_; i++) 00621 { 00622 character.layers.Get(i)->WriteToAsset(asset); 00623 } 00624 } 00625 00626 } 00627 00628 } 00629 00630 00631 //*** ReadFromAssetNew *** 00632 00633 void Font::ReadFromAssetNew(const Asset* asset) 00634 { 00635 int nameLength=0; 00636 asset->Read(&nameLength); 00637 char* name=new char[nameLength+1]; 00638 asset->Read(name,nameLength); 00639 name[nameLength]=0; 00640 name_=StringId(name); 00641 delete name; 00642 asset->Read(&size_); 00643 asset->Read(&lineSpacing_); 00644 asset->Read(&baseline_); 00645 asset->Read(&layerCount_); 00646 int characterCount=0; 00647 asset->Read(&characterCount); 00648 00649 for (int i=0; i<characterCount; i++) 00650 { 00651 Character character; 00652 character.isBlank=false; 00653 asset->Read(&character.ascii); 00654 asset->Read(&character.spacing); 00655 asset->Read(&character.xoffset); 00656 asset->Read(&character.yoffset); 00657 00658 for (int i=0; i<layerCount_; i++) 00659 { 00660 Bitmap* bitmap=new Bitmap_RLE8(); 00661 bitmap->ReadFromAsset(asset); 00662 character.layers.Add(bitmap); 00663 } 00664 00665 if (character.ascii>=0 && character.ascii<=255) 00666 { 00667 characters_[character.ascii]=character; 00668 } 00669 } 00670 00671 int kerningCount=0; 00672 asset->Read(&kerningCount); 00673 00674 for (int i=0; i<kerningCount; i++) 00675 { 00676 Kerning kerning; 00677 asset->Read(&kerning.first); 00678 asset->Read(&kerning.second); 00679 asset->Read(&kerning.amount); 00680 00681 if (kerning.first>=0 && kerning.first<=255) 00682 { 00683 kerning_[kerning.first]=kerning; 00684 } 00685 } 00686 } 00687 00688
Reproduction/republishing of any material on this site without permission is strictly prohibited.
