| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632 |
- /*
- ** 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/>.
- */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * $Archive:: /VSS_Sync/wwlib/wwfont.cpp $*
- * *
- * $Author:: Vss_sync $*
- * *
- * $Modtime:: 10/16/00 11:42a $*
- * *
- * $Revision:: 5 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * WWFontClass::Print -- Print text to the surface specified. *
- * WWFontClass::WWFontClass -- Constructor for a font class object. *
- * WWFontClass::Char_Pixel_Width -- Fetch the pixel width of the character specified. *
- * WWFontClass::String_Pixel_Width -- Determines the width of the string in pixels. *
- * WWFontClass::Raw_Width -- Fetch the raw width of a character. *
- * WWFontClass::Raw_Height -- Fetch the height of the font. *
- * WWFontClass::Get_Width -- Get normalized width of the nominal font character. *
- * WWFontClass::Get_Height -- Fetch the normalized height of the nominal font character. *
- * WWFontClass::Set_XSpacing -- Set the X spacing override value. *
- * WWFontClass::Set_YSpacing -- Set the vertical (Y) spacing override value. *
- * Set_Font_Data -- Allow font data to be set after construction. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "always.h"
- #include "_convert.h"
- #include "wwfont.h"
- //#include <stdlib.h>
- #define FONTINFOMAXHEIGHT 4
- #define FONTINFOMAXWIDTH 5
- #define FUDGEDIV 16
- /***********************************************************************************************
- * WWFontClass::WWFontClass -- Constructor for a font class object. *
- * *
- * This constructs a font object as it is based upon the font data output by the legacy *
- * FONTMAKE.EXE utility. *
- * *
- * INPUT: fontdata -- Pointer to the data as output by the fontmake utility. *
- * *
- * isoutlined -- Is this font data available with outline pixels embedded? *
- * *
- * shadow -- Does the font data have shadow pixels embedded? *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- WWFontClass::WWFontClass(void const * fontdata, bool isoutlined, int shadow, ConvertClass *convert, unsigned char *remap) :
- IsOutlinedData(isoutlined),
- Shadow(shadow),
- Converter(convert),
- RemapPalette(remap),
- FontXSpacing(0),
- FontYSpacing(0)
- {
- Set_Font_Data(fontdata);
- }
- /***********************************************************************************************
- * Set_Font_Data -- Allow font data to be set after construction. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 01/24/2000 SKB : Created. *
- *=============================================================================================*/
- void *WWFontClass::Set_Font_Data(void const * fontdata)
- {
- void *old = (void *) FontData;
- FontData = (FontType *)fontdata;
- if (FontData) {
- Set_XSpacing(FontXSpacing);
- Set_YSpacing(FontYSpacing);
- }
- return(old);
- }
- /***********************************************************************************************
- * WWFontClass::Char_Pixel_Width -- Fetch the pixel width of the character specified. *
- * *
- * This will return with the pixel width of the character specified. *
- * *
- * INPUT: c -- The character to determine the pixel width for. *
- * *
- * OUTPUT: Returns with the pixel width of the character. *
- * *
- * WARNINGS: The return width is the screen real estate width which may differ from the *
- * actual pixels of the character. This difference is controlled by the font *
- * X spacing. *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Char_Pixel_Width(char c) const
- {
- int raw = (*(((unsigned char *)FontData) + FontData->WidthBlockOffset + (unsigned char)c));
- raw += FontXSpacing;
- return(raw);
- }
- /***********************************************************************************************
- * WWFontClass::String_Pixel_Width -- Determines the width of the string in pixels. *
- * *
- * This routine is used to determine how many pixels wide the string will be if it were *
- * printed. *
- * *
- * INPUT: string -- The string to convert into its pixel width. *
- * *
- * OUTPUT: Returns with the number of pixels the string would span if it were printed. *
- * *
- * WARNINGS: This routine does not take into account clipping. *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::String_Pixel_Width(char const * string) const
- {
- if (string == NULL) return(0);
- if (string[0] == 0) return 0;
- int largest = 0; // Largest recorded width of the string.
- int width = 0;
- while (*string) {
- if (*string == '\r' || *string == '\n') {
- string++;
- largest = MAX(largest, width);
- width = 0;
- } else {
- width += Char_Pixel_Width(*string++); // add each char's width
- }
- }
- largest = MAX(largest, width);
- return(largest);
- }
- /***********************************************************************************************
- * WWFontClass::Raw_Width -- Fetch the raw width of a character. *
- * *
- * This routine returns the nominal width of the font. This width is basically the width of *
- * the widest character in the font. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the width of the widest character in the font. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Raw_Width(void) const
- {
- return(*(((unsigned char *)FontData) + FontData->InfoBlockOffset + FONTINFOMAXWIDTH));
- }
- /***********************************************************************************************
- * WWFontClass::Raw_Height -- Fetch the height of the font. *
- * *
- * This returns the height of the font without regard for any Y spacing offsets. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the height of the font. *
- * *
- * WARNINGS: All characters in the font have the same logical height even if they actually *
- * consume less pixels. *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Raw_Height(void) const
- {
- return(*(((unsigned char *)FontData) + FontData->InfoBlockOffset + FONTINFOMAXHEIGHT));
- }
- /***********************************************************************************************
- * WWFontClass::Get_Width -- Get normalized width of the nominal font character. *
- * *
- * This routine is used to fetch the width of the widest character in the font but the *
- * width has been biased according to any X spacing override present. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the normalized width of the widest character in the font. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Get_Width(void) const
- {
- return(Raw_Width() + ((FontXSpacing > 0) ? FontXSpacing : 0));
- }
- /***********************************************************************************************
- * WWFontClass::Get_Height -- Fetch the normalized height of the nominal font character. *
- * *
- * This will return the height of the font but the returned height will be adjusted by any *
- * Y spacing override present. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the height of the font normalized by any spacing overrides. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Get_Height(void) const
- {
- return(Raw_Height() + ((FontYSpacing > 0) ? FontYSpacing : 0));
- }
- /***********************************************************************************************
- * WWFontClass::Set_XSpacing -- Set the X spacing override value. *
- * *
- * Use this routine to control the horizontal spacing override for this font. If the value *
- * is negative, the font becomes compressed. If the value is positive, then the font *
- * becomes expanded. *
- * *
- * INPUT: x -- The X spacing override to use for this font. *
- * *
- * OUTPUT: Returns with the old X spacing override value. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Set_XSpacing(int x)
- {
- int old = FontXSpacing;
- FontXSpacing = x;
- if (IsOutlinedData) {
- switch (Shadow) {
- case 0:
- FontXSpacing += -2;
- break;
- case 1:
- FontXSpacing += -1;
- break;
- case 2:
- FontXSpacing += -1;
- break;
- }
- }
- FontXSpacing += Get_Width() / FUDGEDIV;
- return(old);
- }
- /***********************************************************************************************
- * WWFontClass::Set_YSpacing -- Set the vertical (Y) spacing override value. *
- * *
- * Use this routine to control the "line spacing" of a font. If the Y spacing is negative *
- * then the font becomes closer to the line above it. If value is positive, then more *
- * space occurs between lines. *
- * *
- * INPUT: y -- The Y spacing override to use for this font. *
- * *
- * OUTPUT: Returns with the old Y spacing override value. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- *=============================================================================================*/
- int WWFontClass::Set_YSpacing(int y)
- {
- int old = FontYSpacing;
- FontYSpacing = y;
- if (IsOutlinedData) {
- switch (Shadow) {
- case 0:
- FontYSpacing += -2;
- break;
- case 1:
- FontYSpacing += -1;
- break;
- case 2:
- FontYSpacing += -1;
- break;
- }
- }
- FontYSpacing += Get_Height() / FUDGEDIV;
- return(old);
- }
-
- /***********************************************************************************************
- * WWFontClass::Print -- Print text to the surface specified. *
- * *
- * This displays text to the surface specified and with the attributes specified. *
- * *
- * INPUT: string -- The string to display to the surface. *
- * *
- * surface -- The surface to display the text upon. *
- * *
- * cliprect -- The clipping rectangle that both clips the text and biases the print *
- * location to. *
- * *
- * point -- The draw position for the upper left corner of the first character. *
- * *
- * convert -- The pixel convert object that is used to draw the correct colors to *
- * the destination surface. *
- * *
- * remap -- Auxiliary remap table for font colors. *
- * *
- * OUTPUT: Returns with the point where the next print should begin if it is to smoothly *
- * continue where this print operation left off. *
- * *
- * WARNINGS: There are two separate drawing routines; one for old fonts and one for new *
- * fonts. *
- * *
- * HISTORY: *
- * 05/26/1997 JLB : Created. *
- * 06/20/1887 BNA : Modified to handle new fonts. *
- * 01/24/2000 SKB : Updated from C&C to include BNA code. *
- * 01/24/2000 SKB : put in call for Get_Remap_Palette *
- * 01/24/2000 SKB : Put in call for get converer. *
- *=============================================================================================*/
- Point2D WWFontClass::Print(char const * string, Surface & surface, Rect const & cliprect, Point2D const & drawpoint, ConvertClass const & convertref, unsigned char const * remap) const
- {
- if (string == NULL) return(drawpoint);
- /*
- ** Compute the surface relative coordinate for the print position.
- */
- Point2D point = drawpoint;
- int xpos = point.Bias_To(cliprect).X;
- // int xpos = point.X + cliprect.X;
- int ypos = point.Bias_To(cliprect).Y;
- // int ypos = point.Y + cliprect.Y;
- int xspacing = FontXSpacing + Raw_Width()/FUDGEDIV;
- int yspacing = FontYSpacing + Raw_Width()/FUDGEDIV;
-
- // This font palette assumes that the font will be used as defined by converter.
- static unsigned char const fontpalette[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
- if (RemapPalette) {
- remap = RemapPalette;
- } else if (!remap) {
- remap = &fontpalette[0];
- }
-
- // If there is a convert supplied with the font, use it as priority.
- ConvertClass const *converter = Converter;
- if (!converter) {
- converter = &convertref;
- }
- /*
- ** Verify that the clipping rectangle (if present) falls within the bounds of the surface.
- */
- // Rect cliprect = surface->Get_Rect();
- // cliprect.X = 0;
- // cliprect.Y = 0;
- /*
- ** Trivially check to see if the print start position is outside the bounds of the clipping
- ** rectangle.
- */
- if (xpos >= cliprect.X+cliprect.Width || ypos >= cliprect.Y+cliprect.Height) {
- return(drawpoint);
- }
- /*
- ** Check to see if access to the surface buffer is possible.
- */
- void * buffer = surface.Lock();
- if (buffer != NULL) {
- int startx = xpos;
- unsigned char * fontwidth = ((unsigned char*)FontData) + FontData->WidthBlockOffset;
- unsigned short * fontheight = (unsigned short*)(((unsigned char*)FontData) + FontData->HeightOffset);
- unsigned short * fontoffset = (unsigned short*)(((unsigned char*)FontData) + FontData->OffsetBlockOffset);
- int bbp = surface.Bytes_Per_Pixel();
- /*
- ** Process the whole string. Stop when the string reaches the right margin.
- */
- while (*string != '\0') {
- unsigned char c = *string++;
- /*
- ** Certain control characters serve a formatting purpose. They merely
- ** adjust the next draw position.
- */
- if (c == '\r') {
- xpos = startx;
- ypos += Raw_Height() + ((yspacing > 0) ? yspacing : 0);
- continue;
- }
- if (c == '\n') {
- xpos = cliprect.X;
- ypos += Raw_Height() + ((yspacing > 0) ? yspacing : 0);
- continue;
- }
- /*
- ** Fetch working values for the character to display. These are used to
- ** control the size of the character rectangle.
- */
- int width = fontwidth[c];
- int dheight = fontheight[c] >> 8;
- int firstrow = fontheight[c] & 0xFF;
- // int height = dheight+firstrow;
-
- /*
- ** Build the character rectangle (surface relative coordinates).
- */
- Rect crect(xpos, ypos, width+((xspacing > 0) ? xspacing : 0), *(((unsigned char *)FontData) + FontData->InfoBlockOffset + FONTINFOMAXHEIGHT) + ((yspacing > 0) ? yspacing : 0));
- /*
- ** Check to see if any part of this character would appear within the clipping
- ** rectangle. If not, then don't process this character.
- */
- crect = crect.Intersect(cliprect);
- if (crect.Is_Valid()) {
-
- /*
- ** Fill the background of the character if the background
- ** color is not transparent.
- */
- if (remap[0] != 0) {
- surface.Fill_Rect(crect, converter->Convert_Pixel(remap[0]));
- }
- /*
- ** Loop through all data rows of this character and output the row
- ** data with clipping.
- */
- if (FontData->FontCompress != (char) 2) { // if the font is the old style
- unsigned char * dataptr = ((unsigned char *)FontData) + fontoffset[c];
- void * drawbuff = (void*)(((char*)buffer) + ((ypos + firstrow) * surface.Stride()) + xpos * bbp);
- for (int h = 0; h < dheight; h++) {
- /*
- ** If the current row to be drawn falls below the clipping rectangle, then
- ** no further drawing for this character is needed -- bail out.
- */
- if (ypos + firstrow + h >= crect.Y + crect.Height) break;
- /*
- ** If the current row to be drawn falls above the clipping rectangle,
- ** then skip the row and advance the source data pointer as well.
- */
- if (ypos + firstrow + h < crect.Y) {
- drawbuff = (void*)(((char*)drawbuff) + surface.Stride());
- dataptr = dataptr + ((width+1)/2);
- } else {
- /*
- ** Process one row of character data. For simplicity reasons, just
- ** loop through all pixels of this row and perform clipping at the
- ** pixel level.
- */
- int dx = xpos;
- int workwidth = width;
- while (workwidth > 0) {
- /*
- ** Fetch the next two pixel values. Two pixel values must
- ** be fetched at the same time since they are nibble packed.
- */
- int c1 = remap[*dataptr & 0x0F];
- int c2 = remap[(*dataptr++ & 0xF0) >> 4];
-
- /*
- ** Draw the first pixel if it falls within the clipping
- ** rectangle and is not transparent.
- */
- if (dx >= cliprect.X && dx < cliprect.X+cliprect.Width) {
- if (c1 != 0) {
- if (bbp == 2) {
- *(short *)drawbuff = (short)converter->Convert_Pixel(c1);
- } else {
- *(char *)drawbuff = (char)converter->Convert_Pixel(c1);
- }
- }
- }
- dx += 1;
- drawbuff = ((char*)drawbuff) + bbp;
- workwidth -= 1;
- if (workwidth == 0) break;
-
- /*
- ** Draw the second pixel if it falls within the clipping
- ** rectangle and is not transparent.
- */
- if (dx >= cliprect.X && dx < cliprect.X+cliprect.Width) {
- if (c2 != 0) {
- if (bbp == 2) {
- *(short *)drawbuff = (short)converter->Convert_Pixel(c2);
- } else {
- *(char *)drawbuff = (char)converter->Convert_Pixel(c2);
- }
- }
- }
- dx += 1;
- drawbuff = ((char*)drawbuff) + bbp;
- workwidth -= 1;
- }
- /*
- ** Move the output pixel pointer to the next line down but at the
- ** left margin of the character block.
- */
- drawbuff = (void*)((((char*)drawbuff) - (width*bbp)) + surface.Stride());
- }
- }
- } else {
- // the font is of the new type
- unsigned char * dataptr = ((unsigned char *)FontData) + fontoffset[c] + FontData->DataBlockOffset;
- void * drawbuff = (void*)(((char*)buffer) + ((ypos + firstrow) * surface.Stride()) + xpos * bbp);
- for (int h = 0; h < dheight; h++) {
- /*
- ** If the current row to be drawn falls below the clipping rectangle, then
- ** no further drawing for this character is needed -- bail out.
- */
- if (ypos + firstrow + h >= crect.Y + crect.Height) break;
- /*
- ** If the current row to be drawn falls above the clipping rectangle,
- ** then skip the row and advance the source data pointer as well.
- */
- if (ypos + firstrow + h < crect.Y) {
- drawbuff = (void*)(((char*)drawbuff) + surface.Stride());
- dataptr = dataptr + width;
- } else {
- /*
- ** Process one row of character data. For simplicity reasons, just
- ** loop through all pixels of this row and perform clipping at the
- ** pixel level.
- */
- int dx = xpos;
- int workwidth = width;
- while (workwidth > 0) {
- /*
- ** Fetch the next pixel value.
- */
- int c1 = remap[*dataptr++]; // no remapping
-
- /*
- ** Draw the pixel if it falls within the clipping
- ** rectangle and is not transparent.
- */
- if (dx >= cliprect.X && dx < cliprect.X+cliprect.Width) {
- if (c1 != 0) {
- if (bbp == 2) {
- *(short *)drawbuff = (short)converter->Convert_Pixel(c1);
- } else {
- *(char *)drawbuff = (char)converter->Convert_Pixel(c1);
- }
- }
- }
- dx += 1;
- drawbuff = ((char*)drawbuff) + bbp;
- workwidth -= 1;
- }
- /*
- ** Move the output pixel pointer to the next line down but at the
- ** left margin of the character block.
- */
- drawbuff = (void*)((((char*)drawbuff) - (width*bbp)) + surface.Stride());
- }
- }
- }
- }
- xpos += Char_Pixel_Width(c);
- // xpos += width + xspacing;
- }
- point = Point2D(xpos - cliprect.X, ypos - cliprect.Y);
- surface.Unlock();
- }
- return(point);
- }
|