wwfont.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /VSS_Sync/wwlib/wwfont.cpp $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 10/16/00 11:42a $*
  29. * *
  30. * $Revision:: 5 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * WWFontClass::Print -- Print text to the surface specified. *
  35. * WWFontClass::WWFontClass -- Constructor for a font class object. *
  36. * WWFontClass::Char_Pixel_Width -- Fetch the pixel width of the character specified. *
  37. * WWFontClass::String_Pixel_Width -- Determines the width of the string in pixels. *
  38. * WWFontClass::Raw_Width -- Fetch the raw width of a character. *
  39. * WWFontClass::Raw_Height -- Fetch the height of the font. *
  40. * WWFontClass::Get_Width -- Get normalized width of the nominal font character. *
  41. * WWFontClass::Get_Height -- Fetch the normalized height of the nominal font character. *
  42. * WWFontClass::Set_XSpacing -- Set the X spacing override value. *
  43. * WWFontClass::Set_YSpacing -- Set the vertical (Y) spacing override value. *
  44. * Set_Font_Data -- Allow font data to be set after construction. *
  45. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  46. #include "always.h"
  47. #include "_convert.h"
  48. #include "wwfont.h"
  49. //#include <stdlib.h>
  50. #define FONTINFOMAXHEIGHT 4
  51. #define FONTINFOMAXWIDTH 5
  52. #define FUDGEDIV 16
  53. /***********************************************************************************************
  54. * WWFontClass::WWFontClass -- Constructor for a font class object. *
  55. * *
  56. * This constructs a font object as it is based upon the font data output by the legacy *
  57. * FONTMAKE.EXE utility. *
  58. * *
  59. * INPUT: fontdata -- Pointer to the data as output by the fontmake utility. *
  60. * *
  61. * isoutlined -- Is this font data available with outline pixels embedded? *
  62. * *
  63. * shadow -- Does the font data have shadow pixels embedded? *
  64. * *
  65. * OUTPUT: none *
  66. * *
  67. * WARNINGS: none *
  68. * *
  69. * HISTORY: *
  70. * 05/26/1997 JLB : Created. *
  71. *=============================================================================================*/
  72. WWFontClass::WWFontClass(void const * fontdata, bool isoutlined, int shadow, ConvertClass *convert, unsigned char *remap) :
  73. IsOutlinedData(isoutlined),
  74. Shadow(shadow),
  75. Converter(convert),
  76. RemapPalette(remap),
  77. FontXSpacing(0),
  78. FontYSpacing(0)
  79. {
  80. Set_Font_Data(fontdata);
  81. }
  82. /***********************************************************************************************
  83. * Set_Font_Data -- Allow font data to be set after construction. *
  84. * *
  85. * INPUT: *
  86. * *
  87. * OUTPUT: *
  88. * *
  89. * WARNINGS: *
  90. * *
  91. * HISTORY: *
  92. * 01/24/2000 SKB : Created. *
  93. *=============================================================================================*/
  94. void *WWFontClass::Set_Font_Data(void const * fontdata)
  95. {
  96. void *old = (void *) FontData;
  97. FontData = (FontType *)fontdata;
  98. if (FontData) {
  99. Set_XSpacing(FontXSpacing);
  100. Set_YSpacing(FontYSpacing);
  101. }
  102. return(old);
  103. }
  104. /***********************************************************************************************
  105. * WWFontClass::Char_Pixel_Width -- Fetch the pixel width of the character specified. *
  106. * *
  107. * This will return with the pixel width of the character specified. *
  108. * *
  109. * INPUT: c -- The character to determine the pixel width for. *
  110. * *
  111. * OUTPUT: Returns with the pixel width of the character. *
  112. * *
  113. * WARNINGS: The return width is the screen real estate width which may differ from the *
  114. * actual pixels of the character. This difference is controlled by the font *
  115. * X spacing. *
  116. * *
  117. * HISTORY: *
  118. * 05/26/1997 JLB : Created. *
  119. *=============================================================================================*/
  120. int WWFontClass::Char_Pixel_Width(char c) const
  121. {
  122. int raw = (*(((unsigned char *)FontData) + FontData->WidthBlockOffset + (unsigned char)c));
  123. raw += FontXSpacing;
  124. return(raw);
  125. }
  126. /***********************************************************************************************
  127. * WWFontClass::String_Pixel_Width -- Determines the width of the string in pixels. *
  128. * *
  129. * This routine is used to determine how many pixels wide the string will be if it were *
  130. * printed. *
  131. * *
  132. * INPUT: string -- The string to convert into its pixel width. *
  133. * *
  134. * OUTPUT: Returns with the number of pixels the string would span if it were printed. *
  135. * *
  136. * WARNINGS: This routine does not take into account clipping. *
  137. * *
  138. * HISTORY: *
  139. * 05/26/1997 JLB : Created. *
  140. *=============================================================================================*/
  141. int WWFontClass::String_Pixel_Width(char const * string) const
  142. {
  143. if (string == NULL) return(0);
  144. if (string[0] == 0) return 0;
  145. int largest = 0; // Largest recorded width of the string.
  146. int width = 0;
  147. while (*string) {
  148. if (*string == '\r' || *string == '\n') {
  149. string++;
  150. largest = MAX(largest, width);
  151. width = 0;
  152. } else {
  153. width += Char_Pixel_Width(*string++); // add each char's width
  154. }
  155. }
  156. largest = MAX(largest, width);
  157. return(largest);
  158. }
  159. /***********************************************************************************************
  160. * WWFontClass::Raw_Width -- Fetch the raw width of a character. *
  161. * *
  162. * This routine returns the nominal width of the font. This width is basically the width of *
  163. * the widest character in the font. *
  164. * *
  165. * INPUT: none *
  166. * *
  167. * OUTPUT: Returns with the width of the widest character in the font. *
  168. * *
  169. * WARNINGS: none *
  170. * *
  171. * HISTORY: *
  172. * 05/26/1997 JLB : Created. *
  173. *=============================================================================================*/
  174. int WWFontClass::Raw_Width(void) const
  175. {
  176. return(*(((unsigned char *)FontData) + FontData->InfoBlockOffset + FONTINFOMAXWIDTH));
  177. }
  178. /***********************************************************************************************
  179. * WWFontClass::Raw_Height -- Fetch the height of the font. *
  180. * *
  181. * This returns the height of the font without regard for any Y spacing offsets. *
  182. * *
  183. * INPUT: none *
  184. * *
  185. * OUTPUT: Returns with the height of the font. *
  186. * *
  187. * WARNINGS: All characters in the font have the same logical height even if they actually *
  188. * consume less pixels. *
  189. * *
  190. * HISTORY: *
  191. * 05/26/1997 JLB : Created. *
  192. *=============================================================================================*/
  193. int WWFontClass::Raw_Height(void) const
  194. {
  195. return(*(((unsigned char *)FontData) + FontData->InfoBlockOffset + FONTINFOMAXHEIGHT));
  196. }
  197. /***********************************************************************************************
  198. * WWFontClass::Get_Width -- Get normalized width of the nominal font character. *
  199. * *
  200. * This routine is used to fetch the width of the widest character in the font but the *
  201. * width has been biased according to any X spacing override present. *
  202. * *
  203. * INPUT: none *
  204. * *
  205. * OUTPUT: Returns with the normalized width of the widest character in the font. *
  206. * *
  207. * WARNINGS: none *
  208. * *
  209. * HISTORY: *
  210. * 05/26/1997 JLB : Created. *
  211. *=============================================================================================*/
  212. int WWFontClass::Get_Width(void) const
  213. {
  214. return(Raw_Width() + ((FontXSpacing > 0) ? FontXSpacing : 0));
  215. }
  216. /***********************************************************************************************
  217. * WWFontClass::Get_Height -- Fetch the normalized height of the nominal font character. *
  218. * *
  219. * This will return the height of the font but the returned height will be adjusted by any *
  220. * Y spacing override present. *
  221. * *
  222. * INPUT: none *
  223. * *
  224. * OUTPUT: Returns with the height of the font normalized by any spacing overrides. *
  225. * *
  226. * WARNINGS: none *
  227. * *
  228. * HISTORY: *
  229. * 05/26/1997 JLB : Created. *
  230. *=============================================================================================*/
  231. int WWFontClass::Get_Height(void) const
  232. {
  233. return(Raw_Height() + ((FontYSpacing > 0) ? FontYSpacing : 0));
  234. }
  235. /***********************************************************************************************
  236. * WWFontClass::Set_XSpacing -- Set the X spacing override value. *
  237. * *
  238. * Use this routine to control the horizontal spacing override for this font. If the value *
  239. * is negative, the font becomes compressed. If the value is positive, then the font *
  240. * becomes expanded. *
  241. * *
  242. * INPUT: x -- The X spacing override to use for this font. *
  243. * *
  244. * OUTPUT: Returns with the old X spacing override value. *
  245. * *
  246. * WARNINGS: none *
  247. * *
  248. * HISTORY: *
  249. * 05/26/1997 JLB : Created. *
  250. *=============================================================================================*/
  251. int WWFontClass::Set_XSpacing(int x)
  252. {
  253. int old = FontXSpacing;
  254. FontXSpacing = x;
  255. if (IsOutlinedData) {
  256. switch (Shadow) {
  257. case 0:
  258. FontXSpacing += -2;
  259. break;
  260. case 1:
  261. FontXSpacing += -1;
  262. break;
  263. case 2:
  264. FontXSpacing += -1;
  265. break;
  266. }
  267. }
  268. FontXSpacing += Get_Width() / FUDGEDIV;
  269. return(old);
  270. }
  271. /***********************************************************************************************
  272. * WWFontClass::Set_YSpacing -- Set the vertical (Y) spacing override value. *
  273. * *
  274. * Use this routine to control the "line spacing" of a font. If the Y spacing is negative *
  275. * then the font becomes closer to the line above it. If value is positive, then more *
  276. * space occurs between lines. *
  277. * *
  278. * INPUT: y -- The Y spacing override to use for this font. *
  279. * *
  280. * OUTPUT: Returns with the old Y spacing override value. *
  281. * *
  282. * WARNINGS: none *
  283. * *
  284. * HISTORY: *
  285. * 05/26/1997 JLB : Created. *
  286. *=============================================================================================*/
  287. int WWFontClass::Set_YSpacing(int y)
  288. {
  289. int old = FontYSpacing;
  290. FontYSpacing = y;
  291. if (IsOutlinedData) {
  292. switch (Shadow) {
  293. case 0:
  294. FontYSpacing += -2;
  295. break;
  296. case 1:
  297. FontYSpacing += -1;
  298. break;
  299. case 2:
  300. FontYSpacing += -1;
  301. break;
  302. }
  303. }
  304. FontYSpacing += Get_Height() / FUDGEDIV;
  305. return(old);
  306. }
  307. /***********************************************************************************************
  308. * WWFontClass::Print -- Print text to the surface specified. *
  309. * *
  310. * This displays text to the surface specified and with the attributes specified. *
  311. * *
  312. * INPUT: string -- The string to display to the surface. *
  313. * *
  314. * surface -- The surface to display the text upon. *
  315. * *
  316. * cliprect -- The clipping rectangle that both clips the text and biases the print *
  317. * location to. *
  318. * *
  319. * point -- The draw position for the upper left corner of the first character. *
  320. * *
  321. * convert -- The pixel convert object that is used to draw the correct colors to *
  322. * the destination surface. *
  323. * *
  324. * remap -- Auxiliary remap table for font colors. *
  325. * *
  326. * OUTPUT: Returns with the point where the next print should begin if it is to smoothly *
  327. * continue where this print operation left off. *
  328. * *
  329. * WARNINGS: There are two separate drawing routines; one for old fonts and one for new *
  330. * fonts. *
  331. * *
  332. * HISTORY: *
  333. * 05/26/1997 JLB : Created. *
  334. * 06/20/1887 BNA : Modified to handle new fonts. *
  335. * 01/24/2000 SKB : Updated from C&C to include BNA code. *
  336. * 01/24/2000 SKB : put in call for Get_Remap_Palette *
  337. * 01/24/2000 SKB : Put in call for get converer. *
  338. *=============================================================================================*/
  339. Point2D WWFontClass::Print(char const * string, Surface & surface, Rect const & cliprect, Point2D const & drawpoint, ConvertClass const & convertref, unsigned char const * remap) const
  340. {
  341. if (string == NULL) return(drawpoint);
  342. /*
  343. ** Compute the surface relative coordinate for the print position.
  344. */
  345. Point2D point = drawpoint;
  346. int xpos = point.Bias_To(cliprect).X;
  347. // int xpos = point.X + cliprect.X;
  348. int ypos = point.Bias_To(cliprect).Y;
  349. // int ypos = point.Y + cliprect.Y;
  350. int xspacing = FontXSpacing + Raw_Width()/FUDGEDIV;
  351. int yspacing = FontYSpacing + Raw_Width()/FUDGEDIV;
  352. // This font palette assumes that the font will be used as defined by converter.
  353. static unsigned char const fontpalette[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
  354. if (RemapPalette) {
  355. remap = RemapPalette;
  356. } else if (!remap) {
  357. remap = &fontpalette[0];
  358. }
  359. // If there is a convert supplied with the font, use it as priority.
  360. ConvertClass const *converter = Converter;
  361. if (!converter) {
  362. converter = &convertref;
  363. }
  364. /*
  365. ** Verify that the clipping rectangle (if present) falls within the bounds of the surface.
  366. */
  367. // Rect cliprect = surface->Get_Rect();
  368. // cliprect.X = 0;
  369. // cliprect.Y = 0;
  370. /*
  371. ** Trivially check to see if the print start position is outside the bounds of the clipping
  372. ** rectangle.
  373. */
  374. if (xpos >= cliprect.X+cliprect.Width || ypos >= cliprect.Y+cliprect.Height) {
  375. return(drawpoint);
  376. }
  377. /*
  378. ** Check to see if access to the surface buffer is possible.
  379. */
  380. void * buffer = surface.Lock();
  381. if (buffer != NULL) {
  382. int startx = xpos;
  383. unsigned char * fontwidth = ((unsigned char*)FontData) + FontData->WidthBlockOffset;
  384. unsigned short * fontheight = (unsigned short*)(((unsigned char*)FontData) + FontData->HeightOffset);
  385. unsigned short * fontoffset = (unsigned short*)(((unsigned char*)FontData) + FontData->OffsetBlockOffset);
  386. int bbp = surface.Bytes_Per_Pixel();
  387. /*
  388. ** Process the whole string. Stop when the string reaches the right margin.
  389. */
  390. while (*string != '\0') {
  391. unsigned char c = *string++;
  392. /*
  393. ** Certain control characters serve a formatting purpose. They merely
  394. ** adjust the next draw position.
  395. */
  396. if (c == '\r') {
  397. xpos = startx;
  398. ypos += Raw_Height() + ((yspacing > 0) ? yspacing : 0);
  399. continue;
  400. }
  401. if (c == '\n') {
  402. xpos = cliprect.X;
  403. ypos += Raw_Height() + ((yspacing > 0) ? yspacing : 0);
  404. continue;
  405. }
  406. /*
  407. ** Fetch working values for the character to display. These are used to
  408. ** control the size of the character rectangle.
  409. */
  410. int width = fontwidth[c];
  411. int dheight = fontheight[c] >> 8;
  412. int firstrow = fontheight[c] & 0xFF;
  413. // int height = dheight+firstrow;
  414. /*
  415. ** Build the character rectangle (surface relative coordinates).
  416. */
  417. Rect crect(xpos, ypos, width+((xspacing > 0) ? xspacing : 0), *(((unsigned char *)FontData) + FontData->InfoBlockOffset + FONTINFOMAXHEIGHT) + ((yspacing > 0) ? yspacing : 0));
  418. /*
  419. ** Check to see if any part of this character would appear within the clipping
  420. ** rectangle. If not, then don't process this character.
  421. */
  422. crect = crect.Intersect(cliprect);
  423. if (crect.Is_Valid()) {
  424. /*
  425. ** Fill the background of the character if the background
  426. ** color is not transparent.
  427. */
  428. if (remap[0] != 0) {
  429. surface.Fill_Rect(crect, converter->Convert_Pixel(remap[0]));
  430. }
  431. /*
  432. ** Loop through all data rows of this character and output the row
  433. ** data with clipping.
  434. */
  435. if (FontData->FontCompress != (char) 2) { // if the font is the old style
  436. unsigned char * dataptr = ((unsigned char *)FontData) + fontoffset[c];
  437. void * drawbuff = (void*)(((char*)buffer) + ((ypos + firstrow) * surface.Stride()) + xpos * bbp);
  438. for (int h = 0; h < dheight; h++) {
  439. /*
  440. ** If the current row to be drawn falls below the clipping rectangle, then
  441. ** no further drawing for this character is needed -- bail out.
  442. */
  443. if (ypos + firstrow + h >= crect.Y + crect.Height) break;
  444. /*
  445. ** If the current row to be drawn falls above the clipping rectangle,
  446. ** then skip the row and advance the source data pointer as well.
  447. */
  448. if (ypos + firstrow + h < crect.Y) {
  449. drawbuff = (void*)(((char*)drawbuff) + surface.Stride());
  450. dataptr = dataptr + ((width+1)/2);
  451. } else {
  452. /*
  453. ** Process one row of character data. For simplicity reasons, just
  454. ** loop through all pixels of this row and perform clipping at the
  455. ** pixel level.
  456. */
  457. int dx = xpos;
  458. int workwidth = width;
  459. while (workwidth > 0) {
  460. /*
  461. ** Fetch the next two pixel values. Two pixel values must
  462. ** be fetched at the same time since they are nibble packed.
  463. */
  464. int c1 = remap[*dataptr & 0x0F];
  465. int c2 = remap[(*dataptr++ & 0xF0) >> 4];
  466. /*
  467. ** Draw the first pixel if it falls within the clipping
  468. ** rectangle and is not transparent.
  469. */
  470. if (dx >= cliprect.X && dx < cliprect.X+cliprect.Width) {
  471. if (c1 != 0) {
  472. if (bbp == 2) {
  473. *(short *)drawbuff = (short)converter->Convert_Pixel(c1);
  474. } else {
  475. *(char *)drawbuff = (char)converter->Convert_Pixel(c1);
  476. }
  477. }
  478. }
  479. dx += 1;
  480. drawbuff = ((char*)drawbuff) + bbp;
  481. workwidth -= 1;
  482. if (workwidth == 0) break;
  483. /*
  484. ** Draw the second pixel if it falls within the clipping
  485. ** rectangle and is not transparent.
  486. */
  487. if (dx >= cliprect.X && dx < cliprect.X+cliprect.Width) {
  488. if (c2 != 0) {
  489. if (bbp == 2) {
  490. *(short *)drawbuff = (short)converter->Convert_Pixel(c2);
  491. } else {
  492. *(char *)drawbuff = (char)converter->Convert_Pixel(c2);
  493. }
  494. }
  495. }
  496. dx += 1;
  497. drawbuff = ((char*)drawbuff) + bbp;
  498. workwidth -= 1;
  499. }
  500. /*
  501. ** Move the output pixel pointer to the next line down but at the
  502. ** left margin of the character block.
  503. */
  504. drawbuff = (void*)((((char*)drawbuff) - (width*bbp)) + surface.Stride());
  505. }
  506. }
  507. } else {
  508. // the font is of the new type
  509. unsigned char * dataptr = ((unsigned char *)FontData) + fontoffset[c] + FontData->DataBlockOffset;
  510. void * drawbuff = (void*)(((char*)buffer) + ((ypos + firstrow) * surface.Stride()) + xpos * bbp);
  511. for (int h = 0; h < dheight; h++) {
  512. /*
  513. ** If the current row to be drawn falls below the clipping rectangle, then
  514. ** no further drawing for this character is needed -- bail out.
  515. */
  516. if (ypos + firstrow + h >= crect.Y + crect.Height) break;
  517. /*
  518. ** If the current row to be drawn falls above the clipping rectangle,
  519. ** then skip the row and advance the source data pointer as well.
  520. */
  521. if (ypos + firstrow + h < crect.Y) {
  522. drawbuff = (void*)(((char*)drawbuff) + surface.Stride());
  523. dataptr = dataptr + width;
  524. } else {
  525. /*
  526. ** Process one row of character data. For simplicity reasons, just
  527. ** loop through all pixels of this row and perform clipping at the
  528. ** pixel level.
  529. */
  530. int dx = xpos;
  531. int workwidth = width;
  532. while (workwidth > 0) {
  533. /*
  534. ** Fetch the next pixel value.
  535. */
  536. int c1 = remap[*dataptr++]; // no remapping
  537. /*
  538. ** Draw the pixel if it falls within the clipping
  539. ** rectangle and is not transparent.
  540. */
  541. if (dx >= cliprect.X && dx < cliprect.X+cliprect.Width) {
  542. if (c1 != 0) {
  543. if (bbp == 2) {
  544. *(short *)drawbuff = (short)converter->Convert_Pixel(c1);
  545. } else {
  546. *(char *)drawbuff = (char)converter->Convert_Pixel(c1);
  547. }
  548. }
  549. }
  550. dx += 1;
  551. drawbuff = ((char*)drawbuff) + bbp;
  552. workwidth -= 1;
  553. }
  554. /*
  555. ** Move the output pixel pointer to the next line down but at the
  556. ** left margin of the character block.
  557. */
  558. drawbuff = (void*)((((char*)drawbuff) - (width*bbp)) + surface.Stride());
  559. }
  560. }
  561. }
  562. }
  563. xpos += Char_Pixel_Width(c);
  564. // xpos += width + xspacing;
  565. }
  566. point = Point2D(xpos - cliprect.X, ypos - cliprect.Y);
  567. surface.Unlock();
  568. }
  569. return(point);
  570. }