CFNT.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // This is the file to deal with the CFNT, which is like
  19. // the CAnim of text. It is currently designed for FSPR1 images,
  20. // but it could very easily be updated for TC use and any
  21. // image type.
  22. #include <string.h>
  23. #ifdef PATHS_IN_INCLUDES
  24. #include "GREEN/BLiT/BLIT.H"
  25. #include "GREEN/BLiT/_BlitInt.H"
  26. #else
  27. #include "BLIT.H"
  28. #include "_BlitInt.H"
  29. #endif
  30. #include "Cfnt.h"
  31. //========================================================
  32. RFont::RFont()
  33. {
  34. m_pFontSets = NULL;
  35. m_sMaxCellHeight = m_sMaxCellWidth = m_sNumberOfScales = 0;
  36. }
  37. void RFont::EraseAll()
  38. {
  39. RFontSet *pfsn,*pfs = m_pFontSets;
  40. while (pfs)
  41. {
  42. pfsn = pfs->m_pNext;
  43. delete pfs;
  44. pfs = pfsn;
  45. }
  46. m_sMaxCellHeight = m_sMaxCellWidth = m_sNumberOfScales = 0;
  47. }
  48. RFont::~RFont()
  49. {
  50. EraseAll();
  51. }
  52. //========================================================
  53. short RFont::Add(char* pszFileName)
  54. {
  55. RFile rfTemp;
  56. if (rfTemp.Open(pszFileName,"rb",RFile::LittleEndian/*,RFile::Ascii*/))
  57. {
  58. TRACE("RFont::AddFont: Couldn't open %s\n",pszFileName);
  59. return -1;
  60. }
  61. Add(&rfTemp);
  62. rfTemp.Close();
  63. return 0;
  64. }
  65. short RFont::Add(RFile* pcf)
  66. {
  67. #ifdef _DEBUG
  68. if (!pcf)
  69. {
  70. TRACE("RFont::AddFont:null CNFile passed.\n");
  71. return -1;
  72. }
  73. #endif
  74. char szCommand[256];
  75. // Read the basic header and verify
  76. pcf->Read(szCommand);
  77. if (strcmp(szCommand,"FONTFILE"))
  78. {
  79. TRACE("RFont::AddFont:Not a valid font file.\n");
  80. return -1;
  81. }
  82. short sVersion;
  83. pcf->Read(&sVersion);
  84. if (sVersion != 8)
  85. {
  86. TRACE("RFont::AddFont:Wrong version of font file!\n");
  87. return -1;
  88. }
  89. short sW,sH,sN;
  90. pcf->Read(&sH);
  91. pcf->Read(&sW);
  92. pcf->Read(&sN);
  93. TRACE("Loading Font, %hd by %hd, %hd scales\n",sW,sH,sN);
  94. short sDone = FALSE;
  95. while (!sDone)
  96. {
  97. pcf->Read(szCommand);
  98. if (!strcmp(szCommand,"ENDFONT"))
  99. {
  100. sDone = TRUE;
  101. break;
  102. }
  103. if (!strcmp(szCommand,"FONTSET"))
  104. {
  105. short sH,sW;
  106. pcf->Read(&sH);
  107. pcf->Read(&sW);
  108. TRACE("FontSet: %hd by %hd\n",sW,sH);
  109. continue;
  110. }
  111. if (!strcmp(szCommand,"LETTER_"))
  112. {
  113. UCHAR ucASCII;
  114. RImage* pim = new RImage;
  115. pcf->Read(&ucASCII);
  116. pim->Load(pcf);
  117. AddLetter(pim,(short)ucASCII);
  118. long lBogus = pcf->Tell();
  119. }
  120. }
  121. return 0;
  122. }
  123. // For FSPR1, you don't need the parameters
  124. // Will return a +1 if overwriting an old letter!
  125. //
  126. short RFont::AddLetter(RImage* pimLetter,short sASCII,
  127. short sKernL,short sKernR)
  128. {
  129. #ifdef _DEBUG
  130. if (!pimLetter)
  131. {
  132. TRACE("RFont::AddLetter: null image!\n");
  133. return -1;
  134. }
  135. #endif
  136. // First find if a font exists:
  137. RFontSet* pFont = m_pFontSets;
  138. RSpecialFSPR1* pInfo = NULL;
  139. // try to handle a generic type efficiently:
  140. if (pimLetter->m_type == RImage::FSPR1)
  141. {
  142. pInfo = (RSpecialFSPR1*)pimLetter->m_pSpecialMem;
  143. if (!pInfo)
  144. {
  145. TRACE("RFont::AddLetter: Bad FSPR1 format!\n");
  146. return -1;
  147. }
  148. if (sASCII != -1) // FSPR1 case only
  149. {
  150. pInfo->m_u16ASCII = sASCII; // translate it...
  151. }
  152. }
  153. while (pFont)
  154. {
  155. if (pFont->m_sCellHeight == pimLetter->m_sHeight) break;
  156. pFont = pFont->m_pNext;
  157. }
  158. if (!pFont) // no match exists -> make a new font set..
  159. {
  160. pFont = new RFontSet;
  161. if (!pFont)
  162. {
  163. TRACE("RFont::AddLetter: Memory alloc error!\n");
  164. return -1;
  165. }
  166. pFont->m_sCellHeight = pimLetter->m_sHeight;
  167. pFont->m_sMaxWidth = pimLetter->m_sWidth;
  168. // Insert into the list so that it's smallest to largest:
  169. RFontSet* pInsertFont = m_pFontSets;
  170. m_sNumberOfScales++;
  171. if (!pInsertFont) m_pFontSets = pFont; // first one
  172. else
  173. {
  174. RFontSet* pLastFont = pInsertFont;
  175. while (pInsertFont)
  176. {
  177. if (pInsertFont->m_sCellHeight < pFont->m_sCellHeight)
  178. {
  179. pLastFont = pInsertFont; // save last position
  180. pInsertFont = pInsertFont->m_pNext; // keep looking
  181. if (pInsertFont) continue;
  182. // insert it at the end:
  183. pLastFont->m_pNext = pFont;
  184. }
  185. // insert before!
  186. pFont->m_pNext = pInsertFont; // stick before...
  187. if (pInsertFont == m_pFontSets) // insert head
  188. m_pFontSets = pFont;
  189. else // link to previous;
  190. pLastFont->m_pNext = pFont;
  191. break;
  192. }
  193. }
  194. }
  195. // Insert it into the font set:
  196. short sRet = 0;
  197. if (pFont->m_ppimCharacters[pInfo->m_u16ASCII])
  198. {
  199. //TRACE("RFont::AddLetter: WARNING! Overwriting old letter!\n");
  200. sRet = 1;
  201. delete pFont->m_ppimCharacters[pInfo->m_u16ASCII];
  202. }
  203. pFont->m_ppimCharacters[pInfo->m_u16ASCII] = pimLetter;
  204. //=====================================================
  205. // Update Font Set parameters
  206. //
  207. if (pimLetter->m_sWidth > pFont->m_sMaxWidth)
  208. pFont->m_sMaxWidth = pimLetter->m_sWidth;
  209. // (All fonts in the font set by DEFINITION have the same
  210. // height)
  211. //=====================================================
  212. // Update global font parameters:
  213. //
  214. if (pimLetter->m_sWidth > m_sMaxCellWidth)
  215. m_sMaxCellWidth = pimLetter->m_sWidth;
  216. if (pimLetter->m_sHeight > m_sMaxCellHeight)
  217. m_sMaxCellHeight = pimLetter->m_sHeight;
  218. return sRet;
  219. }
  220. short RFont::Save(char* pszFileName)
  221. {
  222. RFile rfTemp;
  223. if (rfTemp.Open(pszFileName,"wb",RFile::LittleEndian/*,RFile::Ascii*/))
  224. {
  225. TRACE("RFont::SaveFont: Couldn't open %s\n",pszFileName);
  226. return -1;
  227. }
  228. if (Save(&rfTemp)==0)
  229. {
  230. TRACE("RFont::SaveFont: %s saved!\n",pszFileName);
  231. }
  232. rfTemp.Close();
  233. return 0;
  234. }
  235. // THIS is the font we are loading!
  236. //
  237. short RFont::Load(char* pszFileName)
  238. {
  239. RFile* pfileTemp = new RFile;
  240. if (pfileTemp->Open(pszFileName,"rb",RFile::LittleEndian/*,RFile::Ascii*/))
  241. {
  242. TRACE("RFont::LoadFont: Couldn't open %s\n",pszFileName);
  243. delete pfileTemp;
  244. return -1;
  245. }
  246. if (Load(pfileTemp) == 0)
  247. {
  248. // TRACE("RFont::LoadFont: %s loaded!\n",pszFileName);
  249. pfileTemp->Close();
  250. delete pfileTemp;
  251. return 0;
  252. }
  253. pfileTemp->Close();
  254. delete pfileTemp;
  255. return -1;
  256. }
  257. short RFont::Save(RFile* pcf)
  258. {
  259. #ifdef _DEBUG
  260. if (!pcf)
  261. {
  262. TRACE("RFont::SaveFont:Null Font passed!\n");
  263. return -1;
  264. }
  265. #endif
  266. // Write the basic header
  267. pcf->Write("FONTFILE"); // type
  268. short sVersion = 8;
  269. pcf->Write(&sVersion);
  270. // Write overall font info..
  271. pcf->Write(&m_sMaxCellHeight);
  272. pcf->Write(&m_sMaxCellWidth);
  273. pcf->Write(&m_sNumberOfScales);
  274. // Save each font set:
  275. RFontSet* pfs = m_pFontSets;
  276. while (pfs)
  277. {
  278. pcf->Write("FONTSET");
  279. // Write overall font set info..
  280. pcf->Write(&pfs->m_sCellHeight);
  281. pcf->Write(&pfs->m_sMaxWidth);
  282. for (short i=0;i<256;i++)
  283. {
  284. if (pfs->m_ppimCharacters[i])
  285. {
  286. pcf->Write("LETTER_");
  287. pcf->Write((UCHAR*)&i);
  288. pfs->m_ppimCharacters[i]->Save(pcf);
  289. }
  290. }
  291. pfs = pfs->m_pNext;
  292. }
  293. pcf->Write("ENDFONT");
  294. return 0;
  295. }
  296. // We are in a RFont, so it should exits...
  297. //
  298. short RFont::Load(RFile* pcf)
  299. {
  300. #ifdef _DEBUG
  301. if (!pcf)
  302. {
  303. TRACE("RFont::LoadFont:Null File passed!\n");
  304. return -1;
  305. }
  306. #endif
  307. char string[20] = {0,};
  308. //------------------------------
  309. // Read the basic header
  310. //------------------------------
  311. pcf->Read(&string[0],9);
  312. if (strcmp(&string[0],"FONTFILE")) // not equal
  313. {
  314. TRACE("RFont::Load: Bad font file!\n");
  315. return -1;
  316. }; // type
  317. short sVersion;
  318. pcf->Read(&sVersion);
  319. if (sVersion != 8)
  320. {
  321. TRACE("RFont::Load: This version not supported\n");
  322. return -1;
  323. }
  324. //------------------------------
  325. // Write overall font info..
  326. //------------------------------
  327. pcf->Read(&m_sMaxCellHeight);
  328. pcf->Read(&m_sMaxCellWidth);
  329. pcf->Read(&m_sNumberOfScales);
  330. m_sNumberOfScales = 0; // This will be recreated!
  331. short sDummy = 0; // we don't need this info!
  332. // Load & Instantiate each font set by adding letters:
  333. while (!pcf->IsEOF())
  334. {
  335. pcf->Read(&string[0]);
  336. if (!strcmp(&string[0],"FONTSET")) // equal
  337. {
  338. // Don't need overall font set info..
  339. pcf->Read(&sDummy);
  340. pcf->Read(&sDummy);
  341. }
  342. else if (!strcmp(&string[0],"LETTER_")) // equal
  343. {
  344. UCHAR c;
  345. pcf->Read((UCHAR*)&c);
  346. RImage* pimLetter = new RImage;
  347. pimLetter->Load(pcf);
  348. if (pimLetter == NULL)
  349. {
  350. TRACE("RFont::Load: Bad Letter %c in file!\n",char(c));
  351. }
  352. else
  353. AddLetter(pimLetter); // create the font!
  354. }
  355. else if (!strcmp(&string[0],"ENDFONT")) break; // equal
  356. else
  357. {
  358. TRACE("RFont::Load: Bad font file!\n");
  359. return -1;
  360. }
  361. }
  362. return 0;
  363. }
  364. // This selects the cached font closest in size to
  365. // your request that is greater than or equal to the
  366. // requested font height. This does NOT guarantee that
  367. // your character exists in a given font size. A letter
  368. // based font search may be implemented later.
  369. //
  370. // It returns null if no cached font was found larger than
  371. // the request size.
  372. //
  373. RFont::RFontSet* RFont::FindSize(short sCellH,double *pdScale)
  374. {
  375. RFontSet* pFont = NULL;
  376. RFontSet* pfntRet = NULL;
  377. *pdScale = 0.0;
  378. // Assumes fonts are stored largest first.
  379. if (m_pFontSets == NULL)
  380. {
  381. TRACE("RFont::FindSize: No fonts cached!\n");
  382. return NULL;
  383. }
  384. pFont = m_pFontSets;
  385. // Assume font's are ordered smallest to biggest:
  386. while ((pFont->m_sCellHeight < sCellH))
  387. {
  388. pFont = pFont->m_pNext;
  389. if (!pFont) break;
  390. }
  391. pfntRet = pFont;
  392. if (pfntRet) *pdScale = double(sCellH)/pfntRet->m_sCellHeight;
  393. return pfntRet;
  394. }
  395. // This allows an editor to remove vertain FontSets out of a
  396. // loaded font. It will NOT allow you to delete the final
  397. // fontset, which would leave a degenerate font. You supply
  398. // the fontset to remove. It returns SUCCESS or FAILURE.
  399. //
  400. short RFont::DeleteSet(RFontSet* pRemove)
  401. {
  402. RFontSet* pFont = m_pFontSets;
  403. // Must not degenerate the font:
  404. if (m_sNumberOfScales < 2) return FAILURE;
  405. // Find a match:
  406. short sMatch = FALSE;
  407. RFontSet* pPrevFont = NULL;
  408. while (pFont)
  409. {
  410. if (pFont == pRemove)
  411. {
  412. sMatch = TRUE;
  413. break;
  414. }
  415. pPrevFont = pFont;
  416. pFont = pFont->m_pNext;
  417. }
  418. if (!sMatch) return FAILURE;
  419. // Found a match:
  420. // Handle special cases:
  421. if (!pRemove->m_pNext)
  422. {
  423. // remove the tail
  424. pPrevFont->m_pNext = NULL;
  425. m_sMaxCellHeight = pPrevFont->m_sCellHeight;
  426. m_sMaxCellWidth = pPrevFont->m_sMaxWidth;
  427. }
  428. else if (!pPrevFont)
  429. {
  430. // remove the head
  431. m_pFontSets = pRemove->m_pNext;
  432. }
  433. else
  434. {
  435. // remove from center.
  436. pPrevFont->m_pNext = pRemove->m_pNext;
  437. }
  438. m_sNumberOfScales--;
  439. delete pRemove;
  440. return SUCCESS;
  441. }
  442. //========================================================
  443. RFont::RFontSet::RFontSet()
  444. {
  445. m_sMaxWidth = m_sCellHeight = 0;
  446. m_pNext = NULL;
  447. m_ppimCharacters = (RImage**) calloc(256,sizeof(RImage*));
  448. }
  449. RFont::RFontSet::~RFontSet()
  450. {
  451. short i;
  452. for (i=0;i<256;i++) if(m_ppimCharacters[i])
  453. delete m_ppimCharacters[i];
  454. m_sMaxWidth = m_sCellHeight = 0;
  455. m_pNext = NULL;
  456. free(m_ppimCharacters);
  457. }
  458. //========================================================