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