avp/3dc/AFONT.C

914 lines
22 KiB
C
Raw Normal View History

#include "3dc.h"
#include "inline.h"
#include "module.h"
#include "gamedef.h"
#include "font.h"
#include "indexfnt.hpp"
#define UseLocalAssert 1
#include "ourasert.h"
/* Roxbys font stuff. any comments will be useful!!!
font control - Fonts description and sturctures game/plat/font.h
Platform dependent processing game/plat/platsup.c or ddplat.cpp
*/
/* general ideas. Crap I know!!!
written to maintain compatiblity with the current texture (bitmap) processing tools.
all the information about spacing of the font is maintained witin the bitmap itself,
using hotspots for the texture processing, that way we dont need extra tools to convert
fonts. It also allows complete font positioning (except different letter combos changing)
I have shifted most of the emphasis onto the artists to set up the font and to mark it how they
see fit. All the fonts must contain hotspots for all the letters. In that way we can easily
expand fonts. The character offests at the mo are simply -32. We may have to set up jump tables
at some later date to get chars for different languages.
Nothing supports anti-aliasing at the moment. Be careful with colours!!!
Most of the info is being passed as locals. Clumsy I know. I didnt want to take up more
space than was nessecery
HARD coded. Names of the fonts
Number of fonts to load
Number of characters in the font. you can leave letters blank. The number of
characters in the fonts can be changed for different languages
AVP-Win95
This loads all the fonts in the structure PFFONT AvpFonts[] that is passed
to while NUM_FONTS. The Imageheader->ImagePtr for the data is maintained
untill we have processd the characters. I dont fancy manipulating the data
in a LPDIRECTDRAWSURFACE. The character descriptors in the font contain
nothing but a src RECT. the void* pointer in the PFFONT structure in this
case is cast to LPDIRECTDRAWSURFACE.
Not that the entire font is placed into a
file That is then processed. CLUT where to
put the CLU???? Put it into the vid memory.
use a void*
*/
/*
Only have 8 bit support a tne moment. More to come!!!
Screen modes. I recommend loading up different fonts for different screen modes.
Simply reference a different structure.
*/
#define CHAR_WIDTH(font_num, offset) ((AvpFonts[font_num].srcRect[offset].right - AvpFonts[font_num].srcRect[offset].left))
#define CHAR_HEIGHT(font_num, offset) ((AvpFonts[font_num].srcRect[offset].bottom - AvpFonts[font_num].srcRect[offset].top))
#define IS_CHAR_WHITE_SPACE(ch) ((ch == '\t' || ch == '\n' || ch == ' ' || (int)ch == 0x0))
static int ProcessFontEntry
(
PFFONT* font,
unsigned char* fontstartaddress,
unsigned pitch,
int* countfromrow,
int* countfromcol,
int charnum
);
static int ProcessLineLength
(
char* start_ch, // start char of string
AVP_FONTS fontnum, // the font we are using
int offset, // the offset from the font
int max_width, // the width of the line
char** end_ch, // filled with end address
int* line_length
);
void LoadAllFonts()
{
// these fonts end up being in memory all the time,
// I will also supply a function which is delete
// specific font.
int fontnum = 0;
while(fontnum < NUM_FONTS)
{
/* load the font in turn */
LoadPFFont(fontnum);
fontnum ++;
}
}
void LoadPFFont(int fontnum)
{
// these fonts end up being in memory all the time,
// I will also supply a function which is delete
// specific font.
PFFONT *font = &AvpFonts[fontnum];
unsigned nPitch;
unsigned char * pSurface;
LoadFont(font);
/* get the hotspot color first entry in */
if(font->fttexBitDepth == 15)font->fttexBitDepth = 16;
pSurface = FontLock(font,&nPitch);
GLOBALASSERT(pSurface);
font->hotSpotValue = *(unsigned *)pSurface & (font->fttexBitDepth<32 ? (1<<font->fttexBitDepth)-1 : 0xffffffffU);
/* the hotspot value is the top-left pixel */
{
int charnum = 0;
int countfromrow = 1;
int countfromcol = 0;
/*
find the hotspots and send everything to the
processing function. This part of routine find the
hotspots in numbers of pixels
*/
/*Top line of the texture is redundent we get the hotspot from this*/
/*edge of the texture has only lines*/
while(charnum < font->num_chars_in_font)
{
ProcessFontEntry(font,pSurface,nPitch,&countfromrow,&countfromcol,charnum);
charnum++;
}
#if 0
// Taken out by DHM 26/11/97:
fontnum++;
#endif
charnum = 0;
}
FontUnlock(font);
#if SupportWindows95
INDEXFNT_PFLoadHook
(
(FontIndex) fontnum,
// FontIndex I_Font_New,
font // PFFONT *pffont_New
);
#endif
}
static int ProcessFontEntry
(
PFFONT* font,
unsigned char* fontstartaddress,
unsigned pitch,
int* countfromrow,
int* countfromcol,
int charnum
)
{
/*
okay set the starting point
countfromrow marks the current depth of the processing row in the texture.
countfromcol marks how far along the current coloum we have processed
* = HOTSPOT .. the first pixel is used as the hotspot
**********************
* ** ** **** * <---- startfromrow
###
#
## # # ###
# # # # # ##
### ### #### ##
* * # * **** * Blank chars marked by two hotspots adjacent
### ^^ |at the top and the bottom
* * || |
^ ||______|
|
|
startfromcol
********************* Note that the spot in col 0 marks a new linw of chars
*/
int curr_row = *countfromrow;
int curr_col = *countfromcol;
int y_offset = 0, x_offset = curr_col;
GLOBALASSERT(font);
GLOBALASSERT(fontstartaddress);
GLOBALASSERT(charnum < font->num_chars_in_font);
GLOBALASSERT(curr_row < font->fttexHeight);
GLOBALASSERT(curr_col <= font->fttexWidth);
/*remember that all the corrdinates are done by pixels
find the x and y corrdinates of the left lower hotspot
we process each line (row) from startfromrow to the end
first find the next marker in startfromrow
*/
// only supported if bit depth is a whole number of bytes
GLOBALASSERT(8==font->fttexBitDepth || 16==font->fttexBitDepth || 24==font->fttexBitDepth || 32==font->fttexBitDepth);
while(1)
{
// this bit processes the chars, finds uvs, extents and fills in the sturcture*/
// count along the row to find the next x position
unsigned int colour_here;
if(x_offset > font->fttexWidth - 1)
{
// reached the end of the line! reset x and then y
x_offset = 0;
curr_col = 0;
curr_row += font->fontHeight; // max line height
*countfromrow = curr_row;
GLOBALASSERT(curr_row < font->fttexHeight);
}
switch (font->fttexBitDepth)
{
default:
GLOBALASSERT(0);
case 8:
colour_here = *(fontstartaddress + (curr_row*pitch + x_offset));
break;
case 16:
colour_here = *(unsigned short *)(fontstartaddress + (curr_row*pitch + 2*x_offset));
break;
case 24:
{
unsigned char * pPixel = fontstartaddress + (curr_row*pitch + 3*x_offset);
// assuming the right endianness
colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16;
break;
}
case 32:
colour_here = *(unsigned *)(fontstartaddress + (curr_row*pitch + 4*x_offset));
break;
}
if(colour_here == font->hotSpotValue)
{
int width = -1, height = -1;
/* set up the uv corrds of the top left corner*/
int u = x_offset + 1;
int v = curr_row + 1;
/* scan down to give height*/
for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++)
{
switch (font->fttexBitDepth)
{
default:
GLOBALASSERT(0);
case 8:
colour_here = *(fontstartaddress + (y_offset*pitch + x_offset));
break;
case 16:
colour_here = *(unsigned short *)(fontstartaddress + (y_offset*pitch + 2*x_offset));
break;
case 24:
{
unsigned char * pPixel = fontstartaddress + (y_offset*pitch + 3*x_offset);
// assuming the right endianness
colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16;
break;
}
case 32:
colour_here = *(unsigned *)(fontstartaddress + (y_offset*pitch + 4*x_offset));
break;
}
if(colour_here == font->hotSpotValue)
{
height = y_offset - curr_row - 1; // -1 because we exclude the top and bottom hotspots
break;
}
}
/* scan along to get the width*/
for(++x_offset; x_offset < font->fttexWidth; x_offset ++)
{
switch (font->fttexBitDepth)
{
default:
GLOBALASSERT(0);
case 8:
colour_here = *(fontstartaddress + (curr_row*pitch + x_offset));
break;
case 16:
colour_here = *(unsigned short *)(fontstartaddress + (curr_row*pitch + 2*x_offset));
break;
case 24:
{
unsigned char * pPixel = fontstartaddress + (curr_row*pitch + 3*x_offset);
// assuming the right endianness
colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16;
break;
}
case 32:
colour_here = *(unsigned *)(fontstartaddress + (curr_row*pitch + 4*x_offset));
break;
}
if(colour_here == font->hotSpotValue)
{
width = x_offset - curr_col - 1; // exclude end hotspot
break;
}
}
*countfromcol = x_offset + 1; /* ready for the next char*/
/*fill in the data structure - platform dependent*/
FillCharacterSlot(u, v, width, height, charnum, font);
return 0;
}
x_offset++;
}
return 0;
}
#if 0 // obsolete
static int Process8BitEntry(PFFONT* font,
char* fontstartaddress,
int* countfromrow,
int* countfromcol,
int charnum)
{
/*
okay set the starting point
countfromrow marks the current depth of the processing row in the texture.
countfromcol marks how far along the current coloum we have processed
* = HOTSPOT .. the first pixel is used as the hotspot
**********************
* ** ** **** * <---- startfromrow
###
#
## # # ###
# # # # # ##
### ### #### ##
* * # * **** * Blank chars marked by two hotspots adjacent
### ^^ |at the top and the bottom
* * || |
^ ||______|
|
|
startfromcol
********************* Note that the spot in col 0 marks a new linw of chars
*/
int curr_row = *countfromrow;
int curr_col = *countfromcol;
int y_offset = 0, x_offset = curr_col;
GLOBALASSERT(font);
GLOBALASSERT(fontstartaddress);
GLOBALASSERT(charnum < font->num_chars_in_font);
GLOBALASSERT(curr_row < font->fttexHeight);
GLOBALASSERT(curr_col <= font->fttexWidth);
/*remember that all the corrdinates are done by pixels
find the x and y corrdinates of the left lower hotspot
we process each line (row) from startfromrow to the end
first find the next marker in startfromrow
*/
while(1)
{
// this bit processes the chars, finds uvs, extents and fills in the sturcture*/
// count along the row to find the next x position
unsigned int colour_here;
if(x_offset > font->fttexWidth - 1)
{
// reached the end of the line! reset x and then y
x_offset = 0;
curr_col = 0;
curr_row += font->fontHeight; // max line height
*countfromrow = curr_row;
GLOBALASSERT(curr_row < font->fttexHeight);
}
colour_here = (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset));
if(colour_here == font->hotSpotValue)
{
int width = -1, height = -1;
/* set up the uv corrds of the top left corner*/
int u = x_offset + 1;
int v = curr_row + 1;
/* scan down to give height*/
for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++)
{
colour_here = (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset));
if(colour_here == font->hotSpotValue)
{
height = y_offset - curr_row - 1; // -1 because we exclude the top and bottom hotspots
break;
}
}
/* scan along to get the width*/
for(++x_offset; x_offset < font->fttexWidth; x_offset ++)
{
colour_here = (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset));
if(colour_here == font->hotSpotValue)
{
width = x_offset - curr_col - 1; // exclude end hotspot
break;
}
}
*countfromcol = x_offset + 1; /* ready for the next char*/
/*fill in the data structure - platform dependent*/
FillCharacterSlot(u, v, width, height, charnum, font);
return 0;
}
x_offset++;
} a
}
static int Process16BitEntry(PFFONT *font,
char* fontstartaddress,
int* countfromrow,
int* countfromcol,
int charnum)
{
int curr_row = *countfromrow;
int curr_col = *countfromcol;
int y_offset = 0, x_offset = curr_col;
GLOBALASSERT(font);
GLOBALASSERT(fontstartaddress);
GLOBALASSERT(charnum < font->num_chars_in_font);
GLOBALASSERT(curr_row < font->fttexHeight);
GLOBALASSERT(curr_col <= font->fttexWidth);
/*remember that all the corrdinates are done by pixels
find the x and y corrdinates of the left lower hotspot
we process each line (row) from startfromrow to the end
first find the next marker in startfromrow
*/
while(1)
{
// this bit processes the chars, finds uvs, extents and fills in the sturcture*/
// count along the row to find the next x position
unsigned int colour_here;
if(x_offset > font->fttexWidth - 1)
{
// reached the end of the line! reset x and then y
x_offset = 0;
curr_col = 0;
curr_row += font->fontHeight; // max line height
*countfromrow = curr_row;
GLOBALASSERT(curr_row < font->fttexHeight);
}
{
unsigned int colour_high = 0x000000ff & (unsigned int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2);
unsigned int colour_low = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2 + 1);
colour_here = (colour_high << 8) | colour_low;
}
if(colour_here == font->hotSpotValue)
{
int width = -1, height = -1;
/* set up the uv corrds of the top left corner*/
int u = x_offset + 1;
int v = curr_row + 1;
/* scan down to give height*/
for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++)
{
{
int colour_high = 0x000000ff & (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)*2);
int colour_low = 0x000000ff & (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)*2 + 1);
colour_here = (colour_high << 8) | colour_low;
}
if(colour_here == font->hotSpotValue)
{
height = y_offset - curr_row - 1; // -1 because we exclude the top and bottom hotspots
break;
}
}
/* scan along to get the width*/
for(++x_offset; x_offset < font->fttexWidth; x_offset ++)
{
{
int colour_high = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2);
int colour_low = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2 + 1);
colour_here = (colour_high << 8) | colour_low;
}
if(colour_here == font->hotSpotValue)
{
width = x_offset - curr_col - 1; // exclude end hotspot
break;
}
}
*countfromcol = x_offset + 1; /* ready for the next char*/
/*fill in the data structure - platform dependent*/
FillCharacterSlot(u, v, width, height, charnum, font);
return 0;
}
x_offset++;
}
return 0;
}
static int Process24BitEntry(PFFONT* font,
char* fontstartaddress,
int* countfromrow,
int* countfromcol,
int charnum)
{
return 0;
}
#endif
void BLTWholeFont(int fontnum, int x , int y, int win_width)
{
int i = 0;
int plotto_x = x, plotto_y = y;
while(i < AvpFonts[fontnum].num_chars_in_font)
{
int charwidth = AvpFonts[fontnum].srcRect[i].right - AvpFonts[fontnum].srcRect[i].left;
if((charwidth + plotto_x - x) > win_width)
{
plotto_y += AvpFonts[fontnum].fontHeight;
plotto_x= x;
}
BLTFontOffsetToHUD(&AvpFonts[fontnum], plotto_x, plotto_y, i);
plotto_x += charwidth + 1;
i++;
}
return;
}
void BLTString(FONT_DESC str_packet)
{
PFFONT font = AvpFonts[str_packet.fontnum];
unsigned char *strptr = str_packet.string;
int offset = 0;
int not_finished = Yes;
int pos_x = str_packet.destx;
int pos_y = str_packet.desty;
int white_space_width = CHAR_WIDTH(str_packet.fontnum, 0);
// set up the font processing varibles depending on the type of font
switch(font.font_type)
{
case(I_FONT_NUMERIC):
{
offset = 0x30;
break;
}
case(I_FONT_UC_NUMERIC):
{
offset = 0x20;
break;
}
case(I_FONT_UCLC_NUMERIC):
{
offset = 0x20;
break;
}
default:
GLOBALASSERT(2<1);
}
while(not_finished)
{
int line_length;
char *end_char;
// find the line length and the end char in the line
not_finished = ProcessLineLength
(
strptr, // start char of string
str_packet.fontnum, // the font we are using
offset, // the offset from the font
str_packet.width, // the width of the line
&end_char, // filled with end address
&line_length // filled with line length
);
// work out where to print the line
if(line_length)
{
switch(str_packet.just)
{
case FJ_LEFT_JUST:
{
pos_x = str_packet.destx;
break;
}
case FJ_CENTRED:
{
pos_x = str_packet.destx + ((str_packet.width - line_length) >> 1);
break;
}
case FJ_RIGHT_JUST:
{
pos_x = str_packet.destx + (str_packet.width - line_length);
break;
}
default:
{
;
}
}
// now print the line untill we reach the address of
// the end char
do
{
if(*strptr == ' ')
{
pos_x += white_space_width;
}
else if(*strptr == '\t')
{
pos_x += 4*white_space_width;
}
else if(*strptr == '\n' || strptr == 0x0)
{
GLOBALASSERT(strptr == end_char);
}
else if((int)*strptr == 0xD)
{
// carrige return
// do nothing - our next char should be '\n'
GLOBALASSERT(*(strptr + 1) == '\n');
}
else
{
extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
int end_pos = pos_x + CHAR_WIDTH(str_packet.fontnum, ((int)*strptr - offset));
int bottom_pos = pos_y + CHAR_HEIGHT(str_packet.fontnum, ((int)*strptr - offset));
if(end_pos > ScreenDescriptorBlock.SDB_Width || pos_x < 0)
{
//dont draw
//not_finished = No;
}
else if( bottom_pos > ScreenDescriptorBlock.SDB_Height || pos_y < 0)
{
not_finished = No;
}
else
{
pos_x += BLTFontOffsetToHUD
(
&font,
pos_x,
pos_y,
(int)*strptr - offset
);
pos_x ++; // to make space between letters
}
}
}
while(++strptr != end_char);
pos_y += font.fontHeight - 2;
}
strptr++;
}
}
/*
RWH - changes to font line processing
This function takes a pointer to a string a font and a width and
puts the length of the line into line_length AND puts the end char address into end_ch
It returns 0 when we have reached the end of a string
*/
int ProcessLineLength
(
char* start_ch, // start char of string
AVP_FONTS fontnum, // the font we are using
int offset, // the offset from the font
int max_width, // the width of the line
char** end_ch, // filled with end address
int* line_length
)
{
int continue_to_process_word = Yes;
int white_space_width = CHAR_WIDTH(fontnum, 0);
char *word_ptr = start_ch;
*line_length = 0;
if(start_ch == NULL)
{
*end_ch = NULL;
*line_length = 0;
return 0;
}
// first process any white space at the end of the
// line out
while(*start_ch == ' ')
{
// make sure we havent run out
// of chars to process
if(*start_ch == 0x0)
{
*end_ch = NULL;
*line_length = 0;
return 0;
}
start_ch++;
}
// Now we can start on the characters in the line
// note that we have to have two loops. The first
// continues untill we break out of it. The second
// adds up the length of each word and sees if the line
// with the new word will overrun the max_width
// the word_ptr points to the current char - it is only incremented
// when we can be sure that we can add the current letter to the word
while(1)
{
int word_length = 0;
continue_to_process_word = Yes;
while(continue_to_process_word)
{
// is the next char white space ?
// if so close the word
if(IS_CHAR_WHITE_SPACE(*(word_ptr + 1)))
{
// hit white space - finish this current word but only
// AFTER we have processed the current char
continue_to_process_word = No;
}
// need to process every white space seperately
if(*word_ptr == '\t')
{
// a one char word!
word_length = 4 * white_space_width;
continue_to_process_word = No;
word_ptr++;
}
else if(*word_ptr == 0x0)
{
// reached end of file - need to return 0
*end_ch = word_ptr;
return 0;
}
else if(*word_ptr == '\n')
{
*end_ch = word_ptr;
return 1;
}
else if(*word_ptr == ' ')
{
if(word_length)
{
// tag on the white space onto the word length
word_length += white_space_width;
}
// other wise keep on tiking on
word_ptr++;
}
else
{
// yeah add a letter to the word length
int char_off = (char)(*word_ptr - offset);
word_length += CHAR_WIDTH(fontnum, char_off);
word_length ++; //for space between lettes
word_ptr++; //process next char
}
}
// okay we have the length of this word - check to see if
// it overruns the end of the line - if it is too long,
// break out of the line loop
if((word_length + *line_length) >= max_width)
{
*end_ch = start_ch;
return 1;
}
else
{
*line_length += word_length;
// set up the next word save the beginning of teh word in start_ch
start_ch = word_ptr;
}
}
}