This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/font3d.cpp

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;
}