From 966751b7e84656ebe536fa7494a63ed99bf58d95 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 24 Oct 2019 01:20:58 +0200 Subject: [PATCH] - added GZDoom's font code and some dependencies. --- source/CMakeLists.txt | 20 +- source/build/src/sdlayer.cpp | 37 +- source/common/2d/v_draw.h | 1 + source/common/2d/v_drawtext.cpp | 10 +- source/common/2d/v_text.h | 32 - source/common/fonts/font.cpp | 839 +++++++++++++++++++ source/common/fonts/fontchars.cpp | 231 ++++++ source/common/fonts/fontchars.h | 32 + source/common/fonts/fontinternals.h | 46 ++ source/common/fonts/hexfont.cpp | 436 ++++++++++ source/common/fonts/myiswalpha.h | 524 ++++++++++++ source/common/fonts/singlelumpfont.cpp | 630 ++++++++++++++ source/common/fonts/v_font.cpp | 972 ++++++++++++++++++++++ source/common/fonts/v_font.h | 209 +++++ source/common/fonts/v_text.cpp | 170 ++++ source/common/fonts/v_text.h | 89 ++ source/common/textures/texture.cpp | 5 - source/common/utility/name.cpp | 288 +++++++ source/common/utility/name.h | 125 +++ source/common/utility/namedef.h | 6 + source/common/utility/palentry.h | 6 + source/common/utility/printf.h | 75 +- source/common/utility/sc_man.cpp | 1006 +++++++++++++++++++++++ source/common/utility/sc_man.h | 141 ++++ source/common/utility/sc_man_scanner.re | 389 +++++++++ source/common/utility/sc_man_tokens.h | 146 ++++ source/duke3d/src/screens.cpp | 1 - source/sw/src/config.cpp | 1 - source/sw/src/sector.cpp | 2 + 29 files changed, 6342 insertions(+), 127 deletions(-) create mode 100644 source/common/fonts/font.cpp create mode 100644 source/common/fonts/fontchars.cpp create mode 100644 source/common/fonts/fontchars.h create mode 100644 source/common/fonts/fontinternals.h create mode 100644 source/common/fonts/hexfont.cpp create mode 100644 source/common/fonts/myiswalpha.h create mode 100644 source/common/fonts/singlelumpfont.cpp create mode 100644 source/common/fonts/v_font.cpp create mode 100644 source/common/fonts/v_font.h create mode 100644 source/common/fonts/v_text.cpp create mode 100644 source/common/fonts/v_text.h create mode 100644 source/common/utility/name.cpp create mode 100644 source/common/utility/name.h create mode 100644 source/common/utility/namedef.h create mode 100644 source/common/utility/sc_man.cpp create mode 100644 source/common/utility/sc_man.h create mode 100644 source/common/utility/sc_man_scanner.re create mode 100644 source/common/utility/sc_man_tokens.h diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 9260c0e25..f72109512 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -580,12 +580,10 @@ else() endif( NOT NO_OPENMP ) endif() -if (FALSE) # for later add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h - COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/utility/sc_man_scanner.re - DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/utility/sc_man_scanner.re ) + COMMAND re2c --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/common/utility/sc_man_scanner.re + DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/common/utility/sc_man_scanner.re ) -endif () include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) @@ -637,6 +635,7 @@ file( GLOB HEADER_FILES mact/src/*.h common/*.h common/2d/*.h + common/fonts/*.h common/utility/*.h common/console/*.h @@ -653,8 +652,8 @@ file( GLOB HEADER_FILES set( NOT_COMPILED_SOURCE_FILES ${OTHER_SYSTEM_SOURCES} build/src/sdlkeytrans.cpp - #sc_man_scanner.h - #utility/sc_man_scanner.re + sc_man_scanner.h + common/utility/sc_man_scanner.re ) @@ -795,8 +794,16 @@ set (PCH_SOURCES common/2d/v_drawtext.cpp common/2d/renderstyle.cpp + common/fonts/font.cpp + common/fonts/hexfont.cpp + common/fonts/singlelumpfont.cpp + common/fonts/v_font.cpp + common/fonts/v_text.cpp + common/fonts/fontchars.cpp + common/console/c_cvars.cpp + common/utility/name.cpp common/utility/cmdlib.cpp common/utility/m_argv.cpp common/utility/files.cpp @@ -811,6 +818,7 @@ set (PCH_SOURCES common/utility/matrix.cpp common/utility/m_png.cpp common/utility/memarena.cpp + common/utility/sc_man.cpp common/textures/bitmap.cpp common/textures/buildtiles.cpp diff --git a/source/build/src/sdlayer.cpp b/source/build/src/sdlayer.cpp index aeca93fb4..790c6f201 100644 --- a/source/build/src/sdlayer.cpp +++ b/source/build/src/sdlayer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include # include "glad/glad.h" #include "a.h" @@ -123,6 +124,32 @@ static mutex_t m_initprintf; // Joystick dead and saturation zones uint16_t joydead[9], joysatur[9]; +#define MAX_ERRORTEXT 4096 + +//========================================================================== +// +// I_Error +// +// Throw an error that will send us to the console if we are far enough +// along in the startup process. +// +//========================================================================== + +void I_Error(const char *error, ...) +{ + va_list argptr; + char errortext[MAX_ERRORTEXT]; + + va_start(argptr, error); + snprintf(errortext, MAX_ERRORTEXT, error, argptr); + va_end(argptr); + #ifdef _WIN32 + OutputDebugStringA(errortext); + #endif + + throw std::runtime_error(errortext); +} + #ifdef _WIN32 # if SDL_MAJOR_VERSION != 1 // @@ -511,6 +538,8 @@ int WINAPI WinMain(HINSTANCE , HINSTANCE , LPSTR , int ) int main(int argc, char *argv[]) #endif { + try + { #ifdef _WIN32 char* argvbuf; @@ -576,8 +605,14 @@ int main(int argc, char *argv[]) #if defined(HAVE_GTK2) gtkbuild_exit(r); #endif + return r; + } + catch(std::runtime_error &err) + { + wm_msgbox("Error", "%s", err.what()); + return 3; + } - return r; } diff --git a/source/common/2d/v_draw.h b/source/common/2d/v_draw.h index c8f79461c..270d8a4f2 100644 --- a/source/common/2d/v_draw.h +++ b/source/common/2d/v_draw.h @@ -1,5 +1,6 @@ #pragma once +#include "drawparms.h" struct ScreenDummy { static int GetWidth() { return 1360; } diff --git a/source/common/2d/v_drawtext.cpp b/source/common/2d/v_drawtext.cpp index 213914941..150d69f61 100644 --- a/source/common/2d/v_drawtext.cpp +++ b/source/common/2d/v_drawtext.cpp @@ -44,9 +44,10 @@ #include "v_draw.h" #include "image.h" #include "v_2ddrawer.h" +#include "../fonts/v_font.h" class FFont; -int NumTextColors; + //========================================================================== // // Internal texture drawing function @@ -88,7 +89,6 @@ void DrawChar (F2DDrawer* drawer, FFont *font, int normalcolor, double x, double int dummy; bool redirected; -#if 0 if (NULL != (pic = font->GetChar (character, normalcolor, &dummy, &redirected))) { DrawParms parms; @@ -101,11 +101,9 @@ void DrawChar (F2DDrawer* drawer, FFont *font, int normalcolor, double x, double return; } PalEntry color = 0xffffffff; - parms.remap = redirected? nullptr : font->GetColorTranslation((EColorRange)normalcolor, &color); parms.color = PalEntry((color.a * parms.color.a) / 255, (color.r * parms.color.r) / 255, (color.g * parms.color.g) / 255, (color.b * parms.color.b) / 255); drawer->AddTexture(pic, parms); } -#endif } //========================================================================== @@ -122,7 +120,6 @@ EColorRange V_ParseFontColor(const char32_t *&color_value, int normalcolor, int template void DrawTextCommon(F2DDrawer* drawer, FFont *font, int normalcolor, double x, double y, const chartype *string, DrawParms &parms) { -#if 0 int w; const chartype *ch; int c; @@ -186,7 +183,6 @@ void DrawTextCommon(F2DDrawer* drawer, FFont *font, int normalcolor, double x, d bool redirected = false; if (NULL != (pic = font->GetChar(c, currentcolor, &w, &redirected))) { - parms.remap = redirected? nullptr : range; SetTextureParms(&parms, pic, cx, cy); if (parms.cellx) { @@ -211,9 +207,7 @@ void DrawTextCommon(F2DDrawer* drawer, FFont *font, int normalcolor, double x, d { cx += (parms.spacing) * parms.scalex; } - } -#endif } void DrawText(F2DDrawer* drawer, FFont *font, int normalcolor, double x, double y, const char *string, int tag_first, ...) diff --git a/source/common/2d/v_text.h b/source/common/2d/v_text.h index 90e5401d5..d5bba3b05 100644 --- a/source/common/2d/v_text.h +++ b/source/common/2d/v_text.h @@ -80,38 +80,6 @@ struct FBrokenLines #define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_TEAMCHAT "\034!" -enum EColorRange : int -{ - CR_UNDEFINED = -1, - CR_BRICK, - CR_TAN, - CR_GRAY, - CR_GREY = CR_GRAY, - CR_GREEN, - CR_BROWN, - CR_GOLD, - CR_RED, - CR_BLUE, - CR_ORANGE, - CR_WHITE, - CR_YELLOW, - CR_UNTRANSLATED, - CR_BLACK, - CR_LIGHTBLUE, - CR_CREAM, - CR_OLIVE, - CR_DARKGREEN, - CR_DARKRED, - CR_DARKBROWN, - CR_PURPLE, - CR_DARKGRAY, - CR_CYAN, - CR_ICE, - CR_FIRE, - CR_SAPPHIRE, - CR_TEAL, - NUM_TEXT_COLORS, -}; extern int NumTextColors; diff --git a/source/common/fonts/font.cpp b/source/common/fonts/font.cpp new file mode 100644 index 000000000..bc913a83d --- /dev/null +++ b/source/common/fonts/font.cpp @@ -0,0 +1,839 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include + +#include "templates.h" +#include "m_swap.h" +#include "v_font.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "v_text.h" +#include "image.h" +#include "utf8.h" +#include "myiswalpha.h" +#include "fontchars.h" +#include "imagehelpers.h" + +#include "fontinternals.h" + + + +//========================================================================== +// +// FFont :: ~FFont +// +//========================================================================== + +FFont::~FFont () +{ + FFont **prev = &FirstFont; + FFont *font = *prev; + + while (font != nullptr && font != this) + { + prev = &font->Next; + font = *prev; + } + + if (font != nullptr) + { + *prev = font->Next; + } +} + +//========================================================================== +// +// FFont :: CheckCase +// +//========================================================================== + +void FFont::CheckCase() +{ + int lowercount = 0, uppercount = 0; + for (unsigned i = 0; i < Chars.Size(); i++) + { + unsigned chr = i + FirstChar; + if (lowerforupper[chr] == chr && upperforlower[chr] == chr) + { + continue; // not a letter; + } + if (myislower(chr)) + { + if (Chars[i].TranslatedPic != nullptr) lowercount++; + } + else + { + if (Chars[i].TranslatedPic != nullptr) uppercount++; + } + } + if (lowercount == 0) return; // This is an uppercase-only font and we are done. + + // The ß needs special treatment because it is far more likely to be supplied lowercase only, even in an uppercase font. + if (Chars[0xdf - FirstChar].TranslatedPic != nullptr) + { + if (LastChar < 0x1e9e) + { + Chars.Resize(0x1e9f - FirstChar); + LastChar = 0x1e9e; + } + if (Chars[0x1e9e - FirstChar].TranslatedPic == nullptr) + { + std::swap(Chars[0xdf - FirstChar], Chars[0x1e9e - FirstChar]); + lowercount--; + uppercount++; + if (lowercount == 0) return; + } + } +} + +//========================================================================== +// +// FFont :: FindFont +// +// Searches for the named font in the list of loaded fonts, returning the +// font if it was found. The disk is not checked if it cannot be found. +// +//========================================================================== + +FFont *FFont::FindFont (FName name) +{ + if (name == NAME_None) + { + return nullptr; + } + FFont *font = FirstFont; + + while (font != nullptr) + { + if (font->FontName == name) return font; + font = font->Next; + } + return nullptr; +} + +//========================================================================== +// +// RecordTextureColors +// +// Given a 256 entry buffer, sets every entry that corresponds to a color +// used by the texture to 1. +// +//========================================================================== + +void RecordTextureColors (FTexture *pic, uint32_t *usedcolors) +{ + auto size = pic->GetWidth() * pic->GetHeight(); + TArray pixels(size, 1); + int x; + + pic->Create8BitPixels(pixels.Data()); + + for(x = 0;x < size; x++) + { + usedcolors[pixels[x]]++; + } +} + +//========================================================================== +// +// RecordAllTextureColors +// +// Given a 256 entry buffer, sets every entry that corresponds to a color +// used by the font. +// +//========================================================================== + +void FFont::RecordAllTextureColors(uint32_t *usedcolors) +{ + for (unsigned int i = 0; i < Chars.Size(); i++) + { + if (Chars[i].TranslatedPic) + { + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic); + if (pic) + { + // The remap must be temporarily reset here because this can be called on an initialized font. + auto sr = pic->ResetSourceRemap(); + RecordTextureColors(pic, usedcolors); + pic->SetSourceRemap(sr); + } + } + } +} + +//========================================================================== +// +// SetDefaultTranslation +// +// Builds a translation to map the stock font to a mod provided replacement. +// +//========================================================================== + +void FFont::SetDefaultTranslation(uint32_t *othercolors) +{ + uint32_t mycolors[256] = {}; + RecordAllTextureColors(mycolors); + + uint8_t mytranslation[256], othertranslation[256], myreverse[256], otherreverse[256]; + TArray myluminosity, otherluminosity; + + SimpleTranslation(mycolors, mytranslation, myreverse, myluminosity); + SimpleTranslation(othercolors, othertranslation, otherreverse, otherluminosity); + + FRemapTable remap(ActiveColors); + remap.Palette[0] = 0; + + for (unsigned l = 1; l < myluminosity.Size(); l++) + { + for (unsigned o = 1; o < otherluminosity.Size()-1; o++) // luminosity[0] is for the transparent color + { + if (myluminosity[l] >= otherluminosity[o] && myluminosity[l] <= otherluminosity[o+1]) + { + PalEntry color1 = ImageHelpers::BasePalette[otherreverse[o]]; + PalEntry color2 = ImageHelpers::BasePalette[otherreverse[o+1]]; + double weight = 0; + if (otherluminosity[o] != otherluminosity[o + 1]) + { + weight = (myluminosity[l] - otherluminosity[o]) / (otherluminosity[o + 1] - otherluminosity[o]); + } + int r = int(color1.r + weight * (color2.r - color1.r)); + int g = int(color1.g + weight * (color2.g - color1.g)); + int b = int(color1.b + weight * (color2.b - color1.b)); + + r = clamp(r, 0, 255); + g = clamp(g, 0, 255); + b = clamp(b, 0, 255); + remap.Palette[l] = PalEntry(255, r, g, b); + break; + } + } + } + Ranges[CR_UNTRANSLATED] = remap; + forceremap = true; +} + + +//========================================================================== +// +// compare +// +// Used for sorting colors by brightness. +// +//========================================================================== + +static int compare (const void *arg1, const void *arg2) +{ + if (RPART(ImageHelpers::BasePalette[*((uint8_t *)arg1)]) * 299 + + GPART(ImageHelpers::BasePalette[*((uint8_t *)arg1)]) * 587 + + BPART(ImageHelpers::BasePalette[*((uint8_t *)arg1)]) * 114 < + RPART(ImageHelpers::BasePalette[*((uint8_t *)arg2)]) * 299 + + GPART(ImageHelpers::BasePalette[*((uint8_t *)arg2)]) * 587 + + BPART(ImageHelpers::BasePalette[*((uint8_t *)arg2)]) * 114) + return -1; + else + return 1; +} + +//========================================================================== +// +// FFont :: SimpleTranslation +// +// Colorsused, translation, and reverse must all be 256 entry buffers. +// Colorsused must already be filled out. +// Translation be set to remap the source colors to a new range of +// consecutive colors based at 1 (0 is transparent). +// Reverse will be just the opposite of translation: It maps the new color +// range to the original colors. +// *Luminosity will be an array just large enough to hold the brightness +// levels of all the used colors, in consecutive order. It is sorted from +// darkest to lightest and scaled such that the darkest color is 0.0 and +// the brightest color is 1.0. +// The return value is the number of used colors and thus the number of +// entries in *luminosity. +// +//========================================================================== + +int FFont::SimpleTranslation (uint32_t *colorsused, uint8_t *translation, uint8_t *reverse, TArray &Luminosity) +{ + double min, max, diver; + int i, j; + + memset (translation, 0, 256); + + reverse[0] = 0; + for (i = 1, j = 1; i < 256; i++) + { + if (colorsused[i]) + { + reverse[j++] = i; + } + } + + qsort (reverse+1, j-1, 1, compare); + + Luminosity.Resize(j); + Luminosity[0] = 0.0; // [BL] Prevent uninitalized memory + max = 0.0; + min = 100000000.0; + for (i = 1; i < j; i++) + { + translation[reverse[i]] = i; + + Luminosity[i] = RPART(ImageHelpers::BasePalette[reverse[i]]) * 0.299 + + GPART(ImageHelpers::BasePalette[reverse[i]]) * 0.587 + + BPART(ImageHelpers::BasePalette[reverse[i]]) * 0.114; + if (Luminosity[i] > max) + max = Luminosity[i]; + if (Luminosity[i] < min) + min = Luminosity[i]; + } + diver = 1.0 / (max - min); + for (i = 1; i < j; i++) + { + Luminosity[i] = (Luminosity[i] - min) * diver; + } + + return j; +} + +//========================================================================== +// +// FFont :: BuildTranslations +// +// Build color translations for this font. Luminosity is an array of +// brightness levels. The ActiveColors member must be set to indicate how +// large this array is. Identity is an array that remaps the colors to +// their original values; it is only used for CR_UNTRANSLATED. Ranges +// is an array of TranslationParm structs defining the ranges for every +// possible color, in order. Palette is the colors to use for the +// untranslated version of the font. +// +//========================================================================== + +void FFont::BuildTranslations (const double *luminosity, const uint8_t *identity, + const void *ranges, int total_colors, const PalEntry *palette) +{ + int i, j; + const TranslationParm *parmstart = (const TranslationParm *)ranges; + + FRemapTable remap(total_colors); + + // Create different translations for different color ranges + Ranges.Clear(); + for (i = 0; i < NumTextColors; i++) + { + if (i == CR_UNTRANSLATED) + { + if (identity != nullptr) + { + if (palette != nullptr) + { + memcpy (remap.Palette, palette, ActiveColors*sizeof(PalEntry)); + } + else + { + remap.Palette[0] = ImageHelpers::BasePalette[identity[0]] & MAKEARGB(0,255,255,255); + for (j = 1; j < ActiveColors; ++j) + { + remap.Palette[j] = ImageHelpers::BasePalette[identity[j]] | MAKEARGB(255,0,0,0); + } + } + } + else + { + remap = Ranges[0]; + } + Ranges.Push(remap); + continue; + } + + assert(parmstart->RangeStart >= 0); + + remap.Palette[255] = 0; + + for (j = 0; j < ActiveColors; j++) + { + int v = int(luminosity[j] * 256.0); + + // Find the color range that this luminosity value lies within. + const TranslationParm *parms = parmstart - 1; + do + { + parms++; + if (parms->RangeStart <= v && parms->RangeEnd >= v) + break; + } + while (parms[1].RangeStart > parms[0].RangeEnd); + + // Linearly interpolate to find out which color this luminosity level gets. + int rangev = ((v - parms->RangeStart) << 8) / (parms->RangeEnd - parms->RangeStart); + int r = ((parms->Start[0] << 8) + rangev * (parms->End[0] - parms->Start[0])) >> 8; // red + int g = ((parms->Start[1] << 8) + rangev * (parms->End[1] - parms->Start[1])) >> 8; // green + int b = ((parms->Start[2] << 8) + rangev * (parms->End[2] - parms->Start[2])) >> 8; // blue + r = clamp(r, 0, 255); + g = clamp(g, 0, 255); + b = clamp(b, 0, 255); + remap.Palette[j] = PalEntry(255,r,g,b); + } + Ranges.Push(remap); + + // Advance to the next color range. + while (parmstart[1].RangeStart > parmstart[0].RangeEnd) + { + parmstart++; + } + parmstart++; + } +} + +//========================================================================== +// +// FFont :: GetColorTranslation +// +//========================================================================== + +FRemapTable *FFont::GetColorTranslation (EColorRange range, PalEntry *color) const +{ + if (noTranslate) + { + PalEntry retcolor = PalEntry(255, 255, 255, 255); + if (range >= 0 && range < NumTextColors && range != CR_UNTRANSLATED) + { + retcolor = TranslationColors[range]; + retcolor.a = 255; + } + if (color != nullptr) *color = retcolor; + } + if (ActiveColors == 0) + return nullptr; + else if (range >= NumTextColors) + range = CR_UNTRANSLATED; + //if (range == CR_UNTRANSLATED && !translateUntranslated) return nullptr; + return &Ranges[range]; +} + +//========================================================================== +// +// FFont :: GetCharCode +// +// If the character code is in the font, returns it. If it is not, but it +// is lowercase and has an uppercase variant present, return that. Otherwise +// return -1. +// +//========================================================================== + +int FFont::GetCharCode(int code, bool needpic) const +{ + if (code < 0 && code >= -128) + { + // regular chars turn negative when the 8th bit is set. + code &= 255; + } + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) + { + return code; + } + + // Use different substitution logic based on the fonts content: + // In a font which has both upper and lower case, prefer unaccented small characters over capital ones. + // In a pure upper-case font, do not check for lower case replacements. + if (!MixedCase) + { + // Try converting lowercase characters to uppercase. + if (myislower(code)) + { + code = upperforlower[code]; + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) + { + return code; + } + } + // Try stripping accents from accented characters. + int newcode = stripaccent(code); + if (newcode != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) + { + return code; + } + } + } + else + { + int originalcode = code; + int newcode; + + // Try stripping accents from accented characters. This may repeat to allow multi-step fallbacks. + while ((newcode = stripaccent(code)) != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) + { + return code; + } + } + + code = originalcode; + if (myislower(code)) + { + int upper = upperforlower[code]; + // Stripping accents did not help - now try uppercase for lowercase + if (upper != code) return GetCharCode(upper, needpic); + } + + // Same for the uppercase character. Since we restart at the accented version this must go through the entire thing again. + while ((newcode = stripaccent(code)) != code) + { + code = newcode; + if (code >= FirstChar && code <= LastChar && (!needpic || Chars[code - FirstChar].TranslatedPic != nullptr)) + { + return code; + } + } + + } + + return -1; +} + +//========================================================================== +// +// FFont :: GetChar +// +//========================================================================== + +FTexture *FFont::GetChar (int code, int translation, int *const width, bool *redirected) const +{ + code = GetCharCode(code, true); + int xmove = SpaceWidth; + + if (code >= 0) + { + code -= FirstChar; + xmove = Chars[code].XMove; + } + + if (width != nullptr) + { + *width = xmove; + } + if (code < 0) return nullptr; + + + if (translation == CR_UNTRANSLATED && !forceremap) + { + bool redirect = Chars[code].OriginalPic && Chars[code].OriginalPic != Chars[code].TranslatedPic; + if (redirected) *redirected = redirect; + if (redirect) + { + return Chars[code].OriginalPic; + } + } + if (redirected) *redirected = false; + return Chars[code].TranslatedPic; +} + +//========================================================================== +// +// FFont :: GetCharWidth +// +//========================================================================== + +int FFont::GetCharWidth (int code) const +{ + code = GetCharCode(code, true); + if (code >= 0) return Chars[code - FirstChar].XMove; + return SpaceWidth; +} + +//========================================================================== +// +// +// +//========================================================================== + +double GetBottomAlignOffset(FFont *font, int c) +{ + int w; + FTexture *tex_zero = font->GetChar('0', CR_UNDEFINED, &w); + FTexture *texc = font->GetChar(c, CR_UNDEFINED, &w); + double offset = 0; + if (texc) offset += texc->GetTopOffset(); + if (tex_zero) offset += -tex_zero->GetTopOffset() + tex_zero->GetHeight(); + return offset; +} + +//========================================================================== +// +// Checks if the font contains proper glyphs for all characters in the string +// +//========================================================================== + +bool FFont::CanPrint(const uint8_t *string) const +{ + if (!string) return true; + while (*string) + { + auto chr = GetCharFromString(string); + if (!MixedCase) chr = upperforlower[chr]; // For uppercase-only fonts we shouldn't check lowercase characters. + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr != '\n') + { + int cc = GetCharCode(chr, true); + if (chr != cc && myiswalpha(chr))// && cc != getAlternative(chr)) + { + return false; + } + } + } + + return true; +} + +//========================================================================== +// +// Find string width using this font +// +//========================================================================== + +int FFont::StringWidth(const uint8_t *string) const +{ + int w = 0; + int maxw = 0; + + while (*string) + { + auto chr = GetCharFromString(string); + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr == '\n') + { + if (w > maxw) + maxw = w; + w = 0; + } + else + { + w += GetCharWidth(chr) + GlobalKerning; + } + } + + return std::max(maxw, w); +} + +//========================================================================== +// +// Get the largest ascender in the first line of this text. +// +//========================================================================== + +int FFont::GetMaxAscender(const uint8_t* string) const +{ + int retval = 0; + + while (*string) + { + auto chr = GetCharFromString(string); + if (chr == TEXTCOLOR_ESCAPE) + { + // We do not need to check for UTF-8 in here. + if (*string == '[') + { + while (*string != '\0' && *string != ']') + { + ++string; + } + } + if (*string != '\0') + { + ++string; + } + continue; + } + else if (chr == '\n') + { + break; + } + else + { + auto ctex = GetChar(chr, CR_UNTRANSLATED, nullptr); + if (ctex) + { + auto offs = int(ctex->GetTopOffset()); + if (offs > retval) retval = offs; + } + } + } + + return retval; +} + +//========================================================================== +// +// FFont :: LoadTranslations +// +//========================================================================== + +void FFont::LoadTranslations() +{ + unsigned int count = LastChar - FirstChar + 1; + uint32_t usedcolors[256] = {}; + uint8_t identity[256]; + TArray Luminosity; + + for (unsigned int i = 0; i < count; i++) + { + if (Chars[i].TranslatedPic) + { + FFontChar1 *pic = static_cast(Chars[i].TranslatedPic); + if (pic) + { + pic->SetSourceRemap(nullptr); // Force the FFontChar1 to return the same pixels as the base texture + RecordTextureColors(pic, usedcolors); + } + } + } + + ActiveColors = SimpleTranslation (usedcolors, PatchRemap, identity, Luminosity); + + for (unsigned int i = 0; i < count; i++) + { + if(Chars[i].TranslatedPic) + static_cast(Chars[i].TranslatedPic)->SetSourceRemap(PatchRemap); + } + + BuildTranslations (Luminosity.Data(), identity, &TranslationParms[TranslationType][0], ActiveColors, nullptr); +} + +//========================================================================== +// +// FFont :: FFont - default constructor +// +//========================================================================== + +FFont::FFont () +{ + FontName = NAME_None; + Cursor = '_'; + noTranslate = false; + uint8_t pp = 0; + for (auto &p : PatchRemap) p = pp++; +} + +//========================================================================== +// +// FFont :: FixXMoves +// +// If a font has gaps in its characters, set the missing characters' +// XMoves to either SpaceWidth or the unaccented or uppercase variant's +// XMove. Missing XMoves must be initialized with INT_MIN beforehand. +// +//========================================================================== + +void FFont::FixXMoves() +{ + for (int i = 0; i <= LastChar - FirstChar; ++i) + { + if (Chars[i].XMove == INT_MIN) + { + // Try an uppercase character. + if (myislower(i + FirstChar)) + { + int upper = upperforlower[FirstChar + i]; + if (upper >= FirstChar && upper <= LastChar ) + { + Chars[i].XMove = Chars[upper - FirstChar].XMove; + continue; + } + } + // Try an unnaccented character. + int noaccent = stripaccent(i + FirstChar); + if (noaccent != i + FirstChar) + { + noaccent -= FirstChar; + if (noaccent >= 0) + { + Chars[i].XMove = Chars[noaccent].XMove; + continue; + } + } + Chars[i].XMove = SpaceWidth; + } + if (Chars[i].OriginalPic) + { + int ofs = Chars[i].OriginalPic->GetTopOffset(); + if (ofs > Displacement) Displacement = ofs; + } + } +} + + diff --git a/source/common/fonts/fontchars.cpp b/source/common/fonts/fontchars.cpp new file mode 100644 index 000000000..3298c5212 --- /dev/null +++ b/source/common/fonts/fontchars.cpp @@ -0,0 +1,231 @@ +/* +** fontchars.cpp +** Texture class for font characters +** +**--------------------------------------------------------------------------- +** Copyright 2004-2006 Randy Heit +** Copyright 2006-2018 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "cache1d.h" +#include "bitmap.h" +#include "image.h" +#include "imagehelpers.h" +#include "fontchars.h" +#include "printf.h" + +//========================================================================== +// +// FFontChar1 :: FFontChar1 +// +// Used by fonts made from textures. +// +//========================================================================== + +FFontChar1::FFontChar1 (FTexture *sourcelump) +: BaseTexture(sourcelump), SourceRemap (nullptr) +{ + // now copy all the properties from the base texture + assert(BaseTexture != nullptr); + CopySize(BaseTexture); +} + +//========================================================================== +// +// FFontChar1 :: GetPixels +// +// Render style is not relevant for fonts. This must not use it! +// +//========================================================================== + +void FFontChar1::Create8BitPixels (uint8_t *data) +{ + // Make the texture as normal, then remap it so that all the colors + // are at the low end of the palette + // Why? It only creates unnecessary work! + BaseTexture->Create8BitPixels(data); + + if (SourceRemap) + { + for (int x = 0; x < GetWidth() * GetHeight(); ++x) + { + data[x] = SourceRemap[data[x]]; + } + } +} + +//========================================================================== +// +// FFontChar2 :: FFontChar2 +// +// Used by FON1 and FON2 fonts. +// +//========================================================================== + +FFontChar2::FFontChar2 (const char *sourcelump, int sourcepos, int width, int height, int leftofs, int topofs) +: SourceLump (sourcelump), SourcePos (sourcepos), SourceRemap(nullptr) +{ + Size.x = width; + Size.y = height; + PicAnim.xofs = leftofs; + PicAnim.yofs = topofs; +} + +//========================================================================== +// +// FFontChar2 :: SetSourceRemap +// +//========================================================================== + +void FFontChar2::SetSourceRemap(const uint8_t *sourceremap) +{ + SourceRemap = sourceremap; +} + +//========================================================================== +// +// FFontChar2 :: Get8BitPixels +// +// Like for FontChar1, the render style has no relevance here as well. +// +//========================================================================== + +void FFontChar2::Create8BitPixels(uint8_t *Pixels) +{ + auto lump = kopenFileReader(SourceLump, 0); + int destSize = GetWidth() * GetHeight(); + uint8_t max = 255; + bool rle = true; + + // This is to "fix" bad fonts + { + uint8_t buff[16]; + lump.Read (buff, 4); + if (buff[3] == '2') + { + lump.Read (buff, 7); + max = buff[6]; + lump.Seek (SourcePos - 11, FileReader::SeekCur); + } + else if (buff[3] == 0x1A) + { + lump.Read(buff, 13); + max = buff[12] - 1; + lump.Seek (SourcePos - 17, FileReader::SeekCur); + rle = false; + } + else + { + lump.Seek (SourcePos - 4, FileReader::SeekCur); + } + } + + int runlen = 0, setlen = 0; + uint8_t setval = 0; // Shut up, GCC! + uint8_t *dest_p = Pixels; + int dest_adv = GetHeight(); + int dest_rew = destSize - 1; + + if (rle) + { + for (int y = GetHeight(); y != 0; --y) + { + for (int x = GetWidth(); x != 0; ) + { + if (runlen != 0) + { + uint8_t color = lump.ReadUInt8(); + color = std::min(color, max); + if (SourceRemap != nullptr) + { + color = SourceRemap[color]; + } + *dest_p = color; + dest_p += dest_adv; + x--; + runlen--; + } + else if (setlen != 0) + { + *dest_p = setval; + dest_p += dest_adv; + x--; + setlen--; + } + else + { + int8_t code = lump.ReadInt8(); + if (code >= 0) + { + runlen = code + 1; + } + else if (code != -128) + { + uint8_t color = lump.ReadUInt8(); + setlen = (-code) + 1; + setval = std::min(color, max); + if (SourceRemap != nullptr) + { + setval = SourceRemap[setval]; + } + } + } + } + dest_p -= dest_rew; + } + } + else + { + for (int y = GetHeight(); y != 0; --y) + { + for (int x = GetWidth(); x != 0; ) + { + uint8_t color = lump.ReadUInt8(); + if (color > max) + { + color = max; + } + if (SourceRemap != nullptr) + { + color = SourceRemap[color]; + } + *dest_p = color; + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + } + + if (destSize < 0) + { + I_Error ("The font %s is corrupt", SourceLump.GetChars()); + } +} + diff --git a/source/common/fonts/fontchars.h b/source/common/fonts/fontchars.h new file mode 100644 index 000000000..6cd240e77 --- /dev/null +++ b/source/common/fonts/fontchars.h @@ -0,0 +1,32 @@ + + +// This is a font character that loads a texture and recolors it. +class FFontChar1 : public FTexture +{ +public: + FFontChar1 (FTexture *sourcelump); + void Create8BitPixels(uint8_t *) override; + void SetSourceRemap(const uint8_t *sourceremap) { SourceRemap = sourceremap; } + const uint8_t *ResetSourceRemap() { auto p = SourceRemap; SourceRemap = nullptr; return p; } + FTexture *GetBase() const { return BaseTexture; } + +protected: + + FTexture *BaseTexture; + const uint8_t *SourceRemap; +}; + +// This is a font character that reads RLE compressed data. +class FFontChar2 : public FTexture +{ +public: + FFontChar2 (const char *sourcelump, int sourcepos, int width, int height, int leftofs=0, int topofs=0); + + void Create8BitPixels(uint8_t*) override; + void SetSourceRemap(const uint8_t *sourceremap); + +protected: + FString SourceLump; + int SourcePos; + const uint8_t *SourceRemap; +}; diff --git a/source/common/fonts/fontinternals.h b/source/common/fonts/fontinternals.h new file mode 100644 index 000000000..6d68c6aa8 --- /dev/null +++ b/source/common/fonts/fontinternals.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include "tarray.h" + +// This structure is used by BuildTranslations() to hold color information. +struct TranslationParm +{ + short RangeStart; // First level for this range + short RangeEnd; // Last level for this range + uint8_t Start[3]; // Start color for this range + uint8_t End[3]; // End color for this range +}; + +struct TempParmInfo +{ + unsigned int StartParm[2]; + unsigned int ParmLen[2]; + int Index; +}; +struct TempColorInfo +{ + FName Name; + unsigned int ParmInfo; + PalEntry LogColor; +}; + +struct TranslationMap +{ + FName Name; + int Number; +}; + +extern TArray TranslationParms[2]; +extern TArray TranslationLookup; +extern TArray TranslationColors; +extern uint16_t lowerforupper[65536]; +extern uint16_t upperforlower[65536]; + +class FImageSource; + +void RecordTextureColors (FImageSource *pic, uint32_t *usedcolors); +bool myislower(int code); +bool myisupper(int code); +int stripaccent(int code); +int getAlternative(int code); diff --git a/source/common/fonts/hexfont.cpp b/source/common/fonts/hexfont.cpp new file mode 100644 index 000000000..7111bd21c --- /dev/null +++ b/source/common/fonts/hexfont.cpp @@ -0,0 +1,436 @@ +/* +** bdffont.cpp +** Management for the VGA consolefont +** +**--------------------------------------------------------------------------- +** Copyright 2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "textures.h" +#include "image.h" +#include "v_font.h" +#include "utf8.h" +#include "sc_man.h" +#include "imagehelpers.h" +#include "../2d/v_draw.h" + +#include "fontinternals.h" + + +struct HexDataSource +{ + int FirstChar = INT_MAX, LastChar = INT_MIN; + TArray glyphdata; + unsigned glyphmap[65536] = {}; + + //========================================================================== + // + // parse a HEX font + // + //========================================================================== + + void ParseDefinition(const char *fname) + { + FScanner sc; + sc.Open(fname); + sc.SetCMode(true); + glyphdata.Push(0); // ensure that index 0 can be used as 'not present'. + while (sc.GetString()) + { + int codepoint = (int)strtoull(sc.String, nullptr, 16); + sc.MustGetStringName(":"); + sc.MustGetString(); + if (codepoint >= 0 && codepoint < 65536 && !sc.Compare("00000000000000000000000000000000")) // don't set up empty glyphs. + { + unsigned size = (unsigned)strlen(sc.String); + unsigned offset = glyphdata.Reserve(size / 2 + 1); + glyphmap[codepoint] = offset; + glyphdata[offset++] = size / 2; + for (unsigned i = 0; i < size; i += 2) + { + char hex[] = { sc.String[i], sc.String[i + 1], 0 }; + glyphdata[offset++] = (uint8_t)strtoull(hex, nullptr, 16); + } + if (codepoint < FirstChar) FirstChar = codepoint; + if (codepoint > LastChar) LastChar = codepoint; + } + } + } +}; + +static HexDataSource hexdata; + +// This is a font character that reads RLE compressed data. +class FHexFontChar : public FTexture +{ +public: + FHexFontChar(uint8_t *sourcedata, int swidth, int width, int height); + + void Create8BitPixels(uint8_t *buffer) override; + +protected: + int SourceWidth; + const uint8_t *SourceData; +}; + + +//========================================================================== +// +// FHexFontChar :: FHexFontChar +// +// Used by HEX fonts. +// +//========================================================================== + +FHexFontChar::FHexFontChar (uint8_t *sourcedata, int swidth, int width, int height) +: SourceData (sourcedata) +{ + SourceWidth = swidth; + Size.x = width; + Size.y = height; + PicAnim.xofs = 0; + PicAnim.yofs = 0; +} + +//========================================================================== +// +// FHexFontChar :: Get8BitPixels +// +// The render style has no relevance here. +// +//========================================================================== + +void FHexFontChar::Create8BitPixels(uint8_t *Pixels) +{ + int destSize = Size.x * Size.y; + uint8_t *dest_p = Pixels; + const uint8_t *src_p = SourceData; + + memset(dest_p, 0, destSize); + for (int y = 0; y < Size.y; y++) + { + for (int x = 0; x < SourceWidth; x++) + { + int byte = *src_p++; + uint8_t *pixelstart = dest_p + 8 * x * Size.y + y; + for (int bit = 0; bit < 8; bit++) + { + if (byte & (128 >> bit)) + { + pixelstart[bit*Size.y] = y+2; + // Add a shadow at the bottom right, similar to the old console font. + if (y != Size.y - 1) + { + pixelstart[bit*Size.y + Size.y + 1] = 1; + } + } + } + } + } +} + +class FHexFontChar2 : public FHexFontChar +{ +public: + FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height); + + void Create8BitPixels(uint8_t* buffer) override; +}; + + +//========================================================================== +// +// FHexFontChar :: FHexFontChar +// +// Used by HEX fonts. +// +//========================================================================== + +FHexFontChar2::FHexFontChar2(uint8_t *sourcedata, int swidth, int width, int height) + : FHexFontChar(sourcedata, swidth, width, height) +{ +} + +//========================================================================== +// +// FHexFontChar :: Get8BitPixels +// +// The render style has no relevance here. +// +//========================================================================== + +void FHexFontChar2::Create8BitPixels(uint8_t* Pixels) +{ + int destSize = Size.x * Size.y; + uint8_t *dest_p = Pixels; + + assert(SourceData); + if (SourceData) + { + auto drawLayer = [&](int ix, int iy, int color) + { + const uint8_t *src_p = SourceData; + for (int y = 0; y < Size.y - 2; y++) + { + for (int x = 0; x < SourceWidth; x++) + { + int byte = *src_p++; + uint8_t *pixelstart = dest_p + (ix + 8 * x) * Size.y + (iy + y); + for (int bit = 0; bit < 8; bit++) + { + if (byte & (128 >> bit)) + { + pixelstart[bit*Size.y] = color; + } + } + } + } + }; + memset(dest_p, 0, destSize); + + const int darkcolor = 1; + const int brightcolor = 14; + for (int xx = 0; xx < 3; xx++) for (int yy = 0; yy < 3; yy++) if (xx != 1 || yy != 1) + drawLayer(xx, yy, darkcolor); + drawLayer(1, 1, brightcolor); + } +} + + + +class FHexFont : public FFont +{ + +public: + //========================================================================== + // + // FHexFont :: FHexFont + // + // Loads a HEX font + // + //========================================================================== + + FHexFont (const char *fontname, const char *lump) + { + FontName = fontname; + + FirstChar = hexdata.FirstChar; + LastChar = hexdata.LastChar; + + Next = FirstFont; + FirstFont = this; + FontHeight = 16; + SpaceWidth = 9; + GlobalKerning = 0; + translateUntranslated = true; + + LoadTranslations(); + } + + //========================================================================== + // + // FHexFont :: LoadTranslations + // + //========================================================================== + + void LoadTranslations() + { + const int spacing = 9; + double luminosity[256]; + + memset (PatchRemap, 0, 256); + for (int i = 0; i < 18; i++) + { + // Create a gradient similar to the old console font. + PatchRemap[i] = i; + luminosity[i] = i == 1? 0.01 : 0.5 + (i-2) * (0.5 / 17.); + } + ActiveColors = 18; + + Chars.Resize(LastChar - FirstChar + 1); + for (int i = FirstChar; i <= LastChar; i++) + { + if (hexdata.glyphmap[i] > 0) + { + auto offset = hexdata.glyphmap[i]; + int size = hexdata.glyphdata[offset] / 16; + Chars[i - FirstChar].TranslatedPic = new FHexFontChar (&hexdata.glyphdata[offset+1], size, size * 9, 16); + Chars[i - FirstChar].XMove = size * spacing; + TileFiles.AllTiles.Push(Chars[i - FirstChar].TranslatedPic); // store it in the tile list for automatic deletion. + } + else Chars[i - FirstChar].XMove = spacing; + + } + BuildTranslations (luminosity, nullptr, &TranslationParms[1][0], ActiveColors, nullptr); + } + +}; + + +class FHexFont2 : public FFont +{ + +public: + //========================================================================== + // + // FHexFont :: FHexFont + // + // Loads a HEX font + // + //========================================================================== + + FHexFont2(const char *fontname, const char *lump) + { + assert(lump >= 0); + + FontName = fontname; + + FirstChar = hexdata.FirstChar; + LastChar = hexdata.LastChar; + + Next = FirstFont; + FirstFont = this; + FontHeight = 18; + SpaceWidth = 10; + GlobalKerning = -1; + translateUntranslated = true; + + LoadTranslations(); + } + + //========================================================================== + // + // FHexFont :: LoadTranslations + // + //========================================================================== + + void LoadTranslations() + { + const int spacing = 9; + double luminosity[256]; + + memset(PatchRemap, 0, 256); + for (int i = 0; i < 18; i++) + { + // Create a gradient similar to the old console font. + PatchRemap[i] = i; + luminosity[i] = i / 17.; + } + ActiveColors = 18; + + Chars.Resize(LastChar - FirstChar + 1); + for (int i = FirstChar; i <= LastChar; i++) + { + if (hexdata.glyphmap[i] > 0) + { + auto offset = hexdata.glyphmap[i]; + int size = hexdata.glyphdata[offset] / 16; + Chars[i - FirstChar].TranslatedPic = new FHexFontChar2(&hexdata.glyphdata[offset + 1], size, 2 + size * 8, 18); + Chars[i - FirstChar].XMove = size * spacing; + TileFiles.AllTiles.Push(Chars[i - FirstChar].TranslatedPic); // store it in the tile list for automatic deletion. + } + else Chars[i - FirstChar].XMove = spacing; + + } + BuildTranslations(luminosity, nullptr, &TranslationParms[0][0], ActiveColors, nullptr); + } + + void SetDefaultTranslation(uint32_t *colors) override + { + double myluminosity[18]; + + myluminosity[0] = 0; + for (int i = 1; i < 18; i++) + { + myluminosity[i] = (i - 1) / 16.; + } + + uint8_t othertranslation[256], otherreverse[256]; + TArray otherluminosity; + + SimpleTranslation(colors, othertranslation, otherreverse, otherluminosity); + + FRemapTable remap(ActiveColors); + remap.Palette[255] = 0; + + for (unsigned l = 1; l < 18; l++) + { + for (unsigned o = 1; o < otherluminosity.Size() - 1; o++) // luminosity[0] is for the transparent color + { + if (myluminosity[l] >= otherluminosity[o] && myluminosity[l] <= otherluminosity[o + 1]) + { + PalEntry color1 = ImageHelpers::BasePalette[otherreverse[o]]; + PalEntry color2 = ImageHelpers::BasePalette[otherreverse[o + 1]]; + double weight = 0; + if (otherluminosity[o] != otherluminosity[o + 1]) + { + weight = (myluminosity[l] - otherluminosity[o]) / (otherluminosity[o + 1] - otherluminosity[o]); + } + int r = int(color1.r + weight * (color2.r - color1.r)); + int g = int(color1.g + weight * (color2.g - color1.g)); + int b = int(color1.b + weight * (color2.b - color1.b)); + + r = clamp(r, 0, 255); + g = clamp(g, 0, 255); + b = clamp(b, 0, 255); + remap.Palette[l] = PalEntry(255, r, g, b); + break; + } + } + } + forceremap = true; + + } + +}; + + +//========================================================================== +// +// +// +//========================================================================== + +FFont *CreateHexLumpFont (const char *fontname, const char * lump) +{ + if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump); + return new FHexFont(fontname, lump); +} + +//========================================================================== +// +// +// +//========================================================================== + +FFont *CreateHexLumpFont2(const char *fontname, const char* lump) +{ + if (hexdata.FirstChar == INT_MAX) hexdata.ParseDefinition(lump); + return new FHexFont2(fontname, lump); +} diff --git a/source/common/fonts/myiswalpha.h b/source/common/fonts/myiswalpha.h new file mode 100644 index 000000000..7f97fb562 --- /dev/null +++ b/source/common/fonts/myiswalpha.h @@ -0,0 +1,524 @@ +// Generated by Python 3.7.4 + +#pragma once + +static const uint8_t MYISWALPHA_DATA[] = +{ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, // 0000..007F +0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x04, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, // 0080..00FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0100..017F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0180..01FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0200..027F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0x03, 0x00, 0x1F, 0x50, 0x00, 0x00, // 0280..02FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xBC, // 0300..037F +0x40, 0xD7, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, // 0380..03FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0400..047F +0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0480..04FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, // 0500..057F +0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x87, 0x07, 0x00, // 0580..05FF +0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC0, 0xFE, 0xFF, // 0600..067F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2F, 0x00, 0x60, 0xC0, 0x00, 0x9C, // 0680..06FF +0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0700..077F +0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x02, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x07, 0x30, 0x04, // 0780..07FF +0xFF, 0xFF, 0x3F, 0x04, 0x10, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x07, 0x00, 0x00, // 0800..087F +0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xDF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0880..08FF +0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x23, 0x00, 0x00, 0x01, 0xFF, 0x03, 0x00, 0xFE, 0xFF, // 0900..097F +0xE1, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xC5, 0x23, 0x00, 0x40, 0x00, 0xB0, 0x03, 0x00, 0x03, 0x10, // 0980..09FF +0xE0, 0x87, 0xF9, 0xFF, 0xFF, 0xFD, 0x6D, 0x03, 0x00, 0x00, 0x00, 0x5E, 0x00, 0x00, 0x1C, 0x00, // 0A00..0A7F +0xE0, 0xBF, 0xFB, 0xFF, 0xFF, 0xFD, 0xED, 0x23, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x02, // 0A80..0AFF +0xE0, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xED, 0x23, 0x00, 0x00, 0x00, 0xB0, 0x03, 0x00, 0x02, 0x00, // 0B00..0B7F +0xE8, 0xC7, 0x3D, 0xD6, 0x18, 0xC7, 0xFF, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, // 0B80..0BFF +0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF, 0x23, 0x00, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, // 0C00..0C7F +0xE1, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xEF, 0x23, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x06, 0x00, // 0C80..0CFF +0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0x00, 0x40, 0x70, 0x80, 0x03, 0x00, 0x00, 0xFC, // 0D00..0D7F +0xE0, 0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0xFB, 0x2F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0D80..0DFF +0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0D, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0E00..0E7F +0x96, 0x25, 0xF0, 0xFE, 0xAE, 0xEC, 0x0D, 0x20, 0x5F, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, // 0E80..0EFF +0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, // 0F00..0F7F +0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0F80..0FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x80, 0x00, 0x00, 0x3F, 0x3C, 0x62, 0xC0, 0xE1, 0xFF, // 1000..107F +0x03, 0x40, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, // 1080..10FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1100..117F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1180..11FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, // 1200..127F +0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0x3D, 0x7F, 0x3D, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1280..12FF +0xFF, 0xFF, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, // 1300..137F +0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, // 1380..13FF +0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1400..147F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1480..14FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1500..157F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1580..15FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, // 1600..167F +0xFE, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xFE, 0x01, // 1680..16FF +0xFF, 0xDF, 0x03, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xDF, 0x01, 0x00, // 1700..177F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, // 1780..17FF +0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, // 1800..187F +0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, // 1880..18FF +0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x00, // 1900..197F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1980..19FF +0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, // 1A00..1A7F +0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1A80..1AFF +0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1B00..1B7F +0xF8, 0xFF, 0xFF, 0xFF, 0x01, 0xC0, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, // 1B80..1BFF +0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0x3F, // 1C00..1C7F +0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x63, 0x00, // 1C80..1CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1D00..1D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1D80..1DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1E00..1E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 1E80..1EFF +0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xAA, 0xFF, 0xFF, 0xFF, 0x3F, // 1F00..1F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x5F, 0xDC, 0x1F, 0xCF, 0x0F, 0xFF, 0x1F, 0xDC, 0x1F, // 1F80..1FFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, // 2000..207F +0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2080..20FF +0x84, 0xFC, 0x2F, 0x3E, 0x50, 0xBD, 0xFF, 0xF3, 0xE0, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2100..217F +0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2180..21FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2200..227F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2280..22FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2300..237F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2380..23FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2400..247F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2480..24FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2500..257F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2580..25FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2600..267F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2680..26FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2700..277F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2780..27FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2800..287F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2880..28FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2900..297F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2980..29FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2A00..2A7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2A80..2AFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2B00..2B7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2B80..2BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, // 2C00..2C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x78, 0x0C, 0x00, // 2C80..2CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, // 2D00..2D7F +0xFF, 0xFF, 0x7F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, // 2D80..2DFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2E00..2E7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2E80..2EFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2F00..2F7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2F80..2FFF +0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x18, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3000..307F +0xFF, 0xFF, 0x7F, 0xE0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, // 3080..30FF +0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3100..317F +0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 3180..31FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3200..327F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3280..32FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3300..337F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3380..33FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3400..347F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3480..34FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3500..357F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3580..35FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3600..367F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3680..36FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3700..377F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3780..37FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3800..387F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3880..38FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3900..397F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3980..39FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3A00..3A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3A80..3AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3B00..3B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3B80..3BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3C00..3C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3C80..3CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3D00..3D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3D80..3DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3E00..3E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3E80..3EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3F00..3F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 3F80..3FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4000..407F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4080..40FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4100..417F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4180..41FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4200..427F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4280..42FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4300..437F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4380..43FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4400..447F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4480..44FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4500..457F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4580..45FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4600..467F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4680..46FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4700..477F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4780..47FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4800..487F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4880..48FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4900..497F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4980..49FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4A00..4A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4A80..4AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4B00..4B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4B80..4BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4C00..4C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4C80..4CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4D00..4D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4D80..4DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4E00..4E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4E80..4EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4F00..4F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 4F80..4FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5000..507F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5080..50FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5100..517F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5180..51FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5200..527F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5280..52FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5300..537F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5380..53FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5400..547F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5480..54FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5500..557F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5580..55FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5600..567F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5680..56FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5700..577F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5780..57FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5800..587F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5880..58FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5900..597F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5980..59FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5A00..5A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5A80..5AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5B00..5B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5B80..5BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5C00..5C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5C80..5CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5D00..5D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5D80..5DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5E00..5E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5E80..5EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5F00..5F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 5F80..5FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6000..607F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6080..60FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6100..617F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6180..61FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6200..627F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6280..62FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6300..637F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6380..63FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6400..647F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6480..64FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6500..657F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6580..65FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6600..667F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6680..66FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6700..677F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6780..67FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6800..687F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6880..68FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6900..697F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6980..69FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6A00..6A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6A80..6AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6B00..6B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6B80..6BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6C00..6C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6C80..6CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6D00..6D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6D80..6DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6E00..6E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6E80..6EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6F00..6F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 6F80..6FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7000..707F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7080..70FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7100..717F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7180..71FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7200..727F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7280..72FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7300..737F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7380..73FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7400..747F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7480..74FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7500..757F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7580..75FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7600..767F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7680..76FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7700..777F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7780..77FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7800..787F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7880..78FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7900..797F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7980..79FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7A00..7A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7A80..7AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7B00..7B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7B80..7BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7C00..7C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7C80..7CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7D00..7D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7D80..7DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7E00..7E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7E80..7EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7F00..7F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 7F80..7FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8000..807F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8080..80FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8100..817F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8180..81FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8200..827F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8280..82FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8300..837F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8380..83FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8400..847F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8480..84FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8500..857F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8580..85FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8600..867F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8680..86FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8700..877F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8780..87FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8800..887F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8880..88FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8900..897F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8980..89FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8A00..8A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8A80..8AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8B00..8B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8B80..8BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8C00..8C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8C80..8CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8D00..8D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8D80..8DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8E00..8E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8E80..8EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8F00..8F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8F80..8FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9000..907F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9080..90FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9100..917F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9180..91FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9200..927F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9280..92FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9300..937F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9380..93FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9400..947F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9480..94FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9500..957F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9580..95FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9600..967F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9680..96FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9700..977F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9780..97FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9800..987F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9880..98FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9900..997F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9980..99FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9A00..9A7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9A80..9AFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9B00..9B7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9B80..9BFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9C00..9C7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9C80..9CFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9D00..9D7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9D80..9DFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9E00..9E7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9E80..9EFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 9F00..9F7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, // 9F80..9FFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A000..A07F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A080..A0FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A100..A17F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A180..A1FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A200..A27F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A280..A2FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A300..A37F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A380..A3FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A400..A47F +0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, // A480..A4FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A500..A57F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A580..A5FF +0xFF, 0x1F, 0xFF, 0xFF, 0x00, 0x0C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x80, // A600..A67F +0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, // A680..A6FF +0x00, 0x00, 0x80, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A700..A77F +0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, // A780..A7FF +0xBB, 0xF7, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, // A800..A87F +0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x68, // A880..A8FF +0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x1F, // A900..A97F +0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0xDF, 0xFF, 0x00, 0x7C, // A980..A9FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0xF7, 0x0F, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0xC4, // AA00..AA7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x62, 0x3E, 0x05, 0x00, 0x00, 0x38, 0xFF, 0x07, 0x1C, 0x00, // AA80..AAFF +0x7E, 0x7E, 0x7E, 0x00, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x3F, 0x00, 0xFF, 0xFF, // AB00..AB7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, // AB80..ABFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AC00..AC7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AC80..ACFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AD00..AD7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AD80..ADFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AE00..AE7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AE80..AEFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AF00..AF7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // AF80..AFFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B000..B07F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B080..B0FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B100..B17F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B180..B1FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B200..B27F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B280..B2FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B300..B37F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B380..B3FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B400..B47F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B480..B4FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B500..B57F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B580..B5FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B600..B67F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B680..B6FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B700..B77F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B780..B7FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B800..B87F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B880..B8FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B900..B97F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B980..B9FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BA00..BA7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BA80..BAFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BB00..BB7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BB80..BBFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BC00..BC7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BC80..BCFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BD00..BD7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BD80..BDFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BE00..BE7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BE80..BEFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BF00..BF7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // BF80..BFFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C000..C07F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C080..C0FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C100..C17F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C180..C1FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C200..C27F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C280..C2FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C300..C37F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C380..C3FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C400..C47F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C480..C4FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C500..C57F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C580..C5FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C600..C67F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C680..C6FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C700..C77F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C780..C7FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C800..C87F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C880..C8FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C900..C97F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C980..C9FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CA00..CA7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CA80..CAFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CB00..CB7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CB80..CBFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CC00..CC7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CC80..CCFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CD00..CD7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CD80..CDFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CE00..CE7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CE80..CEFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CF00..CF7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // CF80..CFFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D000..D07F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D080..D0FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D100..D17F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D180..D1FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D200..D27F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D280..D2FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D300..D37F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D380..D3FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D400..D47F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D480..D4FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D500..D57F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D580..D5FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D600..D67F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D680..D6FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D700..D77F +0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x7F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, // D780..D7FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D800..D87F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D880..D8FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D900..D97F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // D980..D9FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DA00..DA7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DA80..DAFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DB00..DB7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DB80..DBFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DC00..DC7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DC80..DCFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DD00..DD7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DD80..DDFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DE00..DE7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DE80..DEFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DF00..DF7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // DF80..DFFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E000..E07F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E080..E0FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E100..E17F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E180..E1FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E200..E27F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E280..E2FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E300..E37F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E380..E3FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E400..E47F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E480..E4FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E500..E57F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E580..E5FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E600..E67F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E680..E6FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E700..E77F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E780..E7FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E800..E87F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E880..E8FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E900..E97F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // E980..E9FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EA00..EA7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EA80..EAFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EB00..EB7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EB80..EBFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EC00..EC7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EC80..ECFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ED00..ED7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ED80..EDFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EE00..EE7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EE80..EEFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EF00..EF7F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EF80..EFFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F000..F07F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F080..F0FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F100..F17F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F180..F1FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F200..F27F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F280..F2FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F300..F37F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F380..F3FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F400..F47F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F480..F4FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F500..F57F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F580..F5FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F600..F67F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F680..F6FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F700..F77F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F780..F7FF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F800..F87F +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // F880..F8FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // F900..F97F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // F980..F9FF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, // FA00..FA7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, // FA80..FAFF +0x7F, 0x00, 0xF8, 0xA0, 0xFF, 0xFD, 0x7F, 0x5F, 0xDB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FB00..FB7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FB80..FBFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FC00..FC7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FC80..FCFF +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // FD00..FD7F +0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, // FD80..FDFF +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFF, // FE00..FE7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, // FE80..FEFF +0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x07, 0xC0, 0xFF, 0xFF, 0xFF, // FF00..FF7F +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 0xFC, 0xFC, 0x1C, 0x00, 0x00, 0x00, 0x00, // FF80..FFFF +}; + +inline int myiswalpha(wint_t ch) +{ + return MYISWALPHA_DATA[ch / 8] & (1 << (ch & 7)); +} diff --git a/source/common/fonts/singlelumpfont.cpp b/source/common/fonts/singlelumpfont.cpp new file mode 100644 index 000000000..dac6aef83 --- /dev/null +++ b/source/common/fonts/singlelumpfont.cpp @@ -0,0 +1,630 @@ +/* +** singlelumpfont.cpp +** Management for compiled font lumps +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "textures.h" +#include "image.h" +#include "v_font.h" +#include "utf8.h" +#include "fontchars.h" +#include "printf.h" +#include "imagehelpers.h" +#include "cache1d.h" + +#include "fontinternals.h" + +/* Special file formats handled here: + +FON1 "console" fonts have the following header: + char Magic[4]; -- The characters "FON1" + uword CharWidth; -- Character cell width + uword CharHeight; -- Character cell height + +The FON1 header is followed by RLE character data for all 256 +8-bit ASCII characters. + + +FON2 "standard" fonts have the following header: + char Magic[4]; -- The characters "FON2" + uword FontHeight; -- Every character in a font has the same height + ubyte FirstChar; -- First character defined by this font. + ubyte LastChar; -- Last character definde by this font. + ubyte bConstantWidth; + ubyte ShadingType; + ubyte PaletteSize; -- size of palette in entries (not bytes!) + ubyte Flags; + +There is presently only one flag for FON2: + FOF_WHOLEFONTKERNING 1 -- The Kerning field is present in the file + +The FON2 header is followed by variable length data: + word Kerning; + -- only present if FOF_WHOLEFONTKERNING is set + + ubyte Palette[PaletteSize+1][3]; + -- The last entry is the delimiter color. The delimiter is not used + -- by the font but is used by imagetool when converting the font + -- back to an image. Color 0 is the transparent color and is also + -- used only for converting the font back to an image. The other + -- entries are all presorted in increasing order of brightness. + + ubyte CharacterData[...]; + -- RLE character data, in order +*/ + +class FSingleLumpFont : public FFont +{ +public: + FSingleLumpFont (const char *fontname, const char * lump); + +protected: + void CheckFON1Chars (double *luminosity); + void BuildTranslations2 (); + void FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette, + bool rescale, PalEntry *out_palette); + void LoadTranslations (); + void LoadFON1 (const char * lump, const uint8_t *data); + void LoadFON2 (const char* lump, const uint8_t *data); + void LoadBMF (const char* lump, const uint8_t *data); + + static int BMFCompare(const void *a, const void *b); + + enum + { + FONT1, + FONT2, + BMFFONT + } FontType; + uint8_t PaletteData[768]; + bool RescalePalette; +}; + + +//========================================================================== +// +// FSingleLumpFont :: FSingleLumpFont +// +// Loads a FON1 or FON2 font resource. +// +//========================================================================== + +FSingleLumpFont::FSingleLumpFont (const char *name, const char * lump) +{ + assert(lump >= 0); + + FontName = name; + + auto data = kloadfile(name, 0); + + if (data[0] == 0xE1 && data[1] == 0xE6 && data[2] == 0xD5 && data[3] == 0x1A) + { + LoadBMF(name, data.Data()); + Type = BMF; + } + else if (data[0] != 'F' || data[1] != 'O' || data[2] != 'N' || + (data[3] != '1' && data[3] != '2')) + { + I_Error ("%s is not a recognizable font", name); + } + else + { + switch (data[3]) + { + case '1': + LoadFON1 (name, data.Data()); + Type = Fon1; + break; + + case '2': + LoadFON2 (name, data.Data()); + Type = Fon2; + break; + } + } + + Next = FirstFont; + FirstFont = this; +} + +//========================================================================== +// +// FSingleLumpFont :: LoadTranslations +// +//========================================================================== + +void FSingleLumpFont::LoadTranslations() +{ + double luminosity[256]; + uint8_t identity[256]; + PalEntry local_palette[256]; + bool useidentity = true; + bool usepalette = false; + const void* ranges; + unsigned int count = LastChar - FirstChar + 1; + + switch(FontType) + { + case FONT1: + useidentity = false; + ranges = &TranslationParms[1][0]; + CheckFON1Chars (luminosity); + break; + + case BMFFONT: + case FONT2: + usepalette = true; + FixupPalette (identity, luminosity, PaletteData, RescalePalette, local_palette); + + ranges = &TranslationParms[0][0]; + break; + + default: + // Should be unreachable. + I_Error("Unknown font type in FSingleLumpFont::LoadTranslation."); + return; + } + + for(unsigned int i = 0;i < count;++i) + { + if(Chars[i].TranslatedPic) + static_cast(Chars[i].TranslatedPic)->SetSourceRemap(PatchRemap); + } + + BuildTranslations (luminosity, useidentity ? identity : nullptr, ranges, ActiveColors, usepalette ? local_palette : nullptr); +} + +//========================================================================== +// +// FSingleLumpFont :: LoadFON1 +// +// FON1 is used for the console font. +// +//========================================================================== + +void FSingleLumpFont::LoadFON1 (const char * lump, const uint8_t *data) +{ + int w, h; + + // The default console font is for Windows-1252 and fills the 0x80-0x9f range with valid glyphs. + // Since now all internal text is processed as Unicode, these have to be remapped to their proper places. + // The highest valid character in this range is 0x2122, so we need 0x2123 entries in our character table. + Chars.Resize(0x2123); + + w = data[4] + data[5]*256; + h = data[6] + data[7]*256; + + FontType = FONT1; + FontHeight = h; + SpaceWidth = w; + FirstChar = 0; + LastChar = 255; // This is to allow LoadTranslations to function. The way this is all set up really needs to be changed. + GlobalKerning = 0; + translateUntranslated = true; + LoadTranslations(); + LastChar = 0x2122; + + // Move the Windows-1252 characters to their proper place. + for (int i = 0x80; i < 0xa0; i++) + { + if (win1252map[i-0x80] != i && Chars[i].TranslatedPic != nullptr && Chars[win1252map[i - 0x80]].TranslatedPic == nullptr) + { + std::swap(Chars[i], Chars[win1252map[i - 0x80]]); + } + } +} + +//========================================================================== +// +// FSingleLumpFont :: LoadFON2 +// +// FON2 is used for everything but the console font. The console font should +// probably use FON2 as well, but oh well. +// +//========================================================================== + +void FSingleLumpFont::LoadFON2 (const char * lump, const uint8_t *data) +{ + int count, i, totalwidth; + uint16_t *widths; + const uint8_t *palette; + const uint8_t *data_p; + + FontType = FONT2; + FontHeight = data[4] + data[5]*256; + FirstChar = data[6]; + LastChar = data[7]; + ActiveColors = data[10]+1; + RescalePalette = data[9] == 0; + + count = LastChar - FirstChar + 1; + Chars.Resize(count); + TArray widths2(count, true); + if (data[11] & 1) + { // Font specifies a kerning value. + GlobalKerning = LittleShort(*(int16_t *)&data[12]); + widths = (uint16_t *)(data + 14); + } + else + { // Font does not specify a kerning value. + GlobalKerning = 0; + widths = (uint16_t *)(data + 12); + } + totalwidth = 0; + + if (data[8]) + { // Font is mono-spaced. + totalwidth = LittleShort(widths[0]); + for (i = 0; i < count; ++i) + { + widths2[i] = totalwidth; + } + totalwidth *= count; + palette = (uint8_t *)&widths[1]; + } + else + { // Font has varying character widths. + for (i = 0; i < count; ++i) + { + widths2[i] = LittleShort(widths[i]); + totalwidth += widths2[i]; + } + palette = (uint8_t *)(widths + i); + } + + if (FirstChar <= ' ' && LastChar >= ' ') + { + SpaceWidth = widths2[' '-FirstChar]; + } + else if (FirstChar <= 'N' && LastChar >= 'N') + { + SpaceWidth = (widths2['N' - FirstChar] + 1) / 2; + } + else + { + SpaceWidth = totalwidth * 2 / (3 * count); + } + + memcpy(PaletteData, palette, ActiveColors*3); + + data_p = palette + ActiveColors*3; + + for (i = 0; i < count; ++i) + { + int destSize = widths2[i] * FontHeight; + Chars[i].XMove = widths2[i]; + if (destSize <= 0) + { + Chars[i].TranslatedPic = nullptr; + } + else + { + Chars[i].TranslatedPic = new FFontChar2 (lump, int(data_p - data), widths2[i], FontHeight); + TileFiles.AllTiles.Push(Chars[i].TranslatedPic); + do + { + int8_t code = *data_p++; + if (code >= 0) + { + data_p += code+1; + destSize -= code+1; + } + else if (code != -128) + { + data_p++; + destSize -= (-code)+1; + } + } while (destSize > 0); + } + if (destSize < 0) + { + i += FirstChar; + I_Error ("Overflow decompressing char %d (%c) of %s", i, i, FontName.GetChars()); + } + } + + LoadTranslations(); +} + +//========================================================================== +// +// FSingleLumpFont :: LoadBMF +// +// Loads a BMF font. The file format is described at +// +// +//========================================================================== + +void FSingleLumpFont::LoadBMF(const char *lump, const uint8_t *data) +{ + const uint8_t *chardata; + int numchars, count, totalwidth, nwidth; + int infolen; + int i, chari; + uint8_t raw_palette[256*3]; + PalEntry sort_palette[256]; + + FontType = BMFFONT; + FontHeight = data[5]; + GlobalKerning = (int8_t)data[8]; + ActiveColors = data[16]; + SpaceWidth = -1; + nwidth = -1; + RescalePalette = true; + + infolen = data[17 + ActiveColors*3]; + chardata = data + 18 + ActiveColors*3 + infolen; + numchars = chardata[0] + 256*chardata[1]; + chardata += 2; + + // Scan for lowest and highest characters defined and total font width. + FirstChar = 256; + LastChar = 0; + totalwidth = 0; + for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) + { + if ((chardata[chari+1] == 0 || chardata[chari+2] == 0) && chardata[chari+5] == 0) + { // Don't count empty characters. + continue; + } + if (chardata[chari] < FirstChar) + { + FirstChar = chardata[chari]; + } + if (chardata[chari] > LastChar) + { + LastChar = chardata[chari]; + } + totalwidth += chardata[chari+1]; + } + if (LastChar < FirstChar) + { + I_Error("BMF font defines no characters"); + } + count = LastChar - FirstChar + 1; + Chars.Resize(count); + // BMF palettes are only six bits per component. Fix that. + for (i = 0; i < ActiveColors*3; ++i) + { + raw_palette[i+3] = (data[17 + i] << 2) | (data[17 + i] >> 4); + } + ActiveColors++; + + // Sort the palette by increasing brightness + for (i = 0; i < ActiveColors; ++i) + { + PalEntry *pal = &sort_palette[i]; + pal->a = i; // Use alpha part to point back to original entry + pal->r = raw_palette[i*3 + 0]; + pal->g = raw_palette[i*3 + 1]; + pal->b = raw_palette[i*3 + 2]; + } + qsort(sort_palette + 1, ActiveColors - 1, sizeof(PalEntry), BMFCompare); + + // Create the PatchRemap table from the sorted "alpha" values. + PatchRemap[0] = 0; + for (i = 1; i < ActiveColors; ++i) + { + PatchRemap[sort_palette[i].a] = i; + } + + memcpy(PaletteData, raw_palette, 768); + + // Now scan through the characters again, creating glyphs for each one. + for (i = chari = 0; i < numchars; ++i, chari += 6 + chardata[chari+1] * chardata[chari+2]) + { + assert(chardata[chari] - FirstChar >= 0); + assert(chardata[chari] - FirstChar < count); + if (chardata[chari] == ' ') + { + SpaceWidth = chardata[chari+5]; + } + else if (chardata[chari] == 'N') + { + nwidth = chardata[chari+5]; + } + Chars[chardata[chari] - FirstChar].XMove = chardata[chari+5]; + if (chardata[chari+1] == 0 || chardata[chari+2] == 0) + { // Empty character: skip it. + continue; + } + auto tex = new FFontChar2(lump, int(chardata + chari + 6 - data), + chardata[chari+1], // width + chardata[chari+2], // height + -(int8_t)chardata[chari+3], // x offset + -(int8_t)chardata[chari+4] // y offset + ); + Chars[chardata[chari] - FirstChar].TranslatedPic = tex; + TileFiles.AllTiles.Push(tex); + } + + // If the font did not define a space character, determine a suitable space width now. + if (SpaceWidth < 0) + { + if (nwidth >= 0) + { + SpaceWidth = nwidth; + } + else + { + SpaceWidth = totalwidth * 2 / (3 * count); + } + } + + FixXMoves(); + LoadTranslations(); +} + +//========================================================================== +// +// FSingleLumpFont :: BMFCompare STATIC +// +// Helper to sort BMF palettes. +// +//========================================================================== + +int FSingleLumpFont::BMFCompare(const void *a, const void *b) +{ + const PalEntry *pa = (const PalEntry *)a; + const PalEntry *pb = (const PalEntry *)b; + + return (pa->r * 299 + pa->g * 587 + pa->b * 114) - + (pb->r * 299 + pb->g * 587 + pb->b * 114); +} + +//========================================================================== +// +// FSingleLumpFont :: CheckFON1Chars +// +// Scans a FON1 resource for all the color values it uses and sets up +// some tables like SimpleTranslation. Data points to the RLE data for +// the characters. Also sets up the character textures. +// +//========================================================================== + +void FSingleLumpFont::CheckFON1Chars (double *luminosity) +{ + auto data = kloadfile(GetName(), 0); + if (data.Size() < 8) return; + + uint8_t used[256], reverse[256]; + const uint8_t *data_p; + int i, j; + + memset (used, 0, 256); + data_p = data.Data() + 8; + + for (i = 0; i < 256; ++i) + { + int destSize = SpaceWidth * FontHeight; + + if(!Chars[i].TranslatedPic) + { + Chars[i].TranslatedPic = new FFontChar2 (GetName(), int(data_p - data.Data()), SpaceWidth, FontHeight); + Chars[i].XMove = SpaceWidth; + TileFiles.AllTiles.Push(Chars[i].TranslatedPic); + } + + // Advance to next char's data and count the used colors. + do + { + int8_t code = *data_p++; + if (code >= 0) + { + destSize -= code+1; + while (code-- >= 0) + { + used[*data_p++] = 1; + } + } + else if (code != -128) + { + used[*data_p++] = 1; + destSize -= 1 - code; + } + } while (destSize > 0); + } + + memset (PatchRemap, 0, 256); + reverse[0] = 0; + for (i = 1, j = 1; i < 256; ++i) + { + if (used[i]) + { + reverse[j++] = i; + } + } + for (i = 1; i < j; ++i) + { + PatchRemap[reverse[i]] = i; + luminosity[i] = (reverse[i] - 1) / 254.0; + } + ActiveColors = j; +} + +//========================================================================== +// +// FSingleLumpFont :: FixupPalette +// +// Finds the best matches for the colors used by a FON2 font and sets up +// some tables like SimpleTranslation. +// +//========================================================================== + +void FSingleLumpFont::FixupPalette (uint8_t *identity, double *luminosity, const uint8_t *palette, bool rescale, PalEntry *out_palette) +{ + int i; + double maxlum = 0.0; + double minlum = 100000000.0; + double diver; + + identity[0] = 0; + palette += 3; // Skip the transparent color + + for (i = 1; i < ActiveColors; ++i, palette += 3) + { + int r = palette[0]; + int g = palette[1]; + int b = palette[2]; + double lum = r*0.299 + g*0.587 + b*0.114; + identity[i] = ImageHelpers::BestColor(r, g, b); + luminosity[i] = lum; + out_palette[i].r = r; + out_palette[i].g = g; + out_palette[i].b = b; + out_palette[i].a = 255; + if (lum > maxlum) + maxlum = lum; + if (lum < minlum) + minlum = lum; + } + out_palette[0] = 0; + + if (rescale) + { + diver = 1.0 / (maxlum - minlum); + } + else + { + diver = 1.0 / 255.0; + } + for (i = 1; i < ActiveColors; ++i) + { + luminosity[i] = (luminosity[i] - minlum) * diver; + } +} + +FFont *CreateSingleLumpFont (const char *fontname, const char * lump) +{ + return new FSingleLumpFont(fontname, lump); +} diff --git a/source/common/fonts/v_font.cpp b/source/common/fonts/v_font.cpp new file mode 100644 index 000000000..735767335 --- /dev/null +++ b/source/common/fonts/v_font.cpp @@ -0,0 +1,972 @@ +/* +** v_font.cpp +** Font management +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2019 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include + +#include "templates.h" +#include "m_swap.h" +#include "v_font.h" +#include "cmdlib.h" +#include "sc_man.h" +#include "v_text.h" +#include "image.h" +#include "utf8.h" +#include "cache1d.h" +#include "m_png.h" +#include "printf.h" + +#include "fontinternals.h" + +// MACROS ------------------------------------------------------------------ + +#define DEFAULT_LOG_COLOR PalEntry(223,223,223) + +// TYPES ------------------------------------------------------------------- +int V_GetColor(const char* cstr); + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- +FFont* SmallFont, * SmallFont2, * BigFont, * BigUpper, * ConFont, * IntermissionFont, * NewConsoleFont, * NewSmallFont, * CurrentConsoleFont, * OriginalSmallFont, * AlternativeSmallFont, * OriginalBigFont; + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static int TranslationMapCompare (const void *a, const void *b); +//void UpdateGenericUI(bool cvar); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern int PrintColors[]; + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FFont *FFont::FirstFont = nullptr; +int NumTextColors; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +TArray TranslationParms[2]; +TArray TranslationLookup; +TArray TranslationColors; + +// CODE -------------------------------------------------------------------- + +FFont *V_GetFont(const char *name, const char *fontlumpname) +{ + FFont *font = FFont::FindFont (name); + if (font == nullptr) + { + auto lumpy = kopenFileReader(name, 0); + if (!lumpy.isOpen()) return nullptr; + uint32_t head; + lumpy.Read (&head, 4); + if ((head & MAKE_ID(255,255,255,0)) == MAKE_ID('F','O','N',0) || + head == MAKE_ID(0xE1,0xE6,0xD5,0x1A)) + { + FFont *CreateSingleLumpFont (const char *fontname, const char *lump); + return CreateSingleLumpFont (name, name); + } + } + return font; +} + +//========================================================================== +// +// V_InitCustomFonts +// +// Initialize a list of custom multipatch fonts +// +//========================================================================== + +void V_InitCustomFonts() +{ +#if 0 + FScanner sc; + FTexture *lumplist[256]; + bool notranslate[256]; + bool donttranslate; + FString namebuffer, templatebuf; + int i; + int llump,lastlump=0; + int format; + int start; + int first; + int count; + int spacewidth; + int kerning; + char cursor = '_'; + + while ((llump = Wads.FindLump ("FONTDEFS", &lastlump)) != -1) + { + sc.OpenLumpNum(llump); + while (sc.GetString()) + { + memset (lumplist, 0, sizeof(lumplist)); + memset (notranslate, 0, sizeof(notranslate)); + donttranslate = false; + namebuffer = sc.String; + format = 0; + start = 33; + first = 33; + count = 223; + spacewidth = -1; + kerning = 0; + + sc.MustGetStringName ("{"); + while (!sc.CheckString ("}")) + { + sc.MustGetString(); + if (sc.Compare ("TEMPLATE")) + { + if (format == 2) goto wrong; + sc.MustGetString(); + templatebuf = sc.String; + format = 1; + } + else if (sc.Compare ("BASE")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + start = sc.Number; + format = 1; + } + else if (sc.Compare ("FIRST")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + first = sc.Number; + format = 1; + } + else if (sc.Compare ("COUNT")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + count = sc.Number; + format = 1; + } + else if (sc.Compare ("CURSOR")) + { + sc.MustGetString(); + cursor = sc.String[0]; + } + else if (sc.Compare ("SPACEWIDTH")) + { + if (format == 2) goto wrong; + sc.MustGetNumber(); + spacewidth = sc.Number; + format = 1; + } + else if (sc.Compare("DONTTRANSLATE")) + { + donttranslate = true; + } + else if (sc.Compare ("NOTRANSLATION")) + { + if (format == 1) goto wrong; + while (sc.CheckNumber() && !sc.Crossed) + { + if (sc.Number >= 0 && sc.Number < 256) + notranslate[sc.Number] = true; + } + format = 2; + } + else if (sc.Compare("KERNING")) + { + sc.MustGetNumber(); + kerning = sc.Number; + } + else + { + if (format == 1) goto wrong; + FTexture **p = &lumplist[*(unsigned char*)sc.String]; + sc.MustGetString(); + FTextureID texid = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch); + if (texid.Exists()) + { + *p = TexMan.GetTexture(texid); + } + else if (Wads.GetLumpFile(sc.LumpNum) >= Wads.GetIwadNum()) + { + // Print a message only if this isn't in zdoom.pk3 + sc.ScriptMessage("%s: Unable to find texture in font definition for %s", sc.String, namebuffer.GetChars()); + } + format = 2; + } + } + if (format == 1) + { + FFont *fnt = new FFont (namebuffer, templatebuf, nullptr, first, count, start, llump, spacewidth, donttranslate); + fnt->SetCursor(cursor); + fnt->SetKerning(kerning); + } + else if (format == 2) + { + for (i = 0; i < 256; i++) + { + if (lumplist[i] != nullptr) + { + first = i; + break; + } + } + for (i = 255; i >= 0; i--) + { + if (lumplist[i] != nullptr) + { + count = i - first + 1; + break; + } + } + if (count > 0) + { + FFont *CreateSpecialFont (const char *name, int first, int count, FTexture **lumplist, const bool *notranslate, int lump, bool donttranslate); + FFont *fnt = CreateSpecialFont (namebuffer, first, count, &lumplist[first], notranslate, llump, donttranslate); + fnt->SetCursor(cursor); + fnt->SetKerning(kerning); + } + } + else goto wrong; + } + sc.Close(); + } + return; + +wrong: + sc.ScriptError ("Invalid combination of properties in font '%s'", namebuffer.GetChars()); +#endif +} + +//========================================================================== +// +// V_GetColorFromString +// +// Passed a string of the form "#RGB", "#RRGGBB", "R G B", or "RR GG BB", +// returns a number representing that color. If palette is non-NULL, the +// index of the best match in the palette is returned, otherwise the +// RRGGBB value is returned directly. +// +//========================================================================== + +int V_GetColor(const char* cstr) +{ + int c[3], i, p; + char val[3]; + + val[2] = '\0'; + + // Check for HTML-style #RRGGBB or #RGB color string + if (cstr[0] == '#') + { + size_t len = strlen(cstr); + + if (len == 7) + { + // Extract each eight-bit component into c[]. + for (i = 0; i < 3; ++i) + { + val[0] = cstr[1 + i * 2]; + val[1] = cstr[2 + i * 2]; + c[i] = ParseHex(val); + } + } + else if (len == 4) + { + // Extract each four-bit component into c[], expanding to eight bits. + for (i = 0; i < 3; ++i) + { + val[1] = val[0] = cstr[1 + i]; + c[i] = ParseHex(val); + } + } + else + { + // Bad HTML-style; pretend it's black. + c[2] = c[1] = c[0] = 0; + } + } + else + { + if (strlen(cstr) == 6) + { + char* p; + int color = strtol(cstr, &p, 16); + if (*p == 0) + { + // RRGGBB string + c[0] = (color & 0xff0000) >> 16; + c[1] = (color & 0xff00) >> 8; + c[2] = (color & 0xff); + } + else goto normal; + } + else + { + normal: + // Treat it as a space-delimited hexadecimal string + for (i = 0; i < 3; ++i) + { + // Skip leading whitespace + while (*cstr <= ' ' && *cstr != '\0') + { + cstr++; + } + // Extract a component and convert it to eight-bit + for (p = 0; *cstr > ' '; ++p, ++cstr) + { + if (p < 2) + { + val[p] = *cstr; + } + } + if (p == 0) + { + c[i] = 0; + } + else + { + if (p == 1) + { + val[1] = val[0]; + } + c[i] = ParseHex(val); + } + } + } + } + return MAKERGB(c[0], c[1], c[2]); +} + +//========================================================================== +// +// V_InitFontColors +// +// Reads the list of color translation definitions into memory. +// +//========================================================================== + +void V_InitFontColors () +{ + TArray names; + int lump, lastlump = 0; + TranslationParm tparm = { 0, 0, {0}, {0} }; // Silence GCC (for real with -Wextra ) + TArray parms; + TArray parminfo; + TArray colorinfo; + int c, parmchoice; + TempParmInfo info; + TempColorInfo cinfo; + PalEntry logcolor; + unsigned int i, j; + int k, index; + + info.Index = -1; + + TranslationParms[0].Clear(); + TranslationParms[1].Clear(); + TranslationLookup.Clear(); + TranslationColors.Clear(); + + FScanner sc; + sc.Open("textcolors.txt"); + //while ((lump = Wads.FindLump ("TEXTCOLO", &lastlump)) != -1) + { + while (sc.GetString()) + { + names.Clear(); + + logcolor = DEFAULT_LOG_COLOR; + + // Everything until the '{' is considered a valid name for the + // color range. + names.Push (sc.String); + while (sc.MustGetString(), !sc.Compare ("{")) + { + if (names[0] == NAME_Untranslated) + { + sc.ScriptError ("The \"untranslated\" color may not have any other names"); + } + names.Push (sc.String); + } + + parmchoice = 0; + info.StartParm[0] = parms.Size(); + info.StartParm[1] = 0; + info.ParmLen[1] = info.ParmLen[0] = 0; + tparm.RangeEnd = tparm.RangeStart = -1; + + while (sc.MustGetString(), !sc.Compare ("}")) + { + if (sc.Compare ("Console:")) + { + if (parmchoice == 1) + { + sc.ScriptError ("Each color may only have one set of console ranges"); + } + parmchoice = 1; + info.StartParm[1] = parms.Size(); + info.ParmLen[0] = info.StartParm[1] - info.StartParm[0]; + tparm.RangeEnd = tparm.RangeStart = -1; + } + else if (sc.Compare ("Flat:")) + { + sc.MustGetString(); + logcolor = V_GetColor (sc.String); + } + else + { + // Get first color + c = V_GetColor (sc.String); + tparm.Start[0] = RPART(c); + tparm.Start[1] = GPART(c); + tparm.Start[2] = BPART(c); + + // Get second color + sc.MustGetString(); + c = V_GetColor (sc.String); + tparm.End[0] = RPART(c); + tparm.End[1] = GPART(c); + tparm.End[2] = BPART(c); + + // Check for range specifier + if (sc.CheckNumber()) + { + if (tparm.RangeStart == -1 && sc.Number != 0) + { + sc.ScriptError ("The first color range must start at position 0"); + } + if (sc.Number < 0 || sc.Number > 256) + { + sc.ScriptError ("The color range must be within positions [0,256]"); + } + if (sc.Number <= tparm.RangeEnd) + { + sc.ScriptError ("The color range must not start before the previous one ends"); + } + tparm.RangeStart = sc.Number; + + sc.MustGetNumber(); + if (sc.Number < 0 || sc.Number > 256) + { + sc.ScriptError ("The color range must be within positions [0,256]"); + } + if (sc.Number <= tparm.RangeStart) + { + sc.ScriptError ("The color range end position must be larger than the start position"); + } + tparm.RangeEnd = sc.Number; + } + else + { + tparm.RangeStart = tparm.RangeEnd + 1; + tparm.RangeEnd = 256; + if (tparm.RangeStart >= tparm.RangeEnd) + { + sc.ScriptError ("The color has too many ranges"); + } + } + parms.Push (tparm); + } + } + info.ParmLen[parmchoice] = parms.Size() - info.StartParm[parmchoice]; + if (info.ParmLen[0] == 0) + { + if (names[0] != NAME_Untranslated) + { + sc.ScriptError ("There must be at least one normal range for a color"); + } + } + else + { + if (names[0] == NAME_Untranslated) + { + sc.ScriptError ("The \"untranslated\" color must be left undefined"); + } + } + if (info.ParmLen[1] == 0 && names[0] != NAME_Untranslated) + { // If a console translation is unspecified, make it white, since the console + // font has no color information stored with it. + tparm.RangeStart = 0; + tparm.RangeEnd = 256; + tparm.Start[2] = tparm.Start[1] = tparm.Start[0] = 0; + tparm.End[2] = tparm.End[1] = tparm.End[0] = 255; + info.StartParm[1] = parms.Push (tparm); + info.ParmLen[1] = 1; + } + cinfo.ParmInfo = parminfo.Push (info); + // Record this color information for each name it goes by + for (i = 0; i < names.Size(); ++i) + { + // Redefine duplicates in-place + for (j = 0; j < colorinfo.Size(); ++j) + { + if (colorinfo[j].Name == names[i]) + { + colorinfo[j].ParmInfo = cinfo.ParmInfo; + colorinfo[j].LogColor = logcolor; + break; + } + } + if (j == colorinfo.Size()) + { + cinfo.Name = names[i]; + cinfo.LogColor = logcolor; + colorinfo.Push (cinfo); + } + } + } + } + // Make permananent copies of all the color information we found. + for (i = 0, index = 0; i < colorinfo.Size(); ++i) + { + TranslationMap tmap; + TempParmInfo *pinfo; + + tmap.Name = colorinfo[i].Name; + pinfo = &parminfo[colorinfo[i].ParmInfo]; + if (pinfo->Index < 0) + { + // Write out the set of remappings for this color. + for (k = 0; k < 2; ++k) + { + for (j = 0; j < pinfo->ParmLen[k]; ++j) + { + TranslationParms[k].Push (parms[pinfo->StartParm[k] + j]); + } + } + TranslationColors.Push (colorinfo[i].LogColor); + pinfo->Index = index++; + } + tmap.Number = pinfo->Index; + TranslationLookup.Push (tmap); + } + // Leave a terminating marker at the ends of the lists. + tparm.RangeStart = -1; + TranslationParms[0].Push (tparm); + TranslationParms[1].Push (tparm); + // Sort the translation lookups for fast binary searching. + qsort (&TranslationLookup[0], TranslationLookup.Size(), sizeof(TranslationLookup[0]), TranslationMapCompare); + + NumTextColors = index; + assert (NumTextColors >= NUM_TEXT_COLORS); +} + +//========================================================================== +// +// TranslationMapCompare +// +//========================================================================== + +static int TranslationMapCompare (const void *a, const void *b) +{ + return int(((const TranslationMap *)a)->Name) - int(((const TranslationMap *)b)->Name); +} + +//========================================================================== +// +// V_FindFontColor +// +// Returns the color number for a particular named color range. +// +//========================================================================== + +EColorRange V_FindFontColor (FName name) +{ + int min = 0, max = TranslationLookup.Size() - 1; + + while (min <= max) + { + unsigned int mid = (min + max) / 2; + const TranslationMap *probe = &TranslationLookup[mid]; + if (probe->Name == name) + { + return EColorRange(probe->Number); + } + else if (probe->Name < name) + { + min = mid + 1; + } + else + { + max = mid - 1; + } + } + return CR_UNTRANSLATED; +} + +//========================================================================== +// +// V_LogColorFromColorRange +// +// Returns the color to use for text in the startup/error log window. +// +//========================================================================== + +PalEntry V_LogColorFromColorRange (EColorRange range) +{ + if ((unsigned int)range >= TranslationColors.Size()) + { // Return default color + return DEFAULT_LOG_COLOR; + } + return TranslationColors[range]; +} + +//========================================================================== +// +// V_ParseFontColor +// +// Given a pointer to a color identifier (presumably just after a color +// escape character), return the color it identifies and advances +// color_value to just past it. +// +//========================================================================== + +EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int boldcolor) +{ + const uint8_t *ch = color_value; + int newcolor = *ch++; + + if (newcolor == '-') // Normal + { + newcolor = normalcolor; + } + else if (newcolor == '+') // Bold + { + newcolor = boldcolor; + } + else if (newcolor == '[') // Named + { + const uint8_t *namestart = ch; + while (*ch != ']' && *ch != '\0') + { + ch++; + } + FName rangename((const char *)namestart, int(ch - namestart), true); + if (*ch != '\0') + { + ch++; + } + newcolor = V_FindFontColor (rangename); + } + else if (newcolor >= 'A' && newcolor < NUM_TEXT_COLORS + 'A') // Standard, uppercase + { + newcolor -= 'A'; + } + else if (newcolor >= 'a' && newcolor < NUM_TEXT_COLORS + 'a') // Standard, lowercase + { + newcolor -= 'a'; + } + else // Incomplete! + { + color_value = ch - (newcolor == '\0'); + return CR_UNDEFINED; + } + color_value = ch; + return EColorRange(newcolor); +} + +//========================================================================== +// +// V_InitFonts +// +//========================================================================== + +void V_InitFonts() +{ + V_InitCustomFonts(); + + FFont *CreateHexLumpFont(const char *fontname, const char* lump); + FFont *CreateHexLumpFont2(const char *fontname, const char * lump); + + auto lump = kopenFileReader("newconsolefont.hex", 0); // This is always loaded from gzdoom.pk3 to prevent overriding it with incomplete replacements. + if (!lump.isOpen()) I_Error("newconsolefont.hex not found"); // This font is needed - do not start up without it. + NewConsoleFont = CreateHexLumpFont("NewConsoleFont", "newconsolefont.hex"); + NewSmallFont = CreateHexLumpFont2("NewSmallFont", "newconsolefont.hex"); + CurrentConsoleFont = NewConsoleFont; + + ConFont = V_GetFont("ConsoleFont", "CONFONT"); + { + ConFont = SmallFont; + } +} + +void V_ClearFonts() +{ + while (FFont::FirstFont != nullptr) + { + delete FFont::FirstFont; + } + FFont::FirstFont = nullptr; + AlternativeSmallFont = OriginalSmallFont = CurrentConsoleFont = NewSmallFont = NewConsoleFont = SmallFont = SmallFont2 = BigFont = ConFont = IntermissionFont = nullptr; +} + +//========================================================================== +// +// CleanseString +// +// Does some mild sanity checking on a string: If it ends with an incomplete +// color escape, the escape is removed. +// +//========================================================================== + +char* CleanseString(char* str) +{ + char* escape = strrchr(str, TEXTCOLOR_ESCAPE); + if (escape != NULL) + { + if (escape[1] == '\0') + { + *escape = '\0'; + } + else if (escape[1] == '[') + { + char* close = strchr(escape + 2, ']'); + if (close == NULL) + { + *escape = '\0'; + } + } + } + return str; +} + +int stripaccent(int code) +{ + if (code < 0x8a) + return code; + if (code < 0x100) + { + if (code == 0x8a) // Latin capital letter S with caron + return 'S'; + if (code == 0x8e) // Latin capital letter Z with caron + return 'Z'; + if (code == 0x9a) // Latin small letter S with caron + return 's'; + if (code == 0x9e) // Latin small letter Z with caron + return 'z'; + if (code == 0x9f) // Latin capital letter Y with diaeresis + return 'Y'; + if (code == 0xab || code == 0xbb) return '"'; // typographic quotation marks. + if (code == 0xff) // Latin small letter Y with diaeresis + return 'y'; + // Every other accented character has the high two bits set. + if ((code & 0xC0) == 0) + return code; + // Make lowercase characters uppercase so there are half as many tests. + int acode = code & 0xDF; + if (acode >= 0xC0 && acode <= 0xC5) // A with accents + return 'A' + (code & 0x20); + if (acode == 0xC7) // Cedilla + return 'C' + (acode & 0x20); + if (acode >= 0xC8 && acode <= 0xCB) // E with accents + return 'E' + (code & 0x20); + if (acode >= 0xCC && acode <= 0xCF) // I with accents + return 'I' + (code & 0x20); + if (acode == 0xD0) // Eth + return 'D' + (code & 0x20); + if (acode == 0xD1) // N with tilde + return 'N' + (code & 0x20); + if ((acode >= 0xD2 && acode <= 0xD6) || // O with accents + acode == 0xD8) // O with stroke + return 'O' + (code & 0x20); + if (acode >= 0xD9 && acode <= 0xDC) // U with accents + return 'U' + (code & 0x20); + if (acode == 0xDD) // Y with accute + return 'Y' + (code & 0x20); + if (acode == 0xDE) // Thorn + return 'P' + (code & 0x20); // well, it sort of looks like a 'P' + } + else if (code >= 0x100 && code < 0x180) + { + // For the double-accented Hungarian letters it makes more sense to first map them to the very similar looking Umlauts. + // (And screw the crappy specs that do not allow UTF-8 multibyte character literals here.) + if (code == 0x150) code = 0xd6; + else if (code == 0x151) code = 0xf6; + else if (code == 0x170) code = 0xdc; + else if (code == 0x171) code = 0xfc; + else + { + static const char accentless[] = "AaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiIiJjKkkLlLlLlLlLlNnNnNnnNnOoOoOoOoRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzs"; + return accentless[code - 0x100]; + } + } + else if (code >= 0x200 && code < 0x218) + { + // 0x200-0x217 are irrelevant but easy to map to other characters more likely to exist. + static const uint16_t u200map[] = { 0xc4, 0xe4, 0xc2, 0xe2, 0xcb, 0xeb, 0xca, 0xea, 0xcf, 0xef, 0xce, 0xee, 0xd6, 0xf6, 0xd4, 0xe4, 'R', 'r', 'R', 'r', 0xdc, 0xfc, 0xdb, 0xfb }; + return u200map[code - 0x200]; + } + return getAlternative(code); +} + +int getAlternative(int code) +{ + // This is for determining replacements that do not make CanPrint fail. + switch (code) + { + default: + return code; + + case 0x17f: // The 'long s' can be safely remapped to the regular variant, not that this gets used in any real text... + return 's'; + + case 0x218: // Romanian S with comma below may get remapped to S with cedilla. + return 0x15e; + + case 0x219: + return 0x15f; + + case 0x21a: // Romanian T with comma below may get remapped to T with cedilla. + return 0x162; + + case 0x21b: + return 0x163; + + // Greek characters with equivalents in either Latin or Cyrillic. This is only suitable for uppercase fonts! + case 0x391: + return 'A'; + + case 0x392: + return 'B'; + + case 0x393: + return 0x413; + + case 0x395: + return 'E'; + + case 0x396: + return 'Z'; + + case 0x397: + return 'H'; + + case 0x399: + return 'I'; + + case 0x39a: + return 'K'; + + case 0x39c: + return 'M'; + + case 0x39d: + return 'N'; + + case 0x39f: + return 'O'; + + case 0x3a0: + return 0x41f; + + case 0x3a1: + return 'P'; + + case 0x3a4: + return 'T'; + + case 0x3a5: + return 'Y'; + + case 0x3a6: + return 0x424; + + case 0x3a7: + return 'X'; + + case 0x3aa: + return 0xcf; + + case 0x3ab: + return 0x178; + + case 0x3bf: + return 'o'; + + case 0x3c2: + return 0x3c3; // Lowercase Sigma character in Greek, which changes depending on its positioning in a word; if the font is uppercase only or features a smallcaps style, the second variant of the letter will remain unused + + case 0x3ca: + return 0xef; + + case 0x3cc: + return 0xf3; + + // Cyrillic characters with equivalents in the Latin alphabet. + case 0x400: + return 0xc8; + + case 0x401: + return 0xcb; + + case 0x405: + return 'S'; + + case 0x406: + return 'I'; + + case 0x407: + return 0xcf; + + case 0x408: + return 'J'; + + case 0x450: + return 0xe8; + + case 0x451: + return 0xeb; + + case 0x455: + return 's'; + + case 0x456: + return 'i'; + + case 0x457: + return 0xef; + + case 0x458: + return 'j'; + + } + + // skip the rest of Latin characters because none of them are relevant for modern languages, except Vietnamese which cannot be represented with the tiny bitmap fonts anyway. + + return code; +} \ No newline at end of file diff --git a/source/common/fonts/v_font.h b/source/common/fonts/v_font.h new file mode 100644 index 000000000..055c61c2d --- /dev/null +++ b/source/common/fonts/v_font.h @@ -0,0 +1,209 @@ +/* +** v_font.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __V_FONT_H__ +#define __V_FONT_H__ + +#include "vectors.h" +#include "name.h" +#include "palentry.h" +#include "tarray.h" +#include "zstring.h" + +class DCanvas; +struct FRemapTable; +class FTexture; + +enum EColorRange : int +{ + CR_UNDEFINED = -1, + CR_BRICK, + CR_TAN, + CR_GRAY, + CR_GREY = CR_GRAY, + CR_GREEN, + CR_BROWN, + CR_GOLD, + CR_RED, + CR_BLUE, + CR_ORANGE, + CR_WHITE, + CR_YELLOW, + CR_UNTRANSLATED, + CR_BLACK, + CR_LIGHTBLUE, + CR_CREAM, + CR_OLIVE, + CR_DARKGREEN, + CR_DARKRED, + CR_DARKBROWN, + CR_PURPLE, + CR_DARKGRAY, + CR_CYAN, + CR_ICE, + CR_FIRE, + CR_SAPPHIRE, + CR_TEAL, + NUM_TEXT_COLORS, +}; + +extern int NumTextColors; + + +class FFont +{ +public: + + enum EFontType + { + Unknown, + Folder, + Multilump, + Fon1, + Fon2, + BMF, + Custom + }; + + virtual ~FFont (); + + virtual FTexture *GetChar (int code, int translation, int *const width, bool *redirected = nullptr) const; + virtual int GetCharWidth (int code) const; + FRemapTable *GetColorTranslation (EColorRange range, PalEntry *color = nullptr) const; + int GetSpaceWidth () const { return SpaceWidth; } + int GetHeight () const { return FontHeight; } + int GetDefaultKerning () const { return GlobalKerning; } + int GetMaxAscender(const uint8_t* text) const; + int GetMaxAscender(const char* text) const { return GetMaxAscender((uint8_t*)text); } + int GetMaxAscender(const FString &text) const { return GetMaxAscender((uint8_t*)text.GetChars()); } + virtual void LoadTranslations(); + FName GetName() const { return FontName; } + + static FFont *FindFont(FName fontname); + + // Return width of string in pixels (unscaled) + int StringWidth (const uint8_t *str) const; + inline int StringWidth (const char *str) const { return StringWidth ((const uint8_t *)str); } + inline int StringWidth (const FString &str) const { return StringWidth ((const uint8_t *)str.GetChars()); } + + // Checks if the font contains all characters to print this text. + bool CanPrint(const uint8_t *str) const; + inline bool CanPrint(const char *str) const { return CanPrint((const uint8_t *)str); } + inline bool CanPrint(const FString &str) const { return CanPrint((const uint8_t *)str.GetChars()); } + + int GetCharCode(int code, bool needpic) const; + char GetCursor() const { return Cursor; } + void SetCursor(char c) { Cursor = c; } + void SetKerning(int c) { GlobalKerning = c; } + bool NoTranslate() const { return noTranslate; } + void RecordAllTextureColors(uint32_t *usedcolors); + virtual void SetDefaultTranslation(uint32_t *colors); + void CheckCase(); + + int GetDisplacement() const { return Displacement; } + + +protected: + FFont (); + + void BuildTranslations (const double *luminosity, const uint8_t *identity, + const void *ranges, int total_colors, const PalEntry *palette); + void FixXMoves(); + + static int SimpleTranslation (uint32_t *colorsused, uint8_t *translation, + uint8_t *identity, TArray &Luminosity); + + EFontType Type = EFontType::Unknown; + int FirstChar, LastChar; + int SpaceWidth; + int FontHeight; + int AsciiHeight = 0; + int GlobalKerning; + int TranslationType = 0; + int Displacement = 0; + char Cursor; + bool noTranslate; + bool translateUntranslated; + bool MixedCase = false; + bool forceremap = false; + struct CharData + { + FTexture *TranslatedPic = nullptr; // Texture for use with font translations. + FTexture *OriginalPic = nullptr; // Texture for use with CR_UNTRANSLATED or font colorization. + int XMove = INT_MIN; + }; + TArray Chars; + int ActiveColors; + TArray Ranges; + uint8_t PatchRemap[256]; + + FName FontName = NAME_None; + FFont *Next; + + static FFont *FirstFont; + friend struct FontsDeleter; + + friend void V_ClearFonts(); + friend void V_InitFonts(); +}; + + +extern FFont *SmallFont, *SmallFont2, *BigFont, *BigUpper, *ConFont, *IntermissionFont, *NewConsoleFont, *NewSmallFont, *CurrentConsoleFont, *OriginalSmallFont, *AlternativeSmallFont, *OriginalBigFont; + +void V_InitFonts(); +void V_ClearFonts(); +EColorRange V_FindFontColor (FName name); +PalEntry V_LogColorFromColorRange (EColorRange range); +EColorRange V_ParseFontColor (const uint8_t *&color_value, int normalcolor, int boldcolor); +FFont *V_GetFont(const char *fontname, const char *fontlumpname = nullptr); +void V_InitFontColors(); +char* CleanseString(char* str); + + +struct FRemapTable +{ + FRemapTable(int count = 256) {} + ~FRemapTable() { delete Palette; } + + PalEntry *Palette = nullptr; // The ideal palette this maps to + int PalIndex; + int NumEntries; // # of elements in this table (usually 256) + bool Inactive; // This table is inactive and should be treated as if it was passed as NULL + +private: + void Free(); + void Alloc(int count); +}; + + +#endif //__V_FONT_H__ diff --git a/source/common/fonts/v_text.cpp b/source/common/fonts/v_text.cpp new file mode 100644 index 000000000..c0e00ecb5 --- /dev/null +++ b/source/common/fonts/v_text.cpp @@ -0,0 +1,170 @@ +/* +** v_text.cpp +** Draws text to a canvas. Also has a text line-breaker thingy. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include +#include +#include + +#include "v_text.h" +#include "utf8.h" + + +//========================================================================== +// +// Break long lines of text into multiple lines no longer than maxwidth pixels +// +//========================================================================== + +static void breakit (FBrokenLines *line, FFont *font, const uint8_t *start, const uint8_t *stop, FString &linecolor) +{ + if (!linecolor.IsEmpty()) + { + line->Text = TEXTCOLOR_ESCAPE; + line->Text += linecolor; + } + line->Text.AppendCStrPart ((const char *)start, stop - start); + line->Width = font->StringWidth (line->Text); +} + +TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *string, bool preservecolor) +{ + TArray Lines(128); + + const uint8_t *space = NULL, *start = string; + int c, w, nw; + FString lastcolor, linecolor; + bool lastWasSpace = false; + int kerning = font->GetDefaultKerning (); + + // The real isspace is a bit too badly defined, so use our own one + auto myisspace = [](int ch) { return ch == '\t' || ch == '\r' || ch == '\n' || ch == ' '; }; + + w = 0; + + while ( (c = GetCharFromString(string)) ) + { + if (c == TEXTCOLOR_ESCAPE) + { + if (*string) + { + if (*string == '[') + { + const uint8_t *start = string; + while (*string != ']' && *string != '\0') + { + string++; + } + if (*string != '\0') + { + string++; + } + lastcolor = FString((const char *)start, string - start); + } + else + { + lastcolor = *string++; + } + } + continue; + } + + if (myisspace(c)) + { + if (!lastWasSpace) + { + space = string - 1; + lastWasSpace = true; + } + } + else + { + lastWasSpace = false; + } + + nw = font->GetCharWidth (c); + + if ((w > 0 && w + nw > maxwidth) || c == '\n') + { // Time to break the line + if (!space) + { + for (space = string - 1; (*space & 0xc0) == 0x80 && space > start; space--); + } + + auto index = Lines.Reserve(1); + breakit (&Lines[index], font, start, space, linecolor); + if (c == '\n' && !preservecolor) + { + lastcolor = ""; // Why, oh why, did I do it like this? + } + linecolor = lastcolor; + + w = 0; + lastWasSpace = false; + start = space; + space = NULL; + + while (*start && myisspace (*start) && *start != '\n') + start++; + if (*start == '\n') + start++; + else + while (*start && myisspace (*start)) + start++; + string = start; + } + else + { + w += nw + kerning; + } + } + + // String here is pointing one character after the '\0' + if (--string - start >= 1) + { + const uint8_t *s = start; + + while (s < string) + { + // If there is any non-white space in the remainder of the string, add it. + if (!myisspace (*s++)) + { + auto i = Lines.Reserve(1); + breakit (&Lines[i], font, start, string, linecolor); + break; + } + } + } + return Lines; +} diff --git a/source/common/fonts/v_text.h b/source/common/fonts/v_text.h new file mode 100644 index 000000000..f13ffc38a --- /dev/null +++ b/source/common/fonts/v_text.h @@ -0,0 +1,89 @@ +/* +** v_text.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef __V_TEXT_H__ +#define __V_TEXT_H__ + +#include "zstring.h" +#include "v_font.h" + +struct FBrokenLines +{ + unsigned Width; + FString Text; +}; + +#define TEXTCOLOR_ESCAPE '\034' +#define TEXTCOLOR_ESCAPESTR "\034" + +#define TEXTCOLOR_BRICK "\034A" +#define TEXTCOLOR_TAN "\034B" +#define TEXTCOLOR_GRAY "\034C" +#define TEXTCOLOR_GREY "\034C" +#define TEXTCOLOR_GREEN "\034D" +#define TEXTCOLOR_BROWN "\034E" +#define TEXTCOLOR_GOLD "\034F" +#define TEXTCOLOR_RED "\034G" +#define TEXTCOLOR_BLUE "\034H" +#define TEXTCOLOR_ORANGE "\034I" +#define TEXTCOLOR_WHITE "\034J" +#define TEXTCOLOR_YELLOW "\034K" +#define TEXTCOLOR_UNTRANSLATED "\034L" +#define TEXTCOLOR_BLACK "\034M" +#define TEXTCOLOR_LIGHTBLUE "\034N" +#define TEXTCOLOR_CREAM "\034O" +#define TEXTCOLOR_OLIVE "\034P" +#define TEXTCOLOR_DARKGREEN "\034Q" +#define TEXTCOLOR_DARKRED "\034R" +#define TEXTCOLOR_DARKBROWN "\034S" +#define TEXTCOLOR_PURPLE "\034T" +#define TEXTCOLOR_DARKGRAY "\034U" +#define TEXTCOLOR_CYAN "\034V" +#define TEXTCOLOR_ICE "\034W" +#define TEXTCOLOR_FIRE "\034X" +#define TEXTCOLOR_SAPPHIRE "\034Y" +#define TEXTCOLOR_TEAL "\034Z" + +#define TEXTCOLOR_NORMAL "\034-" +#define TEXTCOLOR_BOLD "\034+" + +#define TEXTCOLOR_CHAT "\034*" +#define TEXTCOLOR_TEAMCHAT "\034!" + +TArray V_BreakLines (FFont *font, int maxwidth, const uint8_t *str, bool preservecolor = false); +inline TArray V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) + { return V_BreakLines (font, maxwidth, (const uint8_t *)str, preservecolor); } +inline TArray V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false) + { return V_BreakLines (font, maxwidth, (const uint8_t *)str.GetChars(), preservecolor); } + +#endif //__V_TEXT_H__ diff --git a/source/common/textures/texture.cpp b/source/common/textures/texture.cpp index 2ad399bc7..75927ba60 100644 --- a/source/common/textures/texture.cpp +++ b/source/common/textures/texture.cpp @@ -104,11 +104,6 @@ FBitmap FTexture::GetBgraBitmap(const PalEntry *remap, int *ptrans) // //=========================================================================== -#define APART(c) (((c)>>24)&0xff) -#define RPART(c) (((c)>>16)&0xff) -#define GPART(c) (((c)>>8)&0xff) -#define BPART(c) ((c)&0xff) - PalEntry FTexture::averageColor(const uint32_t *data, int size, int maxout) { int i; diff --git a/source/common/utility/name.cpp b/source/common/utility/name.cpp new file mode 100644 index 000000000..c548111a7 --- /dev/null +++ b/source/common/utility/name.cpp @@ -0,0 +1,288 @@ +/* +** name.cpp +** Implements int-as-string mapping. +** +**--------------------------------------------------------------------------- +** Copyright 2005-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "name.h" +#include "superfasthash.h" +#include "cmdlib.h" + +// MACROS ------------------------------------------------------------------ + +// The number of bytes to allocate to each NameBlock unless somebody is evil +// and wants a really long name. In that case, it gets its own NameBlock +// that is just large enough to hold it. +#define BLOCK_SIZE 4096 + +// How many entries to grow the NameArray by when it needs to grow. +#define NAME_GROW_AMOUNT 256 + +// TYPES ------------------------------------------------------------------- + +// Name text is stored in a linked list of NameBlock structures. This +// is really the header for the block, with the remainder of the block +// being populated by text for names. + +struct FName::NameManager::NameBlock +{ + size_t NextAlloc; + NameBlock *NextBlock; +}; + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +FName::NameManager FName::NameData; +bool FName::NameManager::Inited; + +// Define the predefined names. +static const char *PredefinedNames[] = +{ +#define xx(n) #n, +#include "namedef.h" +#undef xx +}; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FName :: NameManager :: FindName +// +// Returns the index of a name. If the name does not exist and noCreate is +// true, then it returns false. If the name does not exist and noCreate is +// false, then the name is added to the table and its new index is returned. +// +//========================================================================== + +int FName::NameManager::FindName (const char *text, bool noCreate) +{ + if (!Inited) + { + InitBuckets (); + } + + if (text == NULL) + { + return 0; + } + + unsigned int hash = MakeKey (text); + unsigned int bucket = hash % HASH_SIZE; + int scanner = Buckets[bucket]; + + // See if the name already exists. + while (scanner >= 0) + { + if (NameArray[scanner].Hash == hash && stricmp (NameArray[scanner].Text, text) == 0) + { + return scanner; + } + scanner = NameArray[scanner].NextHash; + } + + // If we get here, then the name does not exist. + if (noCreate) + { + return 0; + } + + return AddName (text, hash, bucket); +} + +//========================================================================== +// +// The same as above, but the text length is also passed, for creating +// a name from a substring or for speed if the length is already known. +// +//========================================================================== + +int FName::NameManager::FindName (const char *text, size_t textLen, bool noCreate) +{ + if (!Inited) + { + InitBuckets (); + } + + if (text == NULL) + { + return 0; + } + + unsigned int hash = MakeKey (text, textLen); + unsigned int bucket = hash % HASH_SIZE; + int scanner = Buckets[bucket]; + + // See if the name already exists. + while (scanner >= 0) + { + if (NameArray[scanner].Hash == hash && + strnicmp (NameArray[scanner].Text, text, textLen) == 0 && + NameArray[scanner].Text[textLen] == '\0') + { + return scanner; + } + scanner = NameArray[scanner].NextHash; + } + + // If we get here, then the name does not exist. + if (noCreate) + { + return 0; + } + + return AddName (text, hash, bucket); +} + +//========================================================================== +// +// FName :: NameManager :: InitBuckets +// +// Sets up the hash table and inserts all the default names into the table. +// +//========================================================================== + +void FName::NameManager::InitBuckets () +{ + Inited = true; + memset (Buckets, -1, sizeof(Buckets)); + + // Register built-in names. 'None' must be name 0. + for (size_t i = 0; i < countof(PredefinedNames); ++i) + { + assert((0 == FindName(PredefinedNames[i], true)) && "Predefined name already inserted"); + FindName (PredefinedNames[i], false); + } +} + +//========================================================================== +// +// FName :: NameManager :: AddName +// +// Adds a new name to the name table. +// +//========================================================================== + +int FName::NameManager::AddName (const char *text, unsigned int hash, unsigned int bucket) +{ + char *textstore; + NameBlock *block = Blocks; + size_t len = strlen (text) + 1; + + // Get a block large enough for the name. Only the first block in the + // list is ever considered for name storage. + if (block == NULL || block->NextAlloc + len >= BLOCK_SIZE) + { + block = AddBlock (len); + } + + // Copy the string into the block. + textstore = (char *)block + block->NextAlloc; + strcpy (textstore, text); + block->NextAlloc += len; + + // Add an entry for the name to the NameArray + if (NumNames >= MaxNames) + { + // If no names have been defined yet, make the first allocation + // large enough to hold all the predefined names. + MaxNames += MaxNames == 0 ? countof(PredefinedNames) + NAME_GROW_AMOUNT : NAME_GROW_AMOUNT; + + NameArray = (NameEntry *)realloc (NameArray, MaxNames * sizeof(NameEntry)); + } + + NameArray[NumNames].Text = textstore; + NameArray[NumNames].Hash = hash; + NameArray[NumNames].NextHash = Buckets[bucket]; + Buckets[bucket] = NumNames; + + return NumNames++; +} + +//========================================================================== +// +// FName :: NameManager :: AddBlock +// +// Creates a new NameBlock at least large enough to hold the required +// number of chars. +// +//========================================================================== + +FName::NameManager::NameBlock *FName::NameManager::AddBlock (size_t len) +{ + NameBlock *block; + + len += sizeof(NameBlock); + if (len < BLOCK_SIZE) + { + len = BLOCK_SIZE; + } + block = (NameBlock *)malloc (len); + block->NextAlloc = sizeof(NameBlock); + block->NextBlock = Blocks; + Blocks = block; + return block; +} + +//========================================================================== +// +// FName :: NameManager :: ~NameManager +// +// Release all the memory used for name bookkeeping. +// +//========================================================================== + +FName::NameManager::~NameManager() +{ + NameBlock *block, *next; + + //C_ClearTabCommands(); + + for (block = Blocks; block != NULL; block = next) + { + next = block->NextBlock; + free (block); + } + Blocks = NULL; + + if (NameArray != NULL) + { + free (NameArray); + NameArray = NULL; + } + NumNames = MaxNames = 0; + memset (Buckets, -1, sizeof(Buckets)); +} diff --git a/source/common/utility/name.h b/source/common/utility/name.h new file mode 100644 index 000000000..76324fe7c --- /dev/null +++ b/source/common/utility/name.h @@ -0,0 +1,125 @@ +/* +** name.h +** +**--------------------------------------------------------------------------- +** Copyright 2005-2007 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifndef NAME_H +#define NAME_H + +enum ENamedName +{ +#define xx(n) NAME_##n, +#include "namedef.h" +#undef xx +}; + +class FString; + +class FName +{ +public: + FName() = default; + FName (const char *text) { Index = NameData.FindName (text, false); } + FName (const char *text, bool noCreate) { Index = NameData.FindName (text, noCreate); } + FName (const char *text, size_t textlen, bool noCreate) { Index = NameData.FindName (text, textlen, noCreate); } + FName (const FString &text); + FName (const FString &text, bool noCreate); + FName (const FName &other) = default; + FName (ENamedName index) { Index = index; } + // ~FName () {} // Names can be added but never removed. + + int GetIndex() const { return Index; } + operator int() const { return Index; } + const char *GetChars() const { return NameData.NameArray[Index].Text; } + operator const char *() const { return NameData.NameArray[Index].Text; } + + FName &operator = (const char *text) { Index = NameData.FindName (text, false); return *this; } + FName &operator = (const FString &text); + FName &operator = (const FName &other) = default; + FName &operator = (ENamedName index) { Index = index; return *this; } + + int SetName (const char *text, bool noCreate=false) { return Index = NameData.FindName (text, noCreate); } + + bool IsValidName() const { return (unsigned)Index < (unsigned)NameData.NumNames; } + + // Note that the comparison operators compare the names' indices, not + // their text, so they cannot be used to do a lexicographical sort. + bool operator == (const FName &other) const { return Index == other.Index; } + bool operator != (const FName &other) const { return Index != other.Index; } + bool operator < (const FName &other) const { return Index < other.Index; } + bool operator <= (const FName &other) const { return Index <= other.Index; } + bool operator > (const FName &other) const { return Index > other.Index; } + bool operator >= (const FName &other) const { return Index >= other.Index; } + + bool operator == (ENamedName index) const { return Index == index; } + bool operator != (ENamedName index) const { return Index != index; } + bool operator < (ENamedName index) const { return Index < index; } + bool operator <= (ENamedName index) const { return Index <= index; } + bool operator > (ENamedName index) const { return Index > index; } + bool operator >= (ENamedName index) const { return Index >= index; } + +protected: + int Index; + + struct NameEntry + { + char *Text; + unsigned int Hash; + int NextHash; + }; + + struct NameManager + { + // No constructor because we can't ensure that it actually gets + // called before any FNames are constructed during startup. This + // means this struct must only exist in the program's BSS section. + ~NameManager(); + + enum { HASH_SIZE = 1024 }; + struct NameBlock; + + NameBlock *Blocks; + NameEntry *NameArray; + int NumNames, MaxNames; + int Buckets[HASH_SIZE]; + + int FindName (const char *text, bool noCreate); + int FindName (const char *text, size_t textlen, bool noCreate); + int AddName (const char *text, unsigned int hash, unsigned int bucket); + NameBlock *AddBlock (size_t len); + void InitBuckets (); + static bool Inited; + }; + + static NameManager NameData; +}; + +#endif diff --git a/source/common/utility/namedef.h b/source/common/utility/namedef.h new file mode 100644 index 000000000..6f243f0f2 --- /dev/null +++ b/source/common/utility/namedef.h @@ -0,0 +1,6 @@ +// 'None' must always be the first name. +xx(None) +xx(Null) +xx(_) +xx(Untranslated) + diff --git a/source/common/utility/palentry.h b/source/common/utility/palentry.h index 8f4bfa6d8..e52e62cd3 100644 --- a/source/common/utility/palentry.h +++ b/source/common/utility/palentry.h @@ -80,3 +80,9 @@ inline int Luminance(int r, int g, int b) return (r * 77 + g * 143 + b * 37) >> 8; } +#define APART(c) (((c)>>24)&0xff) +#define RPART(c) (((c)>>16)&0xff) +#define GPART(c) (((c)>>8)&0xff) +#define BPART(c) ((c)&0xff) +#define MAKERGB(r,g,b) uint32_t(((r)<<16)|((g)<<8)|(b)) +#define MAKEARGB(a,r,g,b) uint32_t(((a)<<24)|((r)<<16)|((g)<<8)|(b)) diff --git a/source/common/utility/printf.h b/source/common/utility/printf.h index 0bccb04e0..479d5e9dc 100644 --- a/source/common/utility/printf.h +++ b/source/common/utility/printf.h @@ -11,78 +11,7 @@ void OSD_Printf(const char *fmt, ...) ATTRIBUTE((format(printf,1,2))); #define Printf OSD_Printf -#if 0 -#define TEXTCOLOR_ESCAPE '\034' -#define TEXTCOLOR_ESCAPESTR "\034" +void I_Error(const char *fmt, ...) ATTRIBUTE((format(printf,1,2))); -#define TEXTCOLOR_BRICK "\034A" -#define TEXTCOLOR_TAN "\034B" -#define TEXTCOLOR_GRAY "\034C" -#define TEXTCOLOR_GREY "\034C" -#define TEXTCOLOR_GREEN "\034D" -#define TEXTCOLOR_BROWN "\034E" -#define TEXTCOLOR_GOLD "\034F" -#define TEXTCOLOR_RED "\034G" -#define TEXTCOLOR_BLUE "\034H" -#define TEXTCOLOR_ORANGE "\034I" -#define TEXTCOLOR_WHITE "\034J" -#define TEXTCOLOR_YELLOW "\034K" -#define TEXTCOLOR_UNTRANSLATED "\034L" -#define TEXTCOLOR_BLACK "\034M" -#define TEXTCOLOR_LIGHTBLUE "\034N" -#define TEXTCOLOR_CREAM "\034O" -#define TEXTCOLOR_OLIVE "\034P" -#define TEXTCOLOR_DARKGREEN "\034Q" -#define TEXTCOLOR_DARKRED "\034R" -#define TEXTCOLOR_DARKBROWN "\034S" -#define TEXTCOLOR_PURPLE "\034T" -#define TEXTCOLOR_DARKGRAY "\034U" -#define TEXTCOLOR_CYAN "\034V" -#define TEXTCOLOR_ICE "\034W" -#define TEXTCOLOR_FIRE "\034X" -#define TEXTCOLOR_SAPPHIRE "\034Y" -#define TEXTCOLOR_TEAL "\034Z" -#define TEXTCOLOR_NORMAL "\034-" -#define TEXTCOLOR_BOLD "\034+" - -#define TEXTCOLOR_CHAT "\034*" -#define TEXTCOLOR_TEAMCHAT "\034!" - -#else - -#define TEXTCOLOR_BRICK "" -#define TEXTCOLOR_TAN "" -#define TEXTCOLOR_GRAY "" -#define TEXTCOLOR_GREY "" -#define TEXTCOLOR_GREEN "" -#define TEXTCOLOR_BROWN "" -#define TEXTCOLOR_GOLD "" -#define TEXTCOLOR_RED "" -#define TEXTCOLOR_BLUE "" -#define TEXTCOLOR_ORANGE "" -#define TEXTCOLOR_WHITE "" -#define TEXTCOLOR_YELLOW "" -#define TEXTCOLOR_UNTRANSLATED "" -#define TEXTCOLOR_BLACK "" -#define TEXTCOLOR_LIGHTBLUE "" -#define TEXTCOLOR_CREAM "" -#define TEXTCOLOR_OLIVE "" -#define TEXTCOLOR_DARKGREEN "" -#define TEXTCOLOR_DARKRED "" -#define TEXTCOLOR_DARKBROWN "" -#define TEXTCOLOR_PURPLE "" -#define TEXTCOLOR_DARKGRAY "" -#define TEXTCOLOR_CYAN "" -#define TEXTCOLOR_ICE "" -#define TEXTCOLOR_FIRE "" -#define TEXTCOLOR_SAPPHIRE "" -#define TEXTCOLOR_TEAL "" - -#define TEXTCOLOR_NORMAL "" -#define TEXTCOLOR_BOLD "" - -#define TEXTCOLOR_CHAT "" -#define TEXTCOLOR_TEAMCHAT "" - -#endif \ No newline at end of file +#include "../fonts/v_text.h" diff --git a/source/common/utility/sc_man.cpp b/source/common/utility/sc_man.cpp new file mode 100644 index 000000000..c35703c15 --- /dev/null +++ b/source/common/utility/sc_man.cpp @@ -0,0 +1,1006 @@ + +//************************************************************************** +//** +//** sc_man.c : Heretic 2 : Raven Software, Corp. +//** +//** $RCSfile: sc_man.c,v $ +//** $Revision: 1.3 $ +//** $Date: 96/01/06 03:23:43 $ +//** $Author: bgokey $ +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include "sc_man.h" +#include "cmdlib.h" +#include "templates.h" +#include "printf.h" +#include "name.h" +//#include "v_text.h" +#include "cache1d.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FScanner Constructor +// +//========================================================================== + +FScanner::FScanner() +{ + ScriptOpen = false; +} + +//========================================================================== +// +// FScanner Destructor +// +//========================================================================== + +FScanner::~FScanner() +{ + // Humm... Nothing to do in here. +} + +//========================================================================== +// +// FScanner Copy Constructor +// +//========================================================================== + +FScanner::FScanner(const FScanner &other) +{ + ScriptOpen = false; + *this = other; +} + +//========================================================================== +// +// FScanner :: operator = +// +//========================================================================== + +FScanner &FScanner::operator=(const FScanner &other) +{ + if (this == &other) + { + return *this; + } + if (!other.ScriptOpen) + { + Close(); + return *this; + } + + // Copy protected members + ScriptOpen = true; + ScriptName = other.ScriptName; + ScriptBuffer = other.ScriptBuffer; + ScriptPtr = other.ScriptPtr; + ScriptEndPtr = other.ScriptEndPtr; + AlreadyGot = other.AlreadyGot; + AlreadyGotLine = other.AlreadyGotLine; + LastGotToken = other.LastGotToken; + LastGotPtr = other.LastGotPtr; + LastGotLine = other.LastGotLine; + CMode = other.CMode; + Escape = other.Escape; + StateMode = other.StateMode; + StateOptions = other.StateOptions; + + // Copy public members + if (other.String == other.StringBuffer) + { + memcpy(StringBuffer, other.StringBuffer, sizeof(StringBuffer)); + BigStringBuffer = ""; + String = StringBuffer; + } + else + { + // Past practice means the string buffer must be writeable, which + // removes some of the benefit from using an FString to store + // the big string buffer. + BigStringBuffer = other.BigStringBuffer; + String = BigStringBuffer.LockBuffer(); + } + StringLen = other.StringLen; + TokenType = other.TokenType; + Number = other.Number; + Float = other.Float; + Name = other.Name; + Line = other.Line; + End = other.End; + Crossed = other.Crossed; + + return *this; +} + +//========================================================================== +// +// FScanner :: Open +// +//========================================================================== + +void FScanner::Open (const char *name) +{ + auto fr = kopenFileReader(name, 0); + if (!fr.isOpen()) + { + I_Error("Could not find script lump '%s'\n", name); + } + Close(); + auto data = fr.ReadPadded(1); + ScriptBuffer = data; + ScriptName = name; + //LumpNum = lump; + PrepareScript(); +} + +//========================================================================== +// +// FScanner :: OpenFile +// +// Loads a script from a file. Uses new/delete for memory allocation. +// +//========================================================================== + +void FScanner::OpenFile (const char *name) +{ + Close (); + auto fr = fopenFileReader(name, 0); + if (!fr.isOpen()) return; + auto data = fr.ReadPadded(1); + ScriptBuffer = data; + ScriptName = name; // This is used for error messages so the full file name is preferable + LumpNum = -1; + PrepareScript (); +} + +//========================================================================== +// +// FScanner :: OpenMem +// +// Prepares a script that is already in memory for parsing. The memory is +// copied, so you can do whatever you want with it after opening it. +// +//========================================================================== + +void FScanner::OpenMem (const char *name, const char *buffer, int size) +{ + OpenString(name, FString(buffer, size)); +} + +//========================================================================== +// +// FScanner :: OpenString +// +// Like OpenMem, but takes a string directly. +// +//========================================================================== + +void FScanner::OpenString (const char *name, FString buffer) +{ + Close (); + ScriptBuffer = buffer; + ScriptName = name; + LumpNum = -1; + PrepareScript (); +} + +//========================================================================== +// +// FScanner :: PrepareScript +// +// Prepares a script for parsing. +// +//========================================================================== + +void FScanner::PrepareScript () +{ + // The scanner requires the file to end with a '\n', so add one if + // it doesn't already. + if (ScriptBuffer.Len() == 0 || ScriptBuffer[ScriptBuffer.Len() - 1] != '\n') + { + // If the last character in the buffer is a null character, change + // it to a newline. Otherwise, append a newline to the end. + if (ScriptBuffer.Len() > 0 && ScriptBuffer[ScriptBuffer.Len() - 1] == '\0') + { + ScriptBuffer.LockBuffer()[ScriptBuffer.Len() - 1] = '\n'; + ScriptBuffer.UnlockBuffer(); + } + else + { + ScriptBuffer += '\n'; + } + } + + ScriptPtr = &ScriptBuffer[0]; + ScriptEndPtr = &ScriptBuffer[ScriptBuffer.Len()]; + Line = 1; + End = false; + ScriptOpen = true; + String = StringBuffer; + AlreadyGot = false; + LastGotToken = false; + LastGotPtr = NULL; + LastGotLine = 1; + CMode = false; + Escape = true; + StateMode = 0; + StateOptions = false; + StringBuffer[0] = '\0'; + BigStringBuffer = ""; +} + +//========================================================================== +// +// FScanner :: Close +// +//========================================================================== + +void FScanner::Close () +{ + ScriptOpen = false; + ScriptBuffer = ""; + BigStringBuffer = ""; + StringBuffer[0] = '\0'; + String = StringBuffer; +} + +//========================================================================== +// +// FScanner :: SavePos +// +// Saves the current script location for restoration later +// +//========================================================================== + +const FScanner::SavedPos FScanner::SavePos () +{ + SavedPos pos; + + CheckOpen (); + if (End) + { + pos.SavedScriptPtr = NULL; + } + else + { + pos.SavedScriptPtr = ScriptPtr; + } + pos.SavedScriptLine = Line; + return pos; +} + +//========================================================================== +// +// FScanner :: RestorePos +// +// Restores the previously saved script location +// +//========================================================================== + +void FScanner::RestorePos (const FScanner::SavedPos &pos) +{ + if (pos.SavedScriptPtr) + { + ScriptPtr = pos.SavedScriptPtr; + Line = pos.SavedScriptLine; + End = false; + } + else + { + End = true; + } + AlreadyGot = false; + LastGotToken = false; + Crossed = false; +} + +//========================================================================== +// +// FScanner :: isText +// +// Checks if this is a text file. +// +//========================================================================== + +bool FScanner::isText() +{ + for(unsigned int i=0;i= ScriptEndPtr) + { + End = true; + return false; + } + + LastGotPtr = ScriptPtr; + LastGotLine = Line; + + // In case the generated scanner does not use marker, avoid compiler warnings. + marker; +#include "sc_man_scanner.h" + LastGotToken = tokens; + return return_val; +} + +//========================================================================== +// +// FScanner :: GetString +// +//========================================================================== + +bool FScanner::GetString () +{ + return ScanString (false); +} + +//========================================================================== +// +// FScanner :: MustGetString +// +//========================================================================== + +void FScanner::MustGetString (void) +{ + if (FScanner::GetString() == false) + { + ScriptError ("Missing string (unexpected end of file)."); + } +} + +//========================================================================== +// +// FScanner :: MustGetStringName +// +//========================================================================== + +void FScanner::MustGetStringName (const char *name) +{ + MustGetString (); + if (Compare (name) == false) + { + ScriptError ("Expected '%s', got '%s'.", name, String); + } +} + +//========================================================================== +// +// FScanner :: CheckString +// +// Checks if the next token matches the specified string. Returns true if +// it does. If it doesn't, it ungets it and returns false. +// +//========================================================================== + +bool FScanner::CheckString (const char *name) +{ + if (GetString ()) + { + if (Compare (name)) + { + return true; + } + UnGet (); + } + return false; +} + +//========================================================================== +// +// FScanner :: GetToken +// +// Sets sc_Float, sc_Number, and sc_Name based on sc_TokenType. +// +//========================================================================== + +bool FScanner::GetToken () +{ + if (ScanString (true)) + { + if (TokenType == TK_NameConst) + { + Name = FName(String); + } + else if (TokenType == TK_IntConst) + { + char *stopper; + // Check for unsigned + if (String[StringLen - 1] == 'u' || String[StringLen - 1] == 'U' || + String[StringLen - 2] == 'u' || String[StringLen - 2] == 'U') + { + TokenType = TK_UIntConst; + Number = strtoul(String, &stopper, 0); + Float = (unsigned)Number; + } + else + { + Number = strtol(String, &stopper, 0); + Float = Number; + } + } + else if (TokenType == TK_FloatConst) + { + char *stopper; + Float = strtod(String, &stopper); + } + else if (TokenType == TK_StringConst) + { + StringLen = strbin(String); + } + return true; + } + return false; +} + +//========================================================================== +// +// FScanner :: MustGetAnyToken +// +//========================================================================== + +void FScanner::MustGetAnyToken (void) +{ + if (GetToken () == false) + { + ScriptError ("Missing token (unexpected end of file)."); + } +} + +//========================================================================== +// +// FScanner :: TokenMustBe +// +//========================================================================== + +void FScanner::TokenMustBe (int token) +{ + if (TokenType != token) + { + FString tok1 = TokenName(token); + FString tok2 = TokenName(TokenType, String); + ScriptError ("Expected %s but got %s instead.", tok1.GetChars(), tok2.GetChars()); + } +} + +//========================================================================== +// +// FScanner :: MustGetToken +// +//========================================================================== + +void FScanner::MustGetToken (int token) +{ + MustGetAnyToken (); + TokenMustBe(token); +} + +//========================================================================== +// +// FScanner :: CheckToken +// +// Checks if the next token matches the specified token. Returns true if +// it does. If it doesn't, it ungets it and returns false. +// +//========================================================================== + +bool FScanner::CheckToken (int token) +{ + if (GetToken ()) + { + if (TokenType == token) + { + return true; + } + UnGet (); + } + return false; +} + +//========================================================================== +// +// FScanner :: GetNumber +// +//========================================================================== + +bool FScanner::GetNumber () +{ + char *stopper; + + CheckOpen(); + if (GetString()) + { + if (strcmp (String, "MAXINT") == 0) + { + Number = INT_MAX; + } + else + { + Number = strtol (String, &stopper, 0); + if (*stopper != 0) + { + ScriptError ("SC_GetNumber: Bad numeric constant \"%s\".", String); + } + } + Float = Number; + return true; + } + else + { + return false; + } +} + +//========================================================================== +// +// FScanner :: MustGetNumber +// +//========================================================================== + +void FScanner::MustGetNumber () +{ + if (GetNumber() == false) + { + ScriptError ("Missing integer (unexpected end of file)."); + } +} + +//========================================================================== +// +// FScanner :: CheckNumber +// +// similar to GetNumber but ungets the token if it isn't a number +// and does not print an error +// +//========================================================================== + +bool FScanner::CheckNumber () +{ + char *stopper; + + if (GetString()) + { + if (String[0] == 0) + { + UnGet(); + return false; + } + else if (strcmp (String, "MAXINT") == 0) + { + Number = INT_MAX; + } + else + { + Number = strtol (String, &stopper, 0); + if (*stopper != 0) + { + UnGet(); + return false; + } + } + Float = Number; + return true; + } + else + { + return false; + } +} + +//========================================================================== +// +// FScanner :: CheckFloat +// +// [GRB] Same as SC_CheckNumber, only for floats +// +//========================================================================== + +bool FScanner::CheckFloat () +{ + char *stopper; + + if (GetString()) + { + if (String[0] == 0) + { + UnGet(); + return false; + } + + Float = strtod (String, &stopper); + if (*stopper != 0) + { + UnGet(); + return false; + } + return true; + } + else + { + return false; + } +} + + +//========================================================================== +// +// FScanner :: GetFloat +// +//========================================================================== + +bool FScanner::GetFloat () +{ + char *stopper; + + CheckOpen (); + if (GetString()) + { + Float = strtod (String, &stopper); + if (*stopper != 0) + { + ScriptError ("SC_GetFloat: Bad numeric constant \"%s\".", String); + } + Number = (int)Float; + return true; + } + else + { + return false; + } +} + +//========================================================================== +// +// FScanner :: MustGetFloat +// +//========================================================================== + +void FScanner::MustGetFloat () +{ + if (GetFloat() == false) + { + ScriptError ("Missing floating-point number (unexpected end of file)."); + } +} + +//========================================================================== +// +// FScanner :: UnGet +// +// Assumes there is a valid string in String. +// +//========================================================================== + +void FScanner::UnGet () +{ + AlreadyGot = true; + AlreadyGotLine = LastGotLine; // in case of an error we want the line of the last token. +} + +//========================================================================== +// +// FScanner :: MatchString +// +// Returns the index of the first match to String from the passed +// array of strings, or -1 if not found. +// +//========================================================================== + +int FScanner::MatchString (const char * const *strings, size_t stride) +{ + int i; + + assert(stride % sizeof(const char*) == 0); + + stride /= sizeof(const char*); + + for (i = 0; *strings != NULL; i++) + { + if (Compare (*strings)) + { + return i; + } + strings += stride; + } + return -1; +} + +//========================================================================== +// +// FScanner :: MustMatchString +// +//========================================================================== + +int FScanner::MustMatchString (const char * const *strings, size_t stride) +{ + int i; + + i = MatchString (strings, stride); + if (i == -1) + { + ScriptError ("Unknown keyword '%s'", String); + } + return i; +} + +//========================================================================== +// +// FScanner :: Compare +// +//========================================================================== + +bool FScanner::Compare (const char *text) +{ + return (stricmp (text, String) == 0); +} + +//========================================================================== +// +// FScanner :: TokenName +// +// Returns the name of a token. +// +//========================================================================== + +FString FScanner::TokenName (int token, const char *string) +{ + static const char *const names[] = + { +#define xx(sym,str) str, +#include "sc_man_tokens.h" + }; + + FString work; + + if (token > ' ' && token < 256) + { + work = '\''; + work += token; + work += '\''; + } + else if (token >= TK_Identifier && token < TK_LastToken) + { + work = names[token - TK_Identifier]; + if (string != NULL && token >= TK_Identifier && token <= TK_FloatConst) + { + work += ' '; + char quote = (token == TK_StringConst) ? '"' : '\''; + work += quote; + work += string; + work += quote; + } + } + else + { + FString work; + work.Format ("Unknown(%d)", token); + return work; + } + return work; +} + +//========================================================================== +// +// FScanner::GetMessageLine +// +//========================================================================== + +int FScanner::GetMessageLine() +{ + return AlreadyGot? AlreadyGotLine : Line; +} + +//========================================================================== +// +// FScanner::ScriptError +// +//========================================================================== + +void FScanner::ScriptError (const char *message, ...) +{ + FString composed; + + if (message == NULL) + { + composed = "Bad syntax."; + } + else + { + va_list arglist; + va_start (arglist, message); + composed.VFormat (message, arglist); + va_end (arglist); + } + + I_Error ("Script error, \"%s\" line %d:\n%s\n", ScriptName.GetChars(), + AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); +} + +//========================================================================== +// +// FScanner::ScriptMessage +// +//========================================================================== + +void FScanner::ScriptMessage (const char *message, ...) +{ + FString composed; + + if (message == NULL) + { + composed = "Bad syntax."; + } + else + { + va_list arglist; + va_start (arglist, message); + composed.VFormat (message, arglist); + va_end (arglist); + } + + Printf (TEXTCOLOR_RED "Script error, \"%s\" line %d:\n" TEXTCOLOR_RED "%s\n", ScriptName.GetChars(), + AlreadyGot? AlreadyGotLine : Line, composed.GetChars()); +} + +//========================================================================== +// +// FScanner :: CheckOpen +// +//========================================================================== + +void FScanner::CheckOpen() +{ + if (ScriptOpen == false) + { + I_Error ("SC_ call before SC_Open()."); + } +} + + +//========================================================================== +// +// ParseHex +// +//========================================================================== + +int ParseHex(const char* hex) +{ + const char* str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str - '0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str - 'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str - 'A'; + else { + Printf("Bad hex number: %s\n", hex); + return 0; + } + str++; + } + + return num; +} + + \ No newline at end of file diff --git a/source/common/utility/sc_man.h b/source/common/utility/sc_man.h new file mode 100644 index 000000000..1f7cec576 --- /dev/null +++ b/source/common/utility/sc_man.h @@ -0,0 +1,141 @@ +#ifndef __SC_MAN_H__ +#define __SC_MAN_H__ + +#include "zstring.h" +#include "name.h" +#include "basics.h" + +class FScanner +{ +public: + struct SavedPos + { + const char *SavedScriptPtr; + int SavedScriptLine; + }; + + // Methods ------------------------------------------------------ + FScanner(); + FScanner(const FScanner &other); + FScanner(int lumpnum); + ~FScanner(); + + FScanner &operator=(const FScanner &other); + + void Open(const char *lumpname); + void OpenFile(const char *filename); + void OpenMem(const char *name, const char *buffer, int size); + void OpenString(const char *name, FString buffer); + void Close(); + + void SetCMode(bool cmode); + void SetEscape(bool esc); + void SetStateMode(bool stately); + void DisableStateOptions(); + const SavedPos SavePos(); + void RestorePos(const SavedPos &pos); + + static FString TokenName(int token, const char *string=NULL); + + bool GetString(); + void MustGetString(); + void MustGetStringName(const char *name); + bool CheckString(const char *name); + + bool GetToken(); + void MustGetAnyToken(); + void TokenMustBe(int token); + void MustGetToken(int token); + bool CheckToken(int token); + bool CheckTokenId(ENamedName id); + + bool GetNumber(); + void MustGetNumber(); + bool CheckNumber(); + + bool GetFloat(); + void MustGetFloat(); + bool CheckFloat(); + + void UnGet(); + + bool Compare(const char *text); + int MatchString(const char * const *strings, size_t stride = sizeof(char*)); + int MustMatchString(const char * const *strings, size_t stride = sizeof(char*)); + int GetMessageLine(); + + void ScriptError(const char *message, ...) GCCPRINTF(2,3); + void ScriptMessage(const char *message, ...) GCCPRINTF(2,3); + + bool isText(); + + // Members ------------------------------------------------------ + char *String; + int StringLen; + int TokenType; + int Number; + double Float; + FName Name; + int Line; + bool End; + bool Crossed; + int LumpNum; + FString ScriptName; + +protected: + void PrepareScript(); + void CheckOpen(); + bool ScanString(bool tokens); + + // Strings longer than this minus one will be dynamically allocated. + static const int MAX_STRING_SIZE = 128; + + bool ScriptOpen; + FString ScriptBuffer; + const char *ScriptPtr; + const char *ScriptEndPtr; + char StringBuffer[MAX_STRING_SIZE]; + FString BigStringBuffer; + bool AlreadyGot; + int AlreadyGotLine; + bool LastGotToken; + const char *LastGotPtr; + int LastGotLine; + bool CMode; + BYTE StateMode; + bool StateOptions; + bool Escape; +}; + +enum +{ + TK_SequenceStart = 256, +#define xx(sym,str) sym, +#include "sc_man_tokens.h" + TK_LastToken +}; + + +//========================================================================== +// +// +// +//========================================================================== + +enum +{ + MSG_WARNING, + MSG_FATAL, + MSG_ERROR, + MSG_OPTERROR, + MSG_DEBUGERROR, + MSG_DEBUGWARN, + MSG_DEBUGMSG, + MSG_LOG, + MSG_DEBUGLOG, + MSG_MESSAGE +}; + +int ParseHex(const char* hex); + +#endif //__SC_MAN_H__ diff --git a/source/common/utility/sc_man_scanner.re b/source/common/utility/sc_man_scanner.re new file mode 100644 index 000000000..9c4007518 --- /dev/null +++ b/source/common/utility/sc_man_scanner.re @@ -0,0 +1,389 @@ +#define YYCTYPE unsigned char +#define YYCURSOR cursor +#define YYLIMIT limit +#define YYMARKER marker +#define YYFILL(n) {} +#if 0 // As long as the buffer ends with '\n', we need do nothing special for YYFILL. + // This buffer must be as large as the largest YYFILL call + YYCTYPE eofbuf[9]; +#define YYFILL(n) \ + { if(!sc_End) { \ + if(n == 2) { eofbuf[0] = *cursor; } \ + else if(n >= 3 && n <= 9) { memcpy(eofbuf, cursor, n-1); } \ + eofbuf[n-1] = '\n'; \ + cursor = eofbuf; \ + limit = eofbuf + n - 1; \ + sc_End = true; } \ + } \ + assert(n <= sizeof eofbuf) // Semicolon intentionally omitted +#endif + +//#define YYDEBUG(s,c) { Printf ("%d: %02x\n", s, c); } +#define YYDEBUG(s,c) + + const char *cursor = ScriptPtr; + const char *limit = ScriptEndPtr; + +std1: + tok = YYCURSOR; +std2: +/*!re2c + any = [\000-\377]; + WSP = ([\000- ]\[\n]); + NWS = (any\[\000- ]); + O = [0-7]; + D = [0-9]; + L = [a-zA-Z_]; + H = [a-fA-F0-9]; + E = [Ee] [+-]? D+; + FS = [fF]; + IS = [uUlL]; + ESC = [\\] ([abcfnrtv?'"\\] | "x" H+ | O+); + + TOK1 = [{}|=]; + TOKC = [{}|=/`~!@#$%^&*()\[\]\\?\-=+;:<>,.]; + + STOP1 = (TOK1|["/;]); + STOPC = (TOKC|["]); + + TOK2 = (NWS\STOP1); + TOKC2 = (NWS\STOPC); +*/ +#define RET(x) TokenType = (x); goto normal_token; + if (tokens && StateMode != 0) + { + /*!re2c + "/*" { goto comment; } /* C comment */ + "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ + ("#region"|"#endregion") (any\"\n")* "\n" + { goto newline; } /* Region blocks [mxd] */ + + (["](([\\]["])|[^"])*["]) { RET(TK_StringConst); } + 'stop' { RET(TK_Stop); } + 'wait' { RET(TK_Wait); } + 'fail' { RET(TK_Fail); } + 'loop' { RET(TK_Loop); } + 'goto' { StateMode = 0; StateOptions = false; RET(TK_Goto); } + ":" { RET(':'); } + ";" { RET(';'); } + "}" { StateMode = 0; StateOptions = false; RET('}'); } + + WSP+ { goto std1; } + "\n" { goto newline; } + + TOKS = (NWS\[/":;}]); + TOKS* ([/] (TOKS\[*]) TOKS*)* + { RET(TK_NonWhitespace); } + + */ + } + else if (tokens) // A well-defined scanner, based on the c.re example. + { + /*!re2c + "/*" { goto comment; } /* C comment */ + "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ + ("#region"|"#endregion") (any\"\n")* "\n" + { goto newline; } /* Region blocks [mxd] */ + + + /* other DECORATE top level keywords */ + '#include' { RET(TK_Include); } + + L (L|D)* { RET(TK_Identifier); } + + ("0" [xX] H+ IS?IS?) | ("0" D+ IS?IS?) | (D+ IS?IS?) + { RET(TK_IntConst); } + + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) + { RET(TK_FloatConst); } + + (["](([\\]["])|[^"])*["]) + { RET(TK_StringConst); } + + (['] (any\[\n'])* [']) + { RET(TK_NameConst); } + + ".." { RET(TK_DotDot); } + "..." { RET(TK_Ellipsis); } + ">>>=" { RET(TK_URShiftEq); } + ">>=" { RET(TK_RShiftEq); } + "<<=" { RET(TK_LShiftEq); } + "+=" { RET(TK_AddEq); } + "-=" { RET(TK_SubEq); } + "*=" { RET(TK_MulEq); } + "/=" { RET(TK_DivEq); } + "%=" { RET(TK_ModEq); } + "&=" { RET(TK_AndEq); } + "^=" { RET(TK_XorEq); } + "|=" { RET(TK_OrEq); } + ">>>" { RET(TK_URShift); } + ">>" { RET(TK_RShift); } + "<<" { RET(TK_LShift); } + "++" { RET(TK_Incr); } + "--" { RET(TK_Decr); } + "&&" { RET(TK_AndAnd); } + "||" { RET(TK_OrOr); } + "<=" { RET(TK_Leq); } + ">=" { RET(TK_Geq); } + "==" { RET(TK_Eq); } + "!=" { RET(TK_Neq); } + "~==" { RET(TK_ApproxEq); } + "<>=" { RET(TK_LtGtEq); } + "**" { RET(TK_MulMul); } + "::" { RET(TK_ColonColon); } + "->" { RET(TK_Arrow); } + ";" { RET(';'); } + "{" { RET('{'); } + "}" { RET('}'); } + "," { RET(','); } + ":" { RET(':'); } + "=" { RET('='); } + "(" { RET('('); } + ")" { RET(')'); } + "[" { RET('['); } + "]" { RET(']'); } + "." { RET('.'); } + "&" { RET('&'); } + "!" { RET('!'); } + "~" { RET('~'); } + "-" { RET('-'); } + "+" { RET('+'); } + "*" { RET('*'); } + "/" { RET('/'); } + "%" { RET('%'); } + "<" { RET('<'); } + ">" { RET('>'); } + "^" { RET('^'); } + "|" { RET('|'); } + "?" { RET('?'); } + + [ \t\v\f\r]+ { goto std1; } + "\n" { goto newline; } + any + { + ScriptError ("Unexpected character: %c (ASCII %d)\n", *tok, *tok); + goto std1; + } + */ + } + if (!CMode) // The classic Hexen scanner. + { + /*!re2c + "/*" { goto comment; } /* C comment */ + ("//"|";") (any\"\n")* "\n" { goto newline; } /* C++/Hexen comment */ + ("#region"|"#endregion") (any\"\n")* "\n" + { goto newline; } /* Region blocks [mxd] */ + + WSP+ { goto std1; } /* whitespace */ + "\n" { goto newline; } + "\"" { goto string; } + + TOK1 { goto normal_token; } + + /* Regular tokens may contain /, but they must not contain comment starts */ + TOK2* ([/] (TOK2\[*]) TOK2*)* { goto normal_token; } + + any { goto normal_token; } /* unknown character */ + */ + } + else // A modified Hexen scanner for DECORATE. + { + /*!re2c + "/*" { goto comment; } /* C comment */ + "//" (any\"\n")* "\n" { goto newline; } /* C++ comment */ + ("#region"|"#endregion") (any\"\n")* "\n" + { goto newline; } /* Region blocks [mxd] */ + + WSP+ { goto std1; } /* whitespace */ + "\n" { goto newline; } + "\"" { goto string; } + + [-] { goto negative_check; } + ((D* [.] D+) | (D+ [.] D*)) { goto normal_token; } /* decimal number */ + (D+ E FS?) | (D* "." D+ E? FS?) | (D+ "." D* E? FS?) { goto normal_token; } /* float with exponent */ + "::" { goto normal_token; } + "&&" { goto normal_token; } + "==" { goto normal_token; } + "||" { goto normal_token; } + "<<" { goto normal_token; } + ">>" { goto normal_token; } + TOKC { goto normal_token; } + TOKC2+ { goto normal_token; } + + any { goto normal_token; } /* unknown character */ + */ + } + +negative_check: + // re2c doesn't have enough state to handle '-' as the start of a negative number + // and as its own token, so help it out a little. + TokenType = '-'; + if (YYCURSOR >= YYLIMIT) + { + goto normal_token; + } + if (*YYCURSOR >= '0' && *YYCURSOR <= '9') + { + goto std2; + } + if (*YYCURSOR != '.' || YYCURSOR+1 >= YYLIMIT) + { + goto normal_token; + } + if (*(YYCURSOR+1) >= '0' && *YYCURSOR <= '9') + { + goto std2; + } + goto normal_token; + +comment: +/*!re2c + "*/" + { + if (YYCURSOR >= YYLIMIT) + { + ScriptPtr = ScriptEndPtr; + return_val = false; + goto end; + } + goto std1; + } + "\n" + { + if (YYCURSOR >= YYLIMIT) + { + ScriptPtr = ScriptEndPtr; + return_val = false; + goto end; + } + Line++; + Crossed = true; + goto comment; + } + any { goto comment; } +*/ + +newline: + if (YYCURSOR >= YYLIMIT) + { + ScriptPtr = ScriptEndPtr; + return_val = false; + goto end; + } + Line++; + Crossed = true; + goto std1; + +normal_token: + ScriptPtr = (YYCURSOR >= YYLIMIT) ? ScriptEndPtr : cursor; + StringLen = int(ScriptPtr - tok); + if (tokens && (TokenType == TK_StringConst || TokenType == TK_NameConst)) + { + StringLen -= 2; + if (StringLen >= MAX_STRING_SIZE) + { + BigStringBuffer = FString(tok+1, StringLen); + } + else + { + memcpy (StringBuffer, tok+1, StringLen); + } + if (StateMode && TokenType == TK_StringConst) + { + TokenType = TK_NonWhitespace; + } + } + else + { + if (StringLen >= MAX_STRING_SIZE) + { + BigStringBuffer = FString(tok, StringLen); + } + else + { + memcpy (StringBuffer, tok, StringLen); + } + } + if (tokens && StateMode) + { // State mode is exited after two consecutive TK_NonWhitespace tokens + if (TokenType == TK_NonWhitespace) + { + StateMode--; + } + else + { + StateMode = 2; + } + } + if (StringLen < MAX_STRING_SIZE) + { + String = StringBuffer; + StringBuffer[StringLen] = '\0'; + } + else + { + String = BigStringBuffer.LockBuffer(); + } + return_val = true; + goto end; + +string: + if (YYLIMIT != ScriptEndPtr) + { + ScriptPtr = ScriptEndPtr; + return_val = false; + goto end; + } + ScriptPtr = cursor; + BigStringBuffer = ""; + for (StringLen = 0; cursor < YYLIMIT; ++cursor) + { + if (Escape && *cursor == '\\' && *(cursor + 1) == '"') + { + cursor++; + } + else if (*cursor == '\r' && *(cursor + 1) == '\n') + { + cursor++; // convert CR-LF to simply LF + } + else if (*cursor == '"') + { + break; + } + if (*cursor == '\n') + { + if (CMode) + { + if (!Escape || StringLen == 0 || String[StringLen - 1] != '\\') + { + ScriptError ("Unterminated string constant"); + } + else + { + StringLen--; // overwrite the \ character with \n + } + } + Line++; + Crossed = true; + } + if (StringLen == MAX_STRING_SIZE) + { + BigStringBuffer.AppendCStrPart(StringBuffer, StringLen); + StringLen = 0; + } + StringBuffer[StringLen++] = *cursor; + } + if (BigStringBuffer.IsNotEmpty() || StringLen == MAX_STRING_SIZE) + { + BigStringBuffer.AppendCStrPart(StringBuffer, StringLen); + String = BigStringBuffer.LockBuffer(); + StringLen = int(BigStringBuffer.Len()); + } + else + { + String = StringBuffer; + StringBuffer[StringLen] = '\0'; + } + ScriptPtr = cursor + 1; + return_val = true; +end: diff --git a/source/common/utility/sc_man_tokens.h b/source/common/utility/sc_man_tokens.h new file mode 100644 index 000000000..efa479cf3 --- /dev/null +++ b/source/common/utility/sc_man_tokens.h @@ -0,0 +1,146 @@ +xx(TK_Identifier, "identifier") +xx(TK_StringConst, "string constant") +xx(TK_NameConst, "name constant") +xx(TK_IntConst, "integer constant") +xx(TK_UIntConst, "unsigned constant") +xx(TK_FloatConst, "float constant") +xx(TK_NonWhitespace, "non-whitespace") +xx(TK_ColonColon, "'::'") +xx(TK_DotDot, "'..'") +xx(TK_Ellipsis, "'...'") +xx(TK_RShiftEq, "'>>='") +xx(TK_URShiftEq, "'>>>='") +xx(TK_LShiftEq, "'<<='") +xx(TK_AddEq, "'+='") +xx(TK_SubEq, "'-='") +xx(TK_MulEq, "'*='") +xx(TK_DivEq, "'/='") +xx(TK_ModEq, "'%='") +xx(TK_AndEq, "'&='") +xx(TK_XorEq, "'^='") +xx(TK_OrEq, "'|='") +xx(TK_RShift, "'>>'") +xx(TK_URShift, "'>>>'") +xx(TK_LShift, "'<<'") +xx(TK_Incr, "'++'") +xx(TK_Decr, "'--'") +xx(TK_AndAnd, "'&&'") +xx(TK_OrOr, "'||'") +xx(TK_Leq, "'<='") +xx(TK_Geq, "'>='") +xx(TK_Eq, "'=='") +xx(TK_Neq, "'!='") +xx(TK_ApproxEq, "'~=='") +xx(TK_LtGtEq, "'<>='") +xx(TK_MulMul, "'**'") +xx(TK_Arrow, "'->'") +xx(TK_Action, "'action'") +xx(TK_Break, "'break'") +xx(TK_Case, "'case'") +xx(TK_Const, "'const'") +xx(TK_Continue, "'continue'") +xx(TK_Default, "'default'") +xx(TK_Do, "'do'") +xx(TK_Else, "'else'") +xx(TK_For, "'for'") +xx(TK_If, "'if'") +xx(TK_Return, "'return'") +xx(TK_Switch, "'switch'") +xx(TK_Until, "'until'") +xx(TK_While, "'while'") +xx(TK_Bool, "'bool'") +xx(TK_Float, "'float'") +xx(TK_Float32, "'float32'") +xx(TK_Double, "'double'") +xx(TK_Char, "'char'") +xx(TK_Byte, "'byte'") +xx(TK_SByte, "'sbyte'") +xx(TK_Short, "'short'") +xx(TK_UShort, "'ushort'") +xx(TK_Int8, "'int8'") +xx(TK_UInt8, "'uint8'") +xx(TK_Int16, "'int16'") +xx(TK_UInt16, "'uint16'") +xx(TK_Int, "'int'") +xx(TK_UInt, "'uint'") +xx(TK_Long, "'long'") +xx(TK_ULong, "'ulong'") +xx(TK_Void, "'void'") +xx(TK_Struct, "'struct'") +xx(TK_Class, "'class'") +xx(TK_Enum, "'enum'") +xx(TK_Name, "'name'") +xx(TK_String, "'string'") +xx(TK_Sound, "'sound'") +xx(TK_State, "'state'") +xx(TK_Color, "'color'") +xx(TK_Goto, "'goto'") +xx(TK_Abstract, "'abstract'") +xx(TK_ForEach, "'foreach'") +xx(TK_True, "'true'") +xx(TK_False, "'false'") +xx(TK_None, "'none'") +xx(TK_New, "'new'") +xx(TK_InstanceOf, "'instanceof'") +xx(TK_Auto, "'auto'") +xx(TK_Exec, "'exec'") +xx(TK_DefaultProperties, "'defaultproperties'") +xx(TK_Native, "'native'") +xx(TK_Var, "'var'") +xx(TK_Out, "'out'") +xx(TK_Ref, "'ref'") +xx(TK_Event, "'event'") +xx(TK_Static, "'static'") +xx(TK_Transient, "'transient'") +xx(TK_Volatile, "'volatile'") +xx(TK_Final, "'final'") +xx(TK_Throws, "'throws'") +xx(TK_Extend, "'extend'") +xx(TK_Public, "'public'") +xx(TK_Protected, "'protected'") +xx(TK_Private, "'private'") +xx(TK_Dot, "'dot'") +xx(TK_Cross, "'cross'") +xx(TK_Ignores, "'ignores'") +xx(TK_Localized, "'localized'") +xx(TK_Latent, "'latent'") +xx(TK_Singular, "'singular'") +xx(TK_Config, "'config'") +xx(TK_Coerce, "'coerce'") +xx(TK_Iterator, "'iterator'") +xx(TK_Optional, "'optional'") +xx(TK_Export, "'expert'") +xx(TK_Virtual, "'virtual'") +xx(TK_Override, "'override'") +xx(TK_Super, "'super'") +xx(TK_Null, "'null'") +xx(TK_Global, "'global'") +xx(TK_Stop, "'stop'") +xx(TK_Include, "'include'") + +xx(TK_Is, "'is'") +xx(TK_Replaces, "'replaces'") +xx(TK_Vector2, "'vector2'") +xx(TK_Vector3, "'vector3'") +xx(TK_Map, "'map'") +xx(TK_Array, "'array'") +xx(TK_In, "'in'") +xx(TK_SizeOf, "'sizeof'") +xx(TK_AlignOf, "'alignof'") +xx(TK_States, "'states'") +xx(TK_Loop, "'loop'") +xx(TK_Fail, "'fail'") +xx(TK_Wait, "'wait'") +xx(TK_Meta, "'meta'") +xx(TK_Deprecated, "'deprecated'") +xx(TK_ReadOnly, "'readonly'") + +xx(TK_CanRaise, "'canraise'") +xx(TK_Fast, "'fast'") +xx(TK_Light, "'light'") +xx(TK_NoDelay, "'nodelay'") +xx(TK_Offset, "'offset'") +xx(TK_Slow, "'slow'") +xx(TK_Bright, "'bright'") +xx(TK_Let, "'let'") +#undef xx diff --git a/source/duke3d/src/screens.cpp b/source/duke3d/src/screens.cpp index 8cd5d0ed2..00591ce48 100644 --- a/source/duke3d/src/screens.cpp +++ b/source/duke3d/src/screens.cpp @@ -1447,7 +1447,6 @@ void gameDisplay3DRScreen() { if (!I_GeneralTrigger() && g_noLogoAnim == 0) { - buildvfs_kfd i; Net_GetPackets(); if (testkopen("3dr.ivf", 0) || testkopen("3dr.anm", 0)) diff --git a/source/sw/src/config.cpp b/source/sw/src/config.cpp index fd4a0c83b..1469105e3 100644 --- a/source/sw/src/config.cpp +++ b/source/sw/src/config.cpp @@ -566,7 +566,6 @@ void CONFIG_SetupJoystick(void) int32_t CONFIG_ReadSetup(void) { - int32_t dummy; //char ret; extern char ds[]; extern char PlayerNameArg[32]; diff --git a/source/sw/src/sector.cpp b/source/sw/src/sector.cpp index ea4f0cd12..ea9e41c8c 100644 --- a/source/sw/src/sector.cpp +++ b/source/sw/src/sector.cpp @@ -1024,9 +1024,11 @@ OperateWall(short wallnum, short player_is_operating) { WALLp wallp = &wall[wallnum]; + /* switch (LOW_TAG_WALL(wallnum)) { } + */ return FALSE; }