mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Added missing file.
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
Doom 3 BFG Edition 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Doom 3 BFG Edition 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
||||
|
||||
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "tr_local.h"
|
||||
|
||||
const char* DEFAULT_FONT = "Gothic821_Cn_BT";
|
||||
|
||||
static const float old_scale2 = 0.6f;
|
||||
static const float old_scale1 = 0.3f;
|
||||
|
||||
/*
|
||||
==============================
|
||||
Old_SelectValueForScale
|
||||
==============================
|
||||
*/
|
||||
ID_INLINE float Old_SelectValueForScale(float scale, float v0, float v1, float v2) {
|
||||
return (scale >= old_scale2) ? v2 : (scale >= old_scale1) ? v1 : v0;
|
||||
}
|
||||
|
||||
static void Font_ReadBigInt(idFile *fd, int &value) {
|
||||
fd->Read(&value, sizeof(value));
|
||||
value = BigLong(value);
|
||||
}
|
||||
|
||||
static void Font_ReadBigShort(idFile *fd, short &value) {
|
||||
fd->Read(&value, sizeof(value));
|
||||
value = BigShort(value);
|
||||
}
|
||||
|
||||
static bool Font_ReadTGAHeader(const char* filename, int &width, int &height) {
|
||||
width = 0;
|
||||
height = 0;
|
||||
|
||||
idFile* fd = fileSystem->OpenFileRead(filename);
|
||||
if (fd == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte header[18];
|
||||
const int bytesRead = fd->Read(header, sizeof(header));
|
||||
fileSystem->CloseFile(fd);
|
||||
|
||||
if (bytesRead != sizeof(header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
width = header[12] | (header[13] << 8);
|
||||
height = header[14] | (header[15] << 8);
|
||||
return width > 0 && height > 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
R_NormalizeFontName
|
||||
==============================
|
||||
*/
|
||||
static idStr R_NormalizeFontName(const char* fontName) {
|
||||
idStr cleanName = fontName ? fontName : "";
|
||||
cleanName.StripQuotes();
|
||||
cleanName.BackSlashesToSlashes();
|
||||
cleanName.StripFileExtension();
|
||||
|
||||
if (cleanName.IsEmpty() || cleanName.Icmp("fonts") == 0 || cleanName.Icmp("default") == 0) {
|
||||
return DEFAULT_FONT;
|
||||
}
|
||||
|
||||
const char* newFontPrefix = "newfonts/";
|
||||
if (idStr::Icmpn(cleanName.c_str(), newFontPrefix, strlen(newFontPrefix)) == 0) {
|
||||
idStr rest = cleanName.c_str() + strlen(newFontPrefix);
|
||||
int slash = rest.Find('/');
|
||||
if (slash >= 0) {
|
||||
rest = rest.Left(slash);
|
||||
}
|
||||
return rest.IsEmpty() ? DEFAULT_FONT : rest;
|
||||
}
|
||||
|
||||
cleanName.StripPath();
|
||||
return cleanName.IsEmpty() ? DEFAULT_FONT : cleanName;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idRenderSystemLocal::RegisterFont
|
||||
==============================
|
||||
*/
|
||||
idFont* idRenderSystemLocal::RegisterFont(const char* fontName) {
|
||||
idStr cleanName = R_NormalizeFontName(fontName);
|
||||
|
||||
for (int i = 0; i < fonts.Num(); i++) {
|
||||
if (idStr::Icmp(fonts[i]->GetName(), cleanName.c_str()) == 0) {
|
||||
fonts[i]->Touch();
|
||||
return fonts[i];
|
||||
}
|
||||
}
|
||||
|
||||
idFont* font = new idFont(cleanName.c_str());
|
||||
fonts.Append(font);
|
||||
return font;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idRenderSystemLocal::FreeFonts
|
||||
==============================
|
||||
*/
|
||||
void idRenderSystemLocal::FreeFonts() {
|
||||
fonts.DeleteContents(true);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::RemapFont
|
||||
==============================
|
||||
*/
|
||||
idFont* idFont::RemapFont(const char* baseName) {
|
||||
idStr cleanName = R_NormalizeFontName(baseName);
|
||||
|
||||
if (cleanName.Icmp(DEFAULT_FONT) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::~idFont
|
||||
==============================
|
||||
*/
|
||||
idFont::~idFont() {
|
||||
if (fontInfo != NULL) {
|
||||
Mem_Free(fontInfo->glyphData);
|
||||
Mem_Free(fontInfo->charIndex);
|
||||
delete fontInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::idFont
|
||||
==============================
|
||||
*/
|
||||
idFont::idFont(const char* n) : name(R_NormalizeFontName(n)) {
|
||||
fontInfo = NULL;
|
||||
alias = RemapFont(name.c_str());
|
||||
|
||||
if (alias != NULL) {
|
||||
for (idFont* f = alias; f != NULL; f = f->alias) {
|
||||
if (f == this) {
|
||||
common->FatalError("Font alias \"%s\" is a circular reference!", n);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LoadFont()) {
|
||||
if (name.Icmp(DEFAULT_FONT) == 0) {
|
||||
common->FatalError("Could not load default font \"%s\"", DEFAULT_FONT);
|
||||
}
|
||||
else {
|
||||
common->Warning("Could not load font %s", n);
|
||||
alias = renderSystem->RegisterFont(DEFAULT_FONT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct oldGlyphInfo_t {
|
||||
int height;
|
||||
int top;
|
||||
int bottom;
|
||||
int pitch;
|
||||
int xSkip;
|
||||
int imageWidth;
|
||||
int imageHeight;
|
||||
float s;
|
||||
float t;
|
||||
float s2;
|
||||
float t2;
|
||||
int junk;
|
||||
char materialName[32];
|
||||
};
|
||||
static const int GLYPHS_PER_FONT = 256;
|
||||
|
||||
/*
|
||||
==============================
|
||||
LoadOldGlyphData
|
||||
==============================
|
||||
*/
|
||||
bool LoadOldGlyphData(const char* filename, oldGlyphInfo_t glyphInfo[GLYPHS_PER_FONT]) {
|
||||
idFile* fd = fileSystem->OpenFileRead(filename);
|
||||
if (fd == NULL) {
|
||||
return false;
|
||||
}
|
||||
fd->Read(glyphInfo, GLYPHS_PER_FONT * sizeof(oldGlyphInfo_t));
|
||||
for (int i = 0; i < GLYPHS_PER_FONT; i++) {
|
||||
glyphInfo[i].height = LittleLong(glyphInfo[i].height);
|
||||
glyphInfo[i].top = LittleLong(glyphInfo[i].top);
|
||||
glyphInfo[i].bottom = LittleLong(glyphInfo[i].bottom);
|
||||
glyphInfo[i].pitch = LittleLong(glyphInfo[i].pitch);
|
||||
glyphInfo[i].xSkip = LittleLong(glyphInfo[i].xSkip);
|
||||
glyphInfo[i].imageWidth = LittleLong(glyphInfo[i].imageWidth);
|
||||
glyphInfo[i].imageHeight = LittleLong(glyphInfo[i].imageHeight);
|
||||
glyphInfo[i].s = LittleFloat(glyphInfo[i].s);
|
||||
glyphInfo[i].t = LittleFloat(glyphInfo[i].t);
|
||||
glyphInfo[i].s2 = LittleFloat(glyphInfo[i].s2);
|
||||
glyphInfo[i].t2 = LittleFloat(glyphInfo[i].t2);
|
||||
assert(glyphInfo[i].imageWidth == glyphInfo[i].pitch);
|
||||
assert(glyphInfo[i].imageHeight == glyphInfo[i].height);
|
||||
assert(glyphInfo[i].imageWidth == (glyphInfo[i].s2 - glyphInfo[i].s) * 256);
|
||||
assert(glyphInfo[i].imageHeight == (glyphInfo[i].t2 - glyphInfo[i].t) * 256);
|
||||
assert(glyphInfo[i].junk == 0);
|
||||
}
|
||||
fileSystem->CloseFile(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::LoadFont
|
||||
==============================
|
||||
*/
|
||||
bool idFont::LoadFont() {
|
||||
idStr fontName = va("newfonts/%s/48.dat", GetName());
|
||||
idFile* fd = fileSystem->OpenFileRead(fontName);
|
||||
if (fd == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int FONT_INFO_VERSION = 42;
|
||||
const int FONT_INFO_MAGIC = (FONT_INFO_VERSION | ('i' << 24) | ('d' << 16) | ('f' << 8));
|
||||
|
||||
int version = 0;
|
||||
Font_ReadBigInt(fd, version);
|
||||
if (version != FONT_INFO_MAGIC) {
|
||||
idLib::Warning("Wrong version in %s", GetName());
|
||||
fileSystem->CloseFile(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
fontInfo = new fontInfo_t;
|
||||
memset(fontInfo, 0, sizeof(*fontInfo));
|
||||
|
||||
short pointSize = 0;
|
||||
|
||||
Font_ReadBigShort(fd, pointSize);
|
||||
assert(pointSize == 48);
|
||||
|
||||
Font_ReadBigShort(fd, fontInfo->ascender);
|
||||
Font_ReadBigShort(fd, fontInfo->descender);
|
||||
|
||||
Font_ReadBigShort(fd, fontInfo->numGlyphs);
|
||||
|
||||
fontInfo->glyphData = (glyphInfo_t*)Mem_Alloc(sizeof(glyphInfo_t) * fontInfo->numGlyphs);
|
||||
fontInfo->charIndex = (uint32_t*)Mem_Alloc(sizeof(uint32_t) * fontInfo->numGlyphs);
|
||||
|
||||
const int GLYPH_RECORD_SIZE = 10;
|
||||
for (int i = 0; i < fontInfo->numGlyphs; i++) {
|
||||
byte glyphBytes[GLYPH_RECORD_SIZE];
|
||||
if (fd->Read(glyphBytes, sizeof(glyphBytes)) != sizeof(glyphBytes)) {
|
||||
common->Warning("Short glyph data in %s", fontName.c_str());
|
||||
fileSystem->CloseFile(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
fontInfo->glyphData[i].width = glyphBytes[0];
|
||||
fontInfo->glyphData[i].height = glyphBytes[1];
|
||||
fontInfo->glyphData[i].top = (char)glyphBytes[2];
|
||||
fontInfo->glyphData[i].left = (char)glyphBytes[3];
|
||||
fontInfo->glyphData[i].xSkip = glyphBytes[4];
|
||||
fontInfo->glyphData[i].s = glyphBytes[6] | (glyphBytes[7] << 8);
|
||||
fontInfo->glyphData[i].t = glyphBytes[8] | (glyphBytes[9] << 8);
|
||||
}
|
||||
|
||||
fd->Read(fontInfo->charIndex, fontInfo->numGlyphs * sizeof(uint32_t));
|
||||
for (int i = 0; i < fontInfo->numGlyphs; i++) {
|
||||
fontInfo->charIndex[i] = LittleLong(fontInfo->charIndex[i]);
|
||||
}
|
||||
|
||||
memset(fontInfo->ascii, -1, sizeof(fontInfo->ascii));
|
||||
for (int i = 0; i < fontInfo->numGlyphs; i++) {
|
||||
if (fontInfo->charIndex[i] < 128) {
|
||||
fontInfo->ascii[fontInfo->charIndex[i]] = i;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
idStr fontTextureName = fontName;
|
||||
fontTextureName.SetFileExtension("tga");
|
||||
|
||||
fontInfo->material = declManager->FindMaterial(fontTextureName);
|
||||
fontInfo->material->SetSort(SS_GUI);
|
||||
if (!Font_ReadTGAHeader(fontTextureName.c_str(), fontInfo->materialWidth, fontInfo->materialHeight)) {
|
||||
fontInfo->materialWidth = fontInfo->material->GetImageWidth();
|
||||
fontInfo->materialHeight = fontInfo->material->GetImageHeight();
|
||||
}
|
||||
|
||||
int pointSizes[3] = { 12, 24, 48 };
|
||||
float scales[3] = { 4.0f, 2.0f, 1.0f };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
oldGlyphInfo_t oldGlyphInfo[GLYPHS_PER_FONT];
|
||||
const char* oldFileName = va("newfonts/%s/old_%d.dat", GetName(), pointSizes[i]);
|
||||
if (LoadOldGlyphData(oldFileName, oldGlyphInfo)) {
|
||||
int mh = 0;
|
||||
int mw = 0;
|
||||
for (int g = 0; g < GLYPHS_PER_FONT; g++) {
|
||||
if (mh < oldGlyphInfo[g].height) {
|
||||
mh = oldGlyphInfo[g].height;
|
||||
}
|
||||
if (mw < oldGlyphInfo[g].xSkip) {
|
||||
mw = oldGlyphInfo[g].xSkip;
|
||||
}
|
||||
}
|
||||
fontInfo->oldInfo[i].maxWidth = scales[i] * mw;
|
||||
fontInfo->oldInfo[i].maxHeight = scales[i] * mh;
|
||||
}
|
||||
else {
|
||||
int mh = 0;
|
||||
int mw = 0;
|
||||
for (int g = 0; g < fontInfo->numGlyphs; g++) {
|
||||
if (mh < fontInfo->glyphData[g].height) {
|
||||
mh = fontInfo->glyphData[g].height;
|
||||
}
|
||||
if (mw < fontInfo->glyphData[g].xSkip) {
|
||||
mw = fontInfo->glyphData[g].xSkip;
|
||||
}
|
||||
}
|
||||
fontInfo->oldInfo[i].maxWidth = mw;
|
||||
fontInfo->oldInfo[i].maxHeight = mh;
|
||||
}
|
||||
}
|
||||
fileSystem->CloseFile(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::GetGlyphIndex
|
||||
==============================
|
||||
*/
|
||||
int idFont::GetGlyphIndex(uint32_t idx) const {
|
||||
if (idx < 128) {
|
||||
return fontInfo->ascii[idx];
|
||||
}
|
||||
if (fontInfo->numGlyphs == 0) {
|
||||
return -1;
|
||||
}
|
||||
if (fontInfo->charIndex == NULL) {
|
||||
return idx;
|
||||
}
|
||||
int len = fontInfo->numGlyphs;
|
||||
int mid = fontInfo->numGlyphs;
|
||||
int offset = 0;
|
||||
while (mid > 0) {
|
||||
mid = len >> 1;
|
||||
if (fontInfo->charIndex[offset + mid] <= idx) {
|
||||
offset += mid;
|
||||
}
|
||||
len -= mid;
|
||||
}
|
||||
return (fontInfo->charIndex[offset] == idx) ? offset : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::GetLineHeight
|
||||
==============================
|
||||
*/
|
||||
float idFont::GetLineHeight(float scale) const {
|
||||
if (alias != NULL) {
|
||||
return alias->GetLineHeight(scale);
|
||||
}
|
||||
if (fontInfo != NULL) {
|
||||
return scale * Old_SelectValueForScale(scale, fontInfo->oldInfo[0].maxHeight, fontInfo->oldInfo[1].maxHeight, fontInfo->oldInfo[2].maxHeight);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::GetAscender
|
||||
==============================
|
||||
*/
|
||||
float idFont::GetAscender(float scale) const {
|
||||
if (alias != NULL) {
|
||||
return alias->GetAscender(scale);
|
||||
}
|
||||
if (fontInfo != NULL) {
|
||||
return scale * fontInfo->ascender;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::GetMaxCharWidth
|
||||
==============================
|
||||
*/
|
||||
float idFont::GetMaxCharWidth(float scale) const {
|
||||
if (alias != NULL) {
|
||||
return alias->GetMaxCharWidth(scale);
|
||||
}
|
||||
if (fontInfo != NULL) {
|
||||
return scale * Old_SelectValueForScale(scale, fontInfo->oldInfo[0].maxWidth, fontInfo->oldInfo[1].maxWidth, fontInfo->oldInfo[2].maxWidth);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::GetGlyphWidth
|
||||
==============================
|
||||
*/
|
||||
float idFont::GetGlyphWidth(float scale, uint32_t idx) const {
|
||||
if (alias != NULL) {
|
||||
return alias->GetGlyphWidth(scale, idx);
|
||||
}
|
||||
if (fontInfo != NULL) {
|
||||
int i = GetGlyphIndex(idx);
|
||||
const int asterisk = 42;
|
||||
if (i == -1 && idx != asterisk) {
|
||||
i = GetGlyphIndex(asterisk);
|
||||
}
|
||||
if (i >= 0) {
|
||||
return scale * fontInfo->glyphData[i].xSkip;
|
||||
}
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::GetScaledGlyph
|
||||
==============================
|
||||
*/
|
||||
void idFont::GetScaledGlyph(float scale, uint32_t idx, scaledGlyphInfo_t& glyphInfo) const {
|
||||
if (alias != NULL) {
|
||||
return alias->GetScaledGlyph(scale, idx, glyphInfo);
|
||||
}
|
||||
if (fontInfo != NULL) {
|
||||
int i = GetGlyphIndex(idx);
|
||||
const int asterisk = 42;
|
||||
if (i == -1 && idx != asterisk) {
|
||||
i = GetGlyphIndex(asterisk);
|
||||
}
|
||||
if (i >= 0) {
|
||||
float invMaterialWidth = 1.0f / fontInfo->materialWidth;
|
||||
float invMaterialHeight = 1.0f / fontInfo->materialHeight;
|
||||
glyphInfo_t& gi = fontInfo->glyphData[i];
|
||||
glyphInfo.xSkip = scale * gi.xSkip;
|
||||
glyphInfo.top = scale * gi.top;
|
||||
glyphInfo.left = scale * gi.left;
|
||||
glyphInfo.width = scale * gi.width;
|
||||
glyphInfo.height = scale * gi.height;
|
||||
glyphInfo.s1 = (gi.s - 0.5f) * invMaterialWidth;
|
||||
glyphInfo.t1 = (gi.t - 0.5f) * invMaterialHeight;
|
||||
glyphInfo.s2 = (gi.s + gi.width + 0.5f) * invMaterialWidth;
|
||||
glyphInfo.t2 = (gi.t + gi.height + 0.5f) * invMaterialHeight;
|
||||
glyphInfo.material = fontInfo->material;
|
||||
return;
|
||||
}
|
||||
}
|
||||
memset(&glyphInfo, 0, sizeof(glyphInfo));
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
idFont::Touch
|
||||
==============================
|
||||
*/
|
||||
void idFont::Touch() {
|
||||
if (alias != NULL) {
|
||||
alias->Touch();
|
||||
}
|
||||
if (fontInfo != NULL) {
|
||||
const_cast<idMaterial*>(fontInfo->material)->EnsureNotPurged();
|
||||
fontInfo->material->SetSort(SS_GUI);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user