426 lines
17 KiB
C++
426 lines
17 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** Confidential - Westwood Studios ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : Commando / G 3D Library *
|
|
* *
|
|
* $Archive:: /Commando/Code/ww3d2/font3d.cpp $*
|
|
* *
|
|
* $Author:: Jani_p $*
|
|
* *
|
|
* $Modtime:: 4/11/01 10:17p $*
|
|
* *
|
|
* $Revision:: 16 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "font3d.h"
|
|
#include "assetmgr.h"
|
|
#include "texture.h"
|
|
#include <assert.h>
|
|
#include <wwdebug.h>
|
|
#include "surfaceclass.h"
|
|
#include "texture.h"
|
|
#include "vector2i.h"
|
|
|
|
static SurfaceClass *_surface;
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* Font3DDataClass::Font3DDataClass -- constructor *
|
|
* *
|
|
* Constructs and load a Targa font image to create a texture matetial *
|
|
* *
|
|
***********************************************************************************************/
|
|
Font3DDataClass::Font3DDataClass( const char *filename )
|
|
{
|
|
Texture = NULL;
|
|
Load_Font_Image( filename);
|
|
Name = strdup( filename);
|
|
Name = strupr( Name);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* Font3DDataClass::~Font3DDataClass -- destructor *
|
|
* *
|
|
***********************************************************************************************/
|
|
Font3DDataClass::~Font3DDataClass(void)
|
|
{
|
|
if (Name != NULL) {
|
|
free(Name);
|
|
Name = NULL;
|
|
}
|
|
|
|
REF_PTR_RELEASE(Texture);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* FontClass::Minimize_Font_Image *
|
|
* *
|
|
* Rebuilds the give image to better pack characters and to insure a square power of two size *
|
|
* Must be called AFTER Make_Proportional() so each chars minimal bounding box is known *
|
|
* Will only create a new texture of size 128x128 or 256x256, dependant on original width *
|
|
* *
|
|
***********************************************************************************************/
|
|
SurfaceClass *Font3DDataClass::Minimize_Font_Image( SurfaceClass *surface )
|
|
{
|
|
SurfaceClass::SurfaceDescription sd;
|
|
|
|
surface->Get_Description(sd);
|
|
|
|
float current_width = sd.Width;
|
|
float current_height = sd.Height;
|
|
|
|
// determine new width make the size of the new image either 128x128 or 256x256,
|
|
// dependant on the width of the original image
|
|
int new_width;
|
|
if (current_width < 256) {
|
|
new_width = 128;
|
|
} else {
|
|
new_width = 256;
|
|
}
|
|
|
|
int new_height = new_width;
|
|
// create a new 4 bit alpha image to build into
|
|
// We dont support non-homogeneous copies just yet
|
|
SurfaceClass *new_surface = NEW_REF(SurfaceClass,(new_width, new_height,WW3D_FORMAT_A4R4G4B4));
|
|
//SurfaceClass *new_surface0 = NEW_REF(SurfaceClass,(new_width, new_height,sd.Format));
|
|
|
|
// fill with transparent black
|
|
new_surface->Clear();
|
|
|
|
// indices for the location of each added char
|
|
int new_x = 0;
|
|
int new_y = 0;
|
|
|
|
// for each character, copy minimum bounding area to (new_x, new_y) in the new image
|
|
for (int char_index = 0; char_index < 256; char_index++) {
|
|
|
|
// find the lop left coordinate and the height and width of the char's bounding box
|
|
// (must convert the normalized uv tables to pixels and round off)
|
|
int src_x = (int)(UOffsetTable[ char_index ] * current_width + 0.5);
|
|
int src_y = (int)(VOffsetTable[ char_index ] * current_height + 0.5);
|
|
int width = (int)(UWidthTable[ char_index ] * current_width + 0.5);
|
|
int height = (int)(VHeight * current_height + 0.5);
|
|
|
|
// if the character has any visible pixels at all...
|
|
if (width != 0) {
|
|
|
|
// if this charactger will not fit on the current line, goto the next line
|
|
if (new_x + width > new_width) {
|
|
new_x = 0;
|
|
new_y += height;
|
|
|
|
// if we have run out of lines, we have a problem
|
|
// we assert because we have already modified tables for some of the chars
|
|
if (new_y + height > new_height) {
|
|
new_y -= height;
|
|
WWDEBUG_SAY(( "Font doesn't fit texture 2 on char %c\n", char_index ));
|
|
}
|
|
}
|
|
|
|
// blit from original image to new image
|
|
|
|
new_surface->Copy(new_x, new_y,src_x,src_y,width,height,surface);
|
|
|
|
}
|
|
|
|
// update the U and V tables to show new character location
|
|
UOffsetTable[ char_index ] = (float)(new_x) / (float)new_width;
|
|
VOffsetTable[ char_index ] = (float)(new_y) / (float)new_width;
|
|
|
|
// update width in terms of new normal image width
|
|
UWidthTable[ char_index ] *= (float)current_width / (float)new_width;
|
|
|
|
new_x += width;
|
|
}
|
|
|
|
// update height in terms of new normal image height
|
|
VHeight *= (float)current_height / (float)new_height;
|
|
|
|
// be sure the new image is SMALLER than the old image
|
|
// assert ( (new_width * new_height) <= (current_width * current_height));
|
|
|
|
// release the old surface and return the new one
|
|
REF_PTR_RELEASE(surface);
|
|
|
|
_surface = new_surface;
|
|
|
|
return _surface;
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* FontClass::Make_Proportional *
|
|
* *
|
|
* Modifys U and Width tables to convert a monospace font into a proportional font. Hieght *
|
|
* remains the same. Performed by getting the current mono-space bounding box and bringing *
|
|
* in the left and right edges to the first non-transparent ( != 0 ) pixel. Then the U and *
|
|
* width tables are updated with the new values. The image itself is not modified unless... *
|
|
* *
|
|
* we complete by calling Minimize_Font_Image to shink the image & insure a power of 2 square *
|
|
* *
|
|
***********************************************************************************************/
|
|
SurfaceClass *Font3DDataClass::Make_Proportional( SurfaceClass *surface )
|
|
{
|
|
SurfaceClass::SurfaceDescription sd;
|
|
surface->Get_Description(sd);
|
|
float width = sd.Width;
|
|
float height = sd.Height;
|
|
|
|
// for each character in the font...
|
|
for (int char_index = 0; char_index < 256; char_index++) {
|
|
|
|
// find the current bounding box
|
|
// (must convert the normalized uv tables to pixels and round off)
|
|
int x0 = (int)(UOffsetTable[ char_index ] * width + 0.5);
|
|
int y0 = (int)(VOffsetTable[ char_index ] * height + 0.5);
|
|
int x1 = x0 + (int)(UWidthTable[ char_index ] * width + 0.5);
|
|
int y1 = y0 + (int)(VHeight * height + 0.5);
|
|
|
|
// find minimum bounding box by finding the minimum and maximum non-0 x pixel location
|
|
Vector2i minb(x0,y0);
|
|
Vector2i maxb(x1,y1);
|
|
|
|
surface->FindBB(&minb,&maxb);
|
|
|
|
// set the new edges
|
|
x0 = minb.I;
|
|
x1 = maxb.I+1;
|
|
|
|
// if we didn't find ANY non-transparent pixels, the char has no width.
|
|
if (x1 < x0) {
|
|
x1 = x0;
|
|
}
|
|
|
|
// turn off all character after del
|
|
if (char_index > 0x80) {
|
|
x1 = x0;
|
|
}
|
|
|
|
// update the U and width tables
|
|
UOffsetTable[ char_index ] = (float)x0 / width;
|
|
UWidthTable[ char_index ] = (float)( x1 - x0 ) / width;
|
|
CharWidthTable[ char_index ] = x1 - x0;
|
|
}
|
|
|
|
// now shink the image given the minimum char sizes
|
|
// surface = Minimize_Font_Image( surface );
|
|
Minimize_Font_Image( _surface );
|
|
return NULL;
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* Font3DDataClass::Load_Font_Image( SR_SCENE *scene, char *filename ) *
|
|
* *
|
|
* Loads a targa font image file, arranged as 16x16 characters, and builds u v tables to *
|
|
* find each character. Converts the mono-space font into a proportional font, then uploads *
|
|
* the image to the scene as a textur material. *
|
|
* *
|
|
***********************************************************************************************/
|
|
bool Font3DDataClass::Load_Font_Image( const char *filename )
|
|
{
|
|
// get the font surface
|
|
SurfaceClass *surface = NEW_REF(SurfaceClass,(filename));
|
|
WWASSERT(surface);
|
|
|
|
SurfaceClass::SurfaceDescription sd;
|
|
surface->Get_Description(sd);
|
|
|
|
// If input is a font strike (strip) process it as such
|
|
if ( sd.Width > 8 * sd.Height ) {
|
|
|
|
// the height of the strike is the height of the characters
|
|
VHeight = 1;
|
|
CharHeight = sd.Height;
|
|
|
|
int column = 0;
|
|
int width = sd.Width;
|
|
|
|
|
|
// for each char, find the uv start location and set the
|
|
// mono-spaced width and height in normalized screen units
|
|
for (int char_index = 0; char_index < 256; char_index++) {
|
|
|
|
if ( char_index >= 0x7F ) {
|
|
|
|
UOffsetTable[ char_index ] = 0;
|
|
VOffsetTable[ char_index ] = 0;
|
|
UWidthTable[ char_index ] = 0;
|
|
CharWidthTable[ char_index ] = 0;
|
|
|
|
} else {
|
|
|
|
// find the first non-transparent column...
|
|
while (( column < width ) && ( surface->Is_Transparent_Column(column) )) column++;
|
|
int start = column;
|
|
|
|
// find the first transparent column...
|
|
while (( column < width ) && ( !surface->Is_Transparent_Column(column) )) column++;
|
|
int end = column;
|
|
|
|
if ( end <= start ) {
|
|
WWDEBUG_SAY(( "Error Char %d start %d end %d width %d\n", char_index, start, end, width ));
|
|
}
|
|
|
|
// WWASSERT( end > start );
|
|
|
|
UOffsetTable[ char_index ] = (float)start / width;
|
|
VOffsetTable[ char_index ] = 0;
|
|
UWidthTable[ char_index ] = (float)(end - start) / width;
|
|
CharWidthTable[ char_index ] = end - start;
|
|
}
|
|
|
|
}
|
|
|
|
// convert the just created mon-spaced font to proportional (optional)
|
|
// surface = Make_Proportional( surface );
|
|
_surface = surface;
|
|
surface = NULL;
|
|
Minimize_Font_Image( _surface );
|
|
|
|
} else {
|
|
|
|
// Determine the width and height of each mono spaced character in pixels
|
|
// (assumes 16x16 array of chars)
|
|
float font_width = sd.Width;
|
|
float font_height = sd.Height;
|
|
float mono_pixel_width = (font_width / 16);
|
|
float mono_pixel_height = (font_height / 16);
|
|
|
|
// for each char, find the uv start location and set the
|
|
// mono-spaced width and height in normalized screen units
|
|
for (int char_index = 0; char_index < 256; char_index++) {
|
|
UOffsetTable[ char_index ] = (float)((char_index % 16) * mono_pixel_width) / font_width;
|
|
VOffsetTable[ char_index ] = (float)((char_index / 16) * mono_pixel_height) / font_height;
|
|
UWidthTable[ char_index ] = mono_pixel_width / font_width;
|
|
CharWidthTable[ char_index ] = mono_pixel_width;
|
|
}
|
|
VHeight = mono_pixel_height / font_height;
|
|
CharHeight = mono_pixel_height;
|
|
|
|
// convert the just created mon-spaced font to proportional (optional)
|
|
|
|
_surface = surface;
|
|
surface = NULL;
|
|
Make_Proportional( _surface );
|
|
}
|
|
|
|
// create the texture
|
|
if ( _surface ) {
|
|
Texture = NEW_REF(TextureClass,(_surface,TextureClass::MIP_LEVELS_1));
|
|
REF_PTR_RELEASE(_surface);
|
|
}
|
|
|
|
// return SUCCESS!
|
|
return true;
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* Font3DInstanceClass::Font3DInstanceClass -- constructor *
|
|
* *
|
|
* Constructs and load a Targa font image to create a texture matetial *
|
|
* *
|
|
***********************************************************************************************/
|
|
Font3DInstanceClass::Font3DInstanceClass( const char *filename )
|
|
{
|
|
FontData = WW3DAssetManager::Get_Instance()->Get_Font3DData( filename);
|
|
MonoSpacing = 0.0f;
|
|
Scale = 1.0f;
|
|
SpaceSpacing = (int)(FontData->Char_Width('H') / 2.0f);
|
|
InterCharSpacing = 1;
|
|
Build_Cached_Tables();
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* Font3DInstanceClass::~Font3DInstanceClass -- destructor *
|
|
* *
|
|
***********************************************************************************************/
|
|
Font3DInstanceClass::~Font3DInstanceClass(void)
|
|
{
|
|
REF_PTR_RELEASE(FontData);
|
|
}
|
|
|
|
/*
|
|
**
|
|
*/
|
|
void Font3DInstanceClass::Set_Mono_Spaced( void )
|
|
{
|
|
MonoSpacing = FontData->Char_Width('W') + 1;
|
|
Build_Cached_Tables();
|
|
}
|
|
|
|
void Font3DInstanceClass::Build_Cached_Tables()
|
|
{
|
|
// Rebuild the cached tables
|
|
for (int a=0;a<256;++a) {
|
|
float width = (float)FontData->Char_Width(a);
|
|
if ( a == ' ' ) {
|
|
width = SpaceSpacing;
|
|
}
|
|
|
|
ScaledWidthTable[a] = Scale * width;
|
|
if (MonoSpacing != 0.0f) {
|
|
ScaledSpacingTable[a] = Scale * MonoSpacing;
|
|
} else {
|
|
ScaledSpacingTable[a] = Scale * (width + InterCharSpacing);
|
|
}
|
|
}
|
|
ScaledHeight = floor(Scale * (float)FontData->Char_Height('A'));
|
|
}
|
|
|
|
/***********************************************************************************************
|
|
* *
|
|
* Font3DInstanceClass::String_Screen_Width( char *test_str ) *
|
|
* *
|
|
* Finds the normalized screenspace width of a character string - useful for checking before *
|
|
* printing to avoid overflowing the screen. * *
|
|
***********************************************************************************************/
|
|
float Font3DInstanceClass::String_Width( const WCHAR *test_str )
|
|
{
|
|
float width = 0.0;
|
|
for (; *test_str; test_str++) {
|
|
width += Char_Spacing(*test_str);
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
float Font3DInstanceClass::String_Width( const char *test_str )
|
|
{
|
|
float width = 0.0;
|
|
for (; *test_str; test_str++) {
|
|
width += Char_Spacing(*test_str);
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|