2023-05-08 14:33:37 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
|
|
|
|
Quake III Arena source code 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 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
// tr_font.c -- font rendering
|
|
|
|
|
|
|
|
#include "tr_local.h"
|
|
|
|
|
2023-05-09 19:13:37 +02:00
|
|
|
#define MAX_LOADED_FONTS 255
|
|
|
|
|
|
|
|
static fontheader_t s_loadedFonts[MAX_LOADED_FONTS];
|
|
|
|
static int s_numLoadedFonts = 0;
|
|
|
|
static float s_fontHeightScale = 1.0;
|
|
|
|
static float s_fontGeneralScale = 1.0;
|
|
|
|
static float s_fontZ = 0.0;;
|
2023-05-08 14:33:37 +02:00
|
|
|
|
|
|
|
void R_SetFontHeightScale(float scale)
|
|
|
|
{
|
2023-05-09 19:13:37 +02:00
|
|
|
s_fontHeightScale = scale;
|
2023-05-08 14:33:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void R_SetFontScale(float scale)
|
|
|
|
{
|
2023-05-09 19:13:37 +02:00
|
|
|
s_fontGeneralScale = scale;
|
2023-05-08 14:33:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void R_SetFontZ(float zed)
|
|
|
|
{
|
2023-05-09 19:13:37 +02:00
|
|
|
s_fontZ = zed;
|
2023-05-08 14:33:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fontheader_t* R_LoadFont(const char* name)
|
|
|
|
{
|
2023-05-09 19:13:37 +02:00
|
|
|
int i;
|
|
|
|
char* theFile;
|
|
|
|
fontheader_t* header;
|
|
|
|
char* ref;
|
|
|
|
const char* token;
|
|
|
|
qboolean error;
|
|
|
|
|
|
|
|
error = qfalse;
|
|
|
|
|
|
|
|
for (i = 0; i < s_numLoadedFonts; i++)
|
|
|
|
{
|
|
|
|
header = &s_loadedFonts[i];
|
|
|
|
if (!Q_stricmp(name, header->name)) {
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_numLoadedFonts >= MAX_LOADED_FONTS)
|
|
|
|
{
|
|
|
|
ri.Printf(PRINT_WARNING, "LoadFont: Too many fonts loaded! Couldn't load %s\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
va("fonts/%s.RitualFont", name);
|
|
|
|
if (ri.FS_ReadFile(va("fonts/%s.RitualFont", name), (void**)&theFile) == -1)
|
|
|
|
{
|
|
|
|
ri.Printf(PRINT_WARNING, "LoadFont: Couldn't load font %s\n", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
header = &s_loadedFonts[s_numLoadedFonts];
|
|
|
|
header->height = 0.0;
|
|
|
|
header->aspectRatio = 0.0;
|
|
|
|
Q_strncpyz(header->name, name, sizeof(header->name));
|
|
|
|
|
|
|
|
ref = theFile;
|
|
|
|
while (ref && !error)
|
|
|
|
{
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (!Q_stricmp(token, "RitFont"))
|
|
|
|
{
|
|
|
|
// ignore this token
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Q_stricmp(token, "indirections"))
|
|
|
|
{
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (Q_stricmp(token, "{"))
|
|
|
|
{
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (!token[0]) {
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
header->indirection[i] = atoi(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (Q_stricmp(token, "}"))
|
|
|
|
{
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!Q_stricmp(token, "locations"))
|
|
|
|
{
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (Q_stricmp(token, "{"))
|
|
|
|
{
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (Q_stricmp(token, "{")) {
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (header->aspectRatio == 0.0)
|
|
|
|
{
|
|
|
|
ri.Printf(PRINT_WARNING, "WARNING: aspect decl must be before locations in font '%s'", name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
header->locations[i].pos[0] = atof(COM_Parse(&ref)) / 256.0;
|
|
|
|
header->locations[i].pos[1] = atof(COM_Parse(&ref)) * header->aspectRatio / 256.0;
|
|
|
|
header->locations[i].size[0] = atof(COM_Parse(&ref)) / 256.0;
|
|
|
|
header->locations[i].size[1] = atof(COM_Parse(&ref)) * header->aspectRatio / 256.0;
|
|
|
|
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (Q_stricmp(token, "}"))
|
|
|
|
{
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
if (Q_stricmp(token, "}"))
|
|
|
|
{
|
|
|
|
error = qtrue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!Q_stricmp(token, "height"))
|
|
|
|
{
|
|
|
|
// parse the header height
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
header->height = atof(token);
|
|
|
|
}
|
|
|
|
else if (!Q_stricmp(token, "aspect"))
|
|
|
|
{
|
|
|
|
// parse the aspect ratio
|
|
|
|
token = COM_Parse(&ref);
|
|
|
|
header->aspectRatio = atof(token);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// unknown token
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (token[0])
|
|
|
|
{
|
|
|
|
ri.Printf(PRINT_WARNING, "WARNING: Unknown token '%s' parsing font '%s'\n", token, name);
|
|
|
|
error = qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_LoadFontShader(header);
|
|
|
|
if (!header->height || !header->aspectRatio) {
|
|
|
|
// invalid height or aspect ratio
|
|
|
|
error = qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ri.FS_FreeFile(theFile);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
ri.Printf(3, "WARNING: Error parsing font %s.\n", name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s_numLoadedFonts++;
|
|
|
|
return header;
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:33:37 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2023-05-08 14:57:51 +02:00
|
|
|
|
2023-05-09 19:13:37 +02:00
|
|
|
void R_LoadFontShader(fontheader_t* font)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int save;
|
|
|
|
char filename[64];
|
|
|
|
shader_t* fontshader;
|
|
|
|
|
|
|
|
save = r_sequencenumber;
|
|
|
|
r_sequencenumber = -1;
|
|
|
|
Com_sprintf(filename, sizeof(filename), "gfx/fonts/%s", font->name);
|
|
|
|
font->shader = R_FindShader(filename, -1, qfalse, qfalse, qfalse, qfalse);
|
|
|
|
r_sequencenumber = save;
|
|
|
|
|
|
|
|
if (!font->shader) {
|
|
|
|
ri.Error(ERR_DROP, "Could not load font shader for %s\n", filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
fontshader = (shader_t*)font->shader;
|
|
|
|
if (fontshader->numUnfoggedPasses > 0)
|
|
|
|
{
|
|
|
|
for (i = 0; i < fontshader->numUnfoggedPasses; i++)
|
|
|
|
{
|
|
|
|
if (fontshader->unfoggedStages[0] != NULL && fontshader->unfoggedStages[0]->active)
|
|
|
|
{
|
|
|
|
fontshader->unfoggedStages[0]->rgbGen = CGEN_GLOBAL_COLOR;
|
|
|
|
fontshader->unfoggedStages[0]->alphaGen = AGEN_GLOBAL_ALPHA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
font->trhandle = r_sequencenumber;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
font->trhandle = r_sequencenumber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:57:51 +02:00
|
|
|
void R_DrawString(const fontheader_t* font, const char* text, float x, float y, int maxlen, qboolean bVirtualScreen) {
|
|
|
|
// FIXME: unimplemented
|
|
|
|
}
|
|
|
|
|
2023-05-09 19:13:37 +02:00
|
|
|
void R_DrawFloatingString(const fontheader_t* font, const char* text, const vec3_t org, const vec4_t color, float scale, int maxlen) {
|
|
|
|
// FIXME: unimplemented
|
|
|
|
}
|
|
|
|
|
2023-05-08 14:57:51 +02:00
|
|
|
float R_GetFontHeight(const fontheader_t* font)
|
|
|
|
{
|
2023-05-09 19:13:37 +02:00
|
|
|
if (!font) {
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return font->height * s_fontGeneralScale * s_fontHeightScale;
|
2023-05-08 14:57:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
float R_GetFontStringWidth(const fontheader_t* font, const char* s)
|
|
|
|
{
|
2023-05-09 19:13:37 +02:00
|
|
|
float widths;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
widths = 0.0;
|
|
|
|
|
|
|
|
if (!font) {
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; s[i]; i++)
|
|
|
|
{
|
|
|
|
int indirected;
|
|
|
|
char c = *s;
|
|
|
|
|
|
|
|
if (c == 9)
|
|
|
|
{
|
|
|
|
indirected = font->indirection[32];
|
|
|
|
if (indirected != -1) {
|
|
|
|
widths += font->locations[indirected].size[0] * 3.0;
|
|
|
|
} else {
|
|
|
|
Com_Printf("R_GetFontStringWidth: no space-character in font!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
indirected = font->indirection[c];
|
|
|
|
if (indirected != -1) {
|
|
|
|
widths += font->locations[indirected].size[0];
|
|
|
|
} else {
|
|
|
|
Com_Printf("R_GetFontStringWidth: no 0x%02x-character in font!\n", c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return widths * s_fontGeneralScale * 256.0;
|
2023-05-08 14:57:51 +02:00
|
|
|
}
|