font3d.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando / G 3D Library *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/font3d.cpp $*
  25. * *
  26. * $Author:: Jani_p $*
  27. * *
  28. * $Modtime:: 4/11/01 10:17p $*
  29. * *
  30. * $Revision:: 16 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "font3d.h"
  36. #include "assetmgr.h"
  37. #include "texture.h"
  38. #include <assert.h>
  39. #include <wwdebug.h>
  40. #include "surfaceclass.h"
  41. #include "texture.h"
  42. #include "vector2i.h"
  43. static SurfaceClass *_surface;
  44. /***********************************************************************************************
  45. * *
  46. * Font3DDataClass::Font3DDataClass -- constructor *
  47. * *
  48. * Constructs and load a Targa font image to create a texture matetial *
  49. * *
  50. ***********************************************************************************************/
  51. Font3DDataClass::Font3DDataClass( const char *filename )
  52. {
  53. Texture = NULL;
  54. Load_Font_Image( filename);
  55. Name = strdup( filename);
  56. Name = strupr( Name);
  57. }
  58. /***********************************************************************************************
  59. * *
  60. * Font3DDataClass::~Font3DDataClass -- destructor *
  61. * *
  62. ***********************************************************************************************/
  63. Font3DDataClass::~Font3DDataClass(void)
  64. {
  65. if (Name != NULL) {
  66. free(Name);
  67. Name = NULL;
  68. }
  69. REF_PTR_RELEASE(Texture);
  70. }
  71. /***********************************************************************************************
  72. * *
  73. * FontClass::Minimize_Font_Image *
  74. * *
  75. * Rebuilds the give image to better pack characters and to insure a square power of two size *
  76. * Must be called AFTER Make_Proportional() so each chars minimal bounding box is known *
  77. * Will only create a new texture of size 128x128 or 256x256, dependent on original width *
  78. * *
  79. ***********************************************************************************************/
  80. SurfaceClass *Font3DDataClass::Minimize_Font_Image( SurfaceClass *surface )
  81. {
  82. SurfaceClass::SurfaceDescription sd;
  83. surface->Get_Description(sd);
  84. float current_width = sd.Width;
  85. float current_height = sd.Height;
  86. // determine new width make the size of the new image either 128x128 or 256x256,
  87. // dependent on the width of the original image
  88. int new_width;
  89. if (current_width < 256) {
  90. new_width = 128;
  91. } else {
  92. new_width = 256;
  93. }
  94. int new_height = new_width;
  95. // create a new 4 bit alpha image to build into
  96. // We dont support non-homogeneous copies just yet
  97. SurfaceClass *new_surface = NEW_REF(SurfaceClass,(new_width, new_height,WW3D_FORMAT_A4R4G4B4));
  98. //SurfaceClass *new_surface0 = NEW_REF(SurfaceClass,(new_width, new_height,sd.Format));
  99. // fill with transparent black
  100. new_surface->Clear();
  101. // indices for the location of each added char
  102. int new_x = 0;
  103. int new_y = 0;
  104. // for each character, copy minimum bounding area to (new_x, new_y) in the new image
  105. for (int char_index = 0; char_index < 256; char_index++) {
  106. // find the lop left coordinate and the height and width of the char's bounding box
  107. // (must convert the normalized uv tables to pixels and round off)
  108. int src_x = (int)(UOffsetTable[ char_index ] * current_width + 0.5);
  109. int src_y = (int)(VOffsetTable[ char_index ] * current_height + 0.5);
  110. int width = (int)(UWidthTable[ char_index ] * current_width + 0.5);
  111. int height = (int)(VHeight * current_height + 0.5);
  112. // if the character has any visible pixels at all...
  113. if (width != 0) {
  114. // if this charactger will not fit on the current line, goto the next line
  115. if (new_x + width > new_width) {
  116. new_x = 0;
  117. new_y += height;
  118. // if we have run out of lines, we have a problem
  119. // we assert because we have already modified tables for some of the chars
  120. if (new_y + height > new_height) {
  121. new_y -= height;
  122. WWDEBUG_SAY(( "Font doesn't fit texture 2 on char %c\n", char_index ));
  123. }
  124. }
  125. // blit from original image to new image
  126. new_surface->Copy(new_x, new_y,src_x,src_y,width,height,surface);
  127. }
  128. // update the U and V tables to show new character location
  129. UOffsetTable[ char_index ] = (float)(new_x) / (float)new_width;
  130. VOffsetTable[ char_index ] = (float)(new_y) / (float)new_width;
  131. // update width in terms of new normal image width
  132. UWidthTable[ char_index ] *= (float)current_width / (float)new_width;
  133. new_x += width;
  134. }
  135. // update height in terms of new normal image height
  136. VHeight *= (float)current_height / (float)new_height;
  137. // be sure the new image is SMALLER than the old image
  138. // assert ( (new_width * new_height) <= (current_width * current_height));
  139. // release the old surface and return the new one
  140. REF_PTR_RELEASE(surface);
  141. _surface = new_surface;
  142. return _surface;
  143. }
  144. /***********************************************************************************************
  145. * *
  146. * FontClass::Make_Proportional *
  147. * *
  148. * Modifys U and Width tables to convert a monospace font into a proportional font. Hieght *
  149. * remains the same. Performed by getting the current mono-space bounding box and bringing *
  150. * in the left and right edges to the first non-transparent ( != 0 ) pixel. Then the U and *
  151. * width tables are updated with the new values. The image itself is not modified unless... *
  152. * *
  153. * we complete by calling Minimize_Font_Image to shink the image & insure a power of 2 square *
  154. * *
  155. ***********************************************************************************************/
  156. SurfaceClass *Font3DDataClass::Make_Proportional( SurfaceClass *surface )
  157. {
  158. SurfaceClass::SurfaceDescription sd;
  159. surface->Get_Description(sd);
  160. float width = sd.Width;
  161. float height = sd.Height;
  162. // for each character in the font...
  163. for (int char_index = 0; char_index < 256; char_index++) {
  164. // find the current bounding box
  165. // (must convert the normalized uv tables to pixels and round off)
  166. int x0 = (int)(UOffsetTable[ char_index ] * width + 0.5);
  167. int y0 = (int)(VOffsetTable[ char_index ] * height + 0.5);
  168. int x1 = x0 + (int)(UWidthTable[ char_index ] * width + 0.5);
  169. int y1 = y0 + (int)(VHeight * height + 0.5);
  170. // find minimum bounding box by finding the minimum and maximum non-0 x pixel location
  171. Vector2i minb(x0,y0);
  172. Vector2i maxb(x1,y1);
  173. surface->FindBB(&minb,&maxb);
  174. // set the new edges
  175. x0 = minb.I;
  176. x1 = maxb.I+1;
  177. // if we didn't find ANY non-transparent pixels, the char has no width.
  178. if (x1 < x0) {
  179. x1 = x0;
  180. }
  181. // turn off all character after del
  182. if (char_index > 0x80) {
  183. x1 = x0;
  184. }
  185. // update the U and width tables
  186. UOffsetTable[ char_index ] = (float)x0 / width;
  187. UWidthTable[ char_index ] = (float)( x1 - x0 ) / width;
  188. CharWidthTable[ char_index ] = x1 - x0;
  189. }
  190. // now shink the image given the minimum char sizes
  191. // surface = Minimize_Font_Image( surface );
  192. Minimize_Font_Image( _surface );
  193. return NULL;
  194. }
  195. /***********************************************************************************************
  196. * *
  197. * Font3DDataClass::Load_Font_Image( SR_SCENE *scene, char *filename ) *
  198. * *
  199. * Loads a targa font image file, arranged as 16x16 characters, and builds u v tables to *
  200. * find each character. Converts the mono-space font into a proportional font, then uploads *
  201. * the image to the scene as a textur material. *
  202. * *
  203. ***********************************************************************************************/
  204. bool Font3DDataClass::Load_Font_Image( const char *filename )
  205. {
  206. // get the font surface
  207. SurfaceClass *surface = NEW_REF(SurfaceClass,(filename));
  208. WWASSERT(surface);
  209. SurfaceClass::SurfaceDescription sd;
  210. surface->Get_Description(sd);
  211. // If input is a font strike (strip) process it as such
  212. if ( sd.Width > 8 * sd.Height ) {
  213. // the height of the strike is the height of the characters
  214. VHeight = 1;
  215. CharHeight = sd.Height;
  216. int column = 0;
  217. int width = sd.Width;
  218. // for each char, find the uv start location and set the
  219. // mono-spaced width and height in normalized screen units
  220. for (int char_index = 0; char_index < 256; char_index++) {
  221. if ( char_index >= 0x7F ) {
  222. UOffsetTable[ char_index ] = 0;
  223. VOffsetTable[ char_index ] = 0;
  224. UWidthTable[ char_index ] = 0;
  225. CharWidthTable[ char_index ] = 0;
  226. } else {
  227. // find the first non-transparent column...
  228. while (( column < width ) && ( surface->Is_Transparent_Column(column) )) column++;
  229. int start = column;
  230. // find the first transparent column...
  231. while (( column < width ) && ( !surface->Is_Transparent_Column(column) )) column++;
  232. int end = column;
  233. if ( end <= start ) {
  234. WWDEBUG_SAY(( "Error Char %d start %d end %d width %d\n", char_index, start, end, width ));
  235. }
  236. // WWASSERT( end > start );
  237. UOffsetTable[ char_index ] = (float)start / width;
  238. VOffsetTable[ char_index ] = 0;
  239. UWidthTable[ char_index ] = (float)(end - start) / width;
  240. CharWidthTable[ char_index ] = end - start;
  241. }
  242. }
  243. // convert the just created mon-spaced font to proportional (optional)
  244. // surface = Make_Proportional( surface );
  245. _surface = surface;
  246. surface = NULL;
  247. Minimize_Font_Image( _surface );
  248. } else {
  249. // Determine the width and height of each mono spaced character in pixels
  250. // (assumes 16x16 array of chars)
  251. float font_width = sd.Width;
  252. float font_height = sd.Height;
  253. float mono_pixel_width = (font_width / 16);
  254. float mono_pixel_height = (font_height / 16);
  255. // for each char, find the uv start location and set the
  256. // mono-spaced width and height in normalized screen units
  257. for (int char_index = 0; char_index < 256; char_index++) {
  258. UOffsetTable[ char_index ] = (float)((char_index % 16) * mono_pixel_width) / font_width;
  259. VOffsetTable[ char_index ] = (float)((char_index / 16) * mono_pixel_height) / font_height;
  260. UWidthTable[ char_index ] = mono_pixel_width / font_width;
  261. CharWidthTable[ char_index ] = mono_pixel_width;
  262. }
  263. VHeight = mono_pixel_height / font_height;
  264. CharHeight = mono_pixel_height;
  265. // convert the just created mon-spaced font to proportional (optional)
  266. _surface = surface;
  267. surface = NULL;
  268. Make_Proportional( _surface );
  269. }
  270. // create the texture
  271. if ( _surface ) {
  272. Texture = NEW_REF(TextureClass,(_surface,TextureClass::MIP_LEVELS_1));
  273. REF_PTR_RELEASE(_surface);
  274. }
  275. // return SUCCESS!
  276. return true;
  277. }
  278. /***********************************************************************************************
  279. * *
  280. * Font3DInstanceClass::Font3DInstanceClass -- constructor *
  281. * *
  282. * Constructs and load a Targa font image to create a texture matetial *
  283. * *
  284. ***********************************************************************************************/
  285. Font3DInstanceClass::Font3DInstanceClass( const char *filename )
  286. {
  287. FontData = WW3DAssetManager::Get_Instance()->Get_Font3DData( filename);
  288. MonoSpacing = 0.0f;
  289. Scale = 1.0f;
  290. SpaceSpacing = (int)(FontData->Char_Width('H') / 2.0f);
  291. InterCharSpacing = 1;
  292. Build_Cached_Tables();
  293. }
  294. /***********************************************************************************************
  295. * *
  296. * Font3DInstanceClass::~Font3DInstanceClass -- destructor *
  297. * *
  298. ***********************************************************************************************/
  299. Font3DInstanceClass::~Font3DInstanceClass(void)
  300. {
  301. REF_PTR_RELEASE(FontData);
  302. }
  303. /*
  304. **
  305. */
  306. void Font3DInstanceClass::Set_Mono_Spaced( void )
  307. {
  308. MonoSpacing = FontData->Char_Width('W') + 1;
  309. Build_Cached_Tables();
  310. }
  311. void Font3DInstanceClass::Build_Cached_Tables()
  312. {
  313. // Rebuild the cached tables
  314. for (int a=0;a<256;++a) {
  315. float width = (float)FontData->Char_Width(a);
  316. if ( a == ' ' ) {
  317. width = SpaceSpacing;
  318. }
  319. ScaledWidthTable[a] = Scale * width;
  320. if (MonoSpacing != 0.0f) {
  321. ScaledSpacingTable[a] = Scale * MonoSpacing;
  322. } else {
  323. ScaledSpacingTable[a] = Scale * (width + InterCharSpacing);
  324. }
  325. }
  326. ScaledHeight = floorf(Scale * (float)FontData->Char_Height('A'));
  327. }
  328. /***********************************************************************************************
  329. * *
  330. * Font3DInstanceClass::String_Screen_Width( char *test_str ) *
  331. * *
  332. * Finds the normalized screenspace width of a character string - useful for checking before *
  333. * printing to avoid overflowing the screen. * *
  334. ***********************************************************************************************/
  335. float Font3DInstanceClass::String_Width( const WCHAR *test_str )
  336. {
  337. float width = 0.0;
  338. for (; *test_str; test_str++) {
  339. width += Char_Spacing(*test_str);
  340. }
  341. return width;
  342. }
  343. float Font3DInstanceClass::String_Width( const char *test_str )
  344. {
  345. float width = 0.0;
  346. for (; *test_str; test_str++) {
  347. width += Char_Spacing(*test_str);
  348. }
  349. return width;
  350. }