font3d.cpp 17 KB

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