diff --git a/prboom2/src/CMakeLists.txt b/prboom2/src/CMakeLists.txt index f5d24c2aa..a2455c441 100644 --- a/prboom2/src/CMakeLists.txt +++ b/prboom2/src/CMakeLists.txt @@ -245,6 +245,16 @@ set(COMMON_SRC dsda/wad_stats.h dsda/zipfile.c dsda/zipfile.h + textscreen/doomkeys.h + textscreen/txt_main.h + textscreen/txt_sdl.c + textscreen/txt_sdl.h + textscreen/txt_utf8.c + textscreen/txt_utf8.h + textscreen/fonts/convert-font + textscreen/fonts/normal.h + textscreen/fonts/hauge-8x18-v1-6.png + textscreen/fonts/README dstrings.c dstrings.h d_deh.c diff --git a/prboom2/src/SDL/i_main.c b/prboom2/src/SDL/i_main.c index 01ce933df..bc722125e 100644 --- a/prboom2/src/SDL/i_main.c +++ b/prboom2/src/SDL/i_main.c @@ -219,6 +219,7 @@ static void I_Quit (void) { M_SaveDefaults (); dsda_DumpEndoom(); + dsda_Shutdown(); } // diff --git a/prboom2/src/SDL/i_video.c b/prboom2/src/SDL/i_video.c index 4ebfeaee7..920ad1351 100644 --- a/prboom2/src/SDL/i_video.c +++ b/prboom2/src/SDL/i_video.c @@ -128,6 +128,16 @@ SDL_Rect window_rect = { 0, 0, 0, 0 }; // Physical window SDL_Rect renderer_rect = { 0, 0, 0, 0 }; // The window, but with HiDPI accounted SDL_Rect viewport_rect = { 0, 0, 0, 0 }; // The renderer, but without the black bars +void *I_GetSDLWindow(void) +{ + return sdl_window; +} + +void *I_GetSDLRenderer(void) +{ + return sdl_renderer; +} + //////////////////////////////////////////////////////////////////////////// // Input code int leds_always_off = 0; // Expected by m_misc, not relevant @@ -673,6 +683,11 @@ static void I_ShutdownSDL(void) return; } +void dsda_Shutdown(void) +{ + I_AtExit(I_ShutdownSDL, true, "I_ShutdownSDL", exit_priority_normal); +} + void I_PreInitGraphics(void) { int p; @@ -691,7 +706,7 @@ void I_PreInitGraphics(void) I_Error("Could not initialize SDL [%s]", SDL_GetError()); } - I_AtExit(I_ShutdownSDL, true, "I_ShutdownSDL", exit_priority_normal); + // No longer call `I_ShutdownSDL()` here cuz we need window/renderer info for ENDOOM later on } // e6y: resolution limitation is removed diff --git a/prboom2/src/d_main.c b/prboom2/src/d_main.c index 53826841b..e82a48433 100644 --- a/prboom2/src/d_main.c +++ b/prboom2/src/d_main.c @@ -2018,6 +2018,10 @@ static void D_DoomMainSetup(void) //e6y: some stuff from command-line should be initialised before ProcessDehFile() e6y_InitCommandLine(); + // Check arguments for demoplayback / demorecording + started_demo = dsda_Flag(dsda_arg_record) || dsda_Flag(dsda_arg_recordfromto) || + dsda_Flag(dsda_arg_playdemo) || dsda_Flag(dsda_arg_timedemo) || dsda_Flag(dsda_arg_fastdemo); + D_AddFile(port_wad_file, source_auto_load); HandlePlayback(); // must come before autoload: may detect iwad in footer diff --git a/prboom2/src/doomdef.h b/prboom2/src/doomdef.h index 06084493b..3d1cde44e 100644 --- a/prboom2/src/doomdef.h +++ b/prboom2/src/doomdef.h @@ -420,6 +420,8 @@ typedef enum { #define ORIG_FRICTION_FACTOR 2048 // original value #define FRICTION_FLY 0xeb00 +extern dboolean started_demo; + extern dboolean raven; // heretic diff --git a/prboom2/src/dsda/configuration.c b/prboom2/src/dsda/configuration.c index 30c907ab7..20e48a60f 100644 --- a/prboom2/src/dsda/configuration.c +++ b/prboom2/src/dsda/configuration.c @@ -1318,6 +1318,14 @@ dsda_config_t dsda_config[dsda_config_count] = { "invert_analog_look", dsda_config_invert_analog_look, CONF_BOOL(0), }, + [dsda_config_show_endoom] = { + "show_endoom", dsda_config_show_endoom, + dsda_config_int, 0, 2, { 2 } + }, + [dsda_config_export_endoom] = { + "export_endoom", dsda_config_export_endoom, + CONF_BOOL(0), + }, [dsda_config_ansi_endoom] = { "ansi_endoom", dsda_config_ansi_endoom, dsda_config_int, 0, 2, { 0 } diff --git a/prboom2/src/dsda/configuration.h b/prboom2/src/dsda/configuration.h index 5d84c6000..baadfd3ac 100644 --- a/prboom2/src/dsda/configuration.h +++ b/prboom2/src/dsda/configuration.h @@ -296,6 +296,8 @@ typedef enum { dsda_config_analog_look_acceleration, dsda_config_swap_analogs, dsda_config_invert_analog_look, + dsda_config_show_endoom, + dsda_config_export_endoom, dsda_config_ansi_endoom, dsda_config_quit_sounds, dsda_config_announce_map, diff --git a/prboom2/src/dsda/endoom.c b/prboom2/src/dsda/endoom.c index be0e23574..2e968de7a 100644 --- a/prboom2/src/dsda/endoom.c +++ b/prboom2/src/dsda/endoom.c @@ -22,13 +22,18 @@ #include "doomdef.h" #include "doomtype.h" +#include "i_video.h" #include "lprintf.h" #include "w_wad.h" #include "dsda/configuration.h" +#include "textscreen/txt_main.h" #include "endoom.h" +#define ENDOOM_W 80 +#define ENDOOM_H 25 + static const char* cp437_to_utf8[256] = { " ", "\xe2\x98\xba", @@ -309,8 +314,14 @@ typedef enum { format_utf8, } output_format_t; +typedef enum { + endoom_window, + endoom_terminal, +} endoom_export_t; + static byte* endoom; static output_format_t output_format; +static endoom_export_t endoom_export; #ifdef _WIN32 static HANDLE hConsole; @@ -341,12 +352,24 @@ static void RestoreOldMode(void) { } #endif +int is_opengl = false; + void dsda_CacheEndoom(void) { int lump; + int show_endoom; + int pwad_only; output_format = dsda_IntConfig(dsda_config_ansi_endoom); - if (!output_format) + show_endoom = dsda_IntConfig(dsda_config_show_endoom); + + if (V_IsOpenGLMode()) + is_opengl = true; + + if (started_demo) + return; + + if (show_endoom==0) return; if (hexen) @@ -360,7 +383,9 @@ void dsda_CacheEndoom(void) { lump = W_CheckNumForName("ENDOOM"); } - if (lump == LUMP_NOT_FOUND || W_LumpLength(lump) != 4000) + pwad_only = (show_endoom==2 && !W_PWADLumpNumExists(lump) && W_PWADMapExists()); + + if (lump == LUMP_NOT_FOUND || W_LumpLength(lump) != 4000 || pwad_only) return; endoom = Z_Malloc(4000); @@ -368,7 +393,23 @@ void dsda_CacheEndoom(void) { } void dsda_DumpEndoom(void) { - if (endoom) { + endoom_export = dsda_IntConfig(dsda_config_export_endoom); + + if (endoom) + { + if (endoom_export) + dsda_TerminalEndoom(); + else + dsda_WindowEndoom(); + } +} + +// +// DSDA Terminal ENDOOM +// + +void dsda_TerminalEndoom(void) +{ int i; const char* color_lookup[] = { "0", "4", "2", "6", "1", "5", "3", "7", @@ -414,5 +455,56 @@ void dsda_DumpEndoom(void) { #ifdef _WIN32 RestoreOldMode(); #endif - } +} + + +// +// Window ENDOOM +// + +void dsda_WindowEndoom(void) +{ + unsigned char *screendata; + int y; + int indent; + + // Set up text mode screen + + TXT_PreInit(I_GetSDLWindow(), I_GetSDLRenderer(), is_opengl); + + if (!TXT_Init()) + { + lprintf(LO_ERROR, "Failed to initialize libtextscreen"); + return; + } + + // Write the data to the screen memory + + screendata = TXT_GetScreenData(); + + indent = (ENDOOM_W - TXT_SCREEN_W) / 2; + + for (y = 0; y < TXT_SCREEN_H; ++y) + { + memcpy(screendata + (y * TXT_SCREEN_W * 2), + endoom + (y * ENDOOM_W + indent) * 2, TXT_SCREEN_W * 2); + } + + // Wait for a keypress + + while (true) + { + TXT_UpdateScreen(); + + if (TXT_GetChar() > 0) + { + break; + } + + TXT_Sleep(0); + } + + // Shut down text mode screen + + TXT_Shutdown(); } diff --git a/prboom2/src/dsda/endoom.h b/prboom2/src/dsda/endoom.h index 7f37714fd..207c9a38d 100644 --- a/prboom2/src/dsda/endoom.h +++ b/prboom2/src/dsda/endoom.h @@ -17,3 +17,5 @@ void dsda_CacheEndoom(void); void dsda_DumpEndoom(void); +void dsda_TerminalEndoom(void); +void dsda_WindowEndoom(void); diff --git a/prboom2/src/dsda/global.c b/prboom2/src/dsda/global.c index 7437e6904..8e46b62f5 100644 --- a/prboom2/src/dsda/global.c +++ b/prboom2/src/dsda/global.c @@ -135,6 +135,7 @@ int g_menu_font_spacing; const char* g_skyflatname; +dboolean started_demo = false; dboolean hexen = false; dboolean heretic = false; dboolean raven = false; diff --git a/prboom2/src/i_video.h b/prboom2/src/i_video.h index a986ef072..2b6003a7e 100644 --- a/prboom2/src/i_video.h +++ b/prboom2/src/i_video.h @@ -63,6 +63,10 @@ void I_InitGraphics (void); void I_UpdateVideoMode(void); void I_ShutdownGraphics(void); +void *I_GetSDLWindow(void); +void *I_GetSDLRenderer(void); +void dsda_Shutdown(void); + /* Takes full 8 bit values. */ void I_SetPalette(int pal); /* CPhipps - pass down palette number */ diff --git a/prboom2/src/m_menu.c b/prboom2/src/m_menu.c index 7b6ba4158..079067f32 100644 --- a/prboom2/src/m_menu.c +++ b/prboom2/src/m_menu.c @@ -3286,6 +3286,8 @@ setup_menu_t gen_controller_settings[] = { FINAL_ENTRY }; +static const char* endoom_list[] = { "Off", "On", "Smart", NULL }; + setup_menu_t gen_misc_settings[] = { { "Death Use Action", S_CHOICE, m_conf, G2_X, dsda_config_death_use_action, 0, death_use_strings }, { "Boom Weapon Auto Switch", S_YESNO, m_conf, G2_X, dsda_config_switch_when_ammo_runs_out }, @@ -3293,6 +3295,8 @@ setup_menu_t gen_misc_settings[] = { { "Enable Cheat Code Entry", S_YESNO, m_conf, G2_X, dsda_config_cheat_codes }, { "Skip Quit Prompt", S_YESNO, m_conf, G2_X, dsda_config_skip_quit_prompt }, EMPTY_LINE, + { "Endoom Screen", S_CHOICE, m_conf, G2_X, dsda_config_show_endoom, 0, endoom_list }, + EMPTY_LINE, TITLE("Rewind", G2_X), { "Rewind Interval (s)", S_NUM, m_conf, G2_X, dsda_config_auto_key_frame_interval }, { "Rewind Depth", S_NUM, m_conf, G2_X, dsda_config_auto_key_frame_depth }, diff --git a/prboom2/src/m_misc.c b/prboom2/src/m_misc.c index 5616b462d..8d6ee0ac5 100644 --- a/prboom2/src/m_misc.c +++ b/prboom2/src/m_misc.c @@ -90,6 +90,8 @@ cfg_def_t cfg_defs[] = MIGRATED_SETTING(dsda_config_demo_smoothturnsfactor), MIGRATED_SETTING(dsda_config_screenshot_dir), MIGRATED_SETTING(dsda_config_startup_delay_ms), + MIGRATED_SETTING(dsda_config_show_endoom), + MIGRATED_SETTING(dsda_config_export_endoom), MIGRATED_SETTING(dsda_config_ansi_endoom), MIGRATED_SETTING(dsda_config_quit_sounds), MIGRATED_SETTING(dsda_config_announce_map), diff --git a/prboom2/src/textscreen/doomkeys.h b/prboom2/src/textscreen/doomkeys.h new file mode 100644 index 000000000..751057d63 --- /dev/null +++ b/prboom2/src/textscreen/doomkeys.h @@ -0,0 +1,236 @@ +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Key definitions +// + +#ifndef __DOOMKEYS__ +#define __DOOMKEYS__ + +// +// DOOM keyboard definition. +// This is the stuff configured by Setup.Exe. +// Most key data are simple ascii (uppercased). +// +#define NUMKEYS 256 +#define KEY_RIGHTARROW 0xae +#define KEY_LEFTARROW 0xac +#define KEY_UPARROW 0xad +#define KEY_DOWNARROW 0xaf +#define KEY_ESCAPE 27 +#define KEY_ENTER 13 +#define KEY_TAB 9 + +#define KEY_BACKSPACE 0x7f +#define KEY_PAUSE 0xff + +#define KEY_EQUALS 0x3d +#define KEY_MINUS 0x2d + +enum +{ + + // Keys without character representations + + KEY_F1 = 0x80, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + + KEY_RSHIFT, + KEY_RCTRL, + KEY_RALT, + KEY_LALT = KEY_RALT, + KEY_CAPSLOCK, + KEY_NUMLOCK, + KEY_SCRLCK, + KEY_PRTSCR, + KEY_HOME, + KEY_END, + KEY_PGUP, + KEY_PGDN, + KEY_INS, + KEY_DEL, + + // Keys on the numerics keypad + + KEYP_0, + KEYP_1, + KEYP_2, + KEYP_3, + KEYP_4, + KEYP_5, + KEYP_6, + KEYP_7, + KEYP_8, + KEYP_9, + KEYP_DIVIDE, + KEYP_PLUS, + KEYP_MINUS, + KEYP_MULTIPLY, + KEYP_PERIOD, + KEYP_EQUALS = KEY_EQUALS, + KEYP_ENTER = KEY_ENTER, +}; + +#define SCANCODE_TO_KEYS_ARRAY { \ + 0, 0, 0, 0, 'a', /* 0-9 */ \ + 'b', 'c', 'd', 'e', 'f', \ + 'g', 'h', 'i', 'j', 'k', /* 10-19 */ \ + 'l', 'm', 'n', 'o', 'p', \ + 'q', 'r', 's', 't', 'u', /* 20-29 */ \ + 'v', 'w', 'x', 'y', 'z', \ + '1', '2', '3', '4', '5', /* 30-39 */ \ + '6', '7', '8', '9', '0', \ + KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE, KEY_TAB, ' ', /* 40-49 */ \ + KEY_MINUS, KEY_EQUALS, '[', ']', '\\', \ + 0, ';', '\'', '`', ',', /* 50-59 */ \ + '.', '/', KEY_CAPSLOCK, KEY_F1, KEY_F2, \ + KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* 60-69 */ \ + KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, \ + KEY_PRTSCR, KEY_SCRLCK, KEY_PAUSE, KEY_INS, KEY_HOME, /* 70-79 */ \ + KEY_PGUP, KEY_DEL, KEY_END, KEY_PGDN, KEY_RIGHTARROW, \ + KEY_LEFTARROW, KEY_DOWNARROW, KEY_UPARROW, /* 80-89 */ \ + KEY_NUMLOCK, KEYP_DIVIDE, \ + KEYP_MULTIPLY, KEYP_MINUS, KEYP_PLUS, KEYP_ENTER, KEYP_1, \ + KEYP_2, KEYP_3, KEYP_4, KEYP_5, KEYP_6, /* 90-99 */ \ + KEYP_7, KEYP_8, KEYP_9, KEYP_0, KEYP_PERIOD, \ + 0, 0, 0, KEYP_EQUALS, /* 100-103 */ \ +} + +// Default names for keys, to use in English or as fallback. +#define KEY_NAMES_ARRAY { \ + { KEY_BACKSPACE, "BACKSP" }, { KEY_TAB, "TAB" }, \ + { KEY_INS, "INS" }, { KEY_DEL, "DEL" }, \ + { KEY_PGUP, "PGUP" }, { KEY_PGDN, "PGDN" }, \ + { KEY_ENTER, "ENTER" }, { KEY_ESCAPE, "ESC" }, \ + { KEY_F1, "F1" }, { KEY_F2, "F2" }, \ + { KEY_F3, "F3" }, { KEY_F4, "F4" }, \ + { KEY_F5, "F5" }, { KEY_F6, "F6" }, \ + { KEY_F7, "F7" }, { KEY_F8, "F8" }, \ + { KEY_F9, "F9" }, { KEY_F10, "F10" }, \ + { KEY_F11, "F11" }, { KEY_F12, "F12" }, \ + { KEY_HOME, "HOME" }, { KEY_END, "END" }, \ + { KEY_MINUS, "-" }, { KEY_EQUALS, "=" }, \ + { KEY_NUMLOCK, "NUMLCK" }, { KEY_SCRLCK, "SCRLCK" }, \ + { KEY_PAUSE, "PAUSE" }, { KEY_PRTSCR, "PRTSC" }, \ + { KEY_UPARROW, "UP" }, { KEY_DOWNARROW, "DOWN" }, \ + { KEY_LEFTARROW, "LEFT" }, { KEY_RIGHTARROW, "RIGHT" }, \ + { KEY_RALT, "ALT" }, { KEY_LALT, "ALT" }, \ + { KEY_RSHIFT, "SHIFT" }, { KEY_CAPSLOCK, "CAPS" }, \ + { KEY_RCTRL, "CTRL" }, { KEYP_5, "NUM5" }, \ + { ' ', "SPACE" }, \ + { 'a', "A" }, { 'b', "B" }, { 'c', "C" }, { 'd', "D" }, \ + { 'e', "E" }, { 'f', "F" }, { 'g', "G" }, { 'h', "H" }, \ + { 'i', "I" }, { 'j', "J" }, { 'k', "K" }, { 'l', "L" }, \ + { 'm', "M" }, { 'n', "N" }, { 'o', "O" }, { 'p', "P" }, \ + { 'q', "Q" }, { 'r', "R" }, { 's', "S" }, { 't', "T" }, \ + { 'u', "U" }, { 'v', "V" }, { 'w', "W" }, { 'x', "X" }, \ + { 'y', "Y" }, { 'z', "Z" }, { '0', "0" }, { '1', "1" }, \ + { '2', "2" }, { '3', "3" }, { '4', "4" }, { '5', "5" }, \ + { '6', "6" }, { '7', "7" }, { '8', "8" }, { '9', "9" }, \ + { '[', "[" }, { ']', "]" }, { ';', ";" }, { '`', "`" }, \ + { ',', "," }, { '.', "." }, { '/', "/" }, { '\\', "\\" }, \ + { '\'', "\'" }, \ +} + +enum +{ + GAMEPAD_A, + GAMEPAD_B, + GAMEPAD_X, + GAMEPAD_Y, + GAMEPAD_BACK, + GAMEPAD_GUIDE, + GAMEPAD_START, + GAMEPAD_LEFT_STICK, + GAMEPAD_RIGHT_STICK, + GAMEPAD_LEFT_SHOULDER, + GAMEPAD_RIGHT_SHOULDER, + GAMEPAD_DPAD_UP, + GAMEPAD_DPAD_DOWN, + GAMEPAD_DPAD_LEFT, + GAMEPAD_DPAD_RIGHT, + GAMEPAD_MISC1, + GAMEPAD_PADDLE1, + GAMEPAD_PADDLE2, + GAMEPAD_PADDLE3, + GAMEPAD_PADDLE4, + GAMEPAD_TOUCHPAD_PRESS, + GAMEPAD_TOUCHPAD_TOUCH, + GAMEPAD_LEFT_TRIGGER, + GAMEPAD_RIGHT_TRIGGER, + GAMEPAD_LEFT_STICK_UP, + GAMEPAD_LEFT_STICK_DOWN, + GAMEPAD_LEFT_STICK_LEFT, + GAMEPAD_LEFT_STICK_RIGHT, + GAMEPAD_RIGHT_STICK_UP, + GAMEPAD_RIGHT_STICK_DOWN, + GAMEPAD_RIGHT_STICK_LEFT, + GAMEPAD_RIGHT_STICK_RIGHT, + + NUM_GAMEPAD_BUTTONS +}; + +enum +{ + MOUSE_BUTTON_LEFT, + MOUSE_BUTTON_RIGHT, + MOUSE_BUTTON_MIDDLE, + MOUSE_BUTTON_X1, + MOUSE_BUTTON_X2, + MOUSE_BUTTON_WHEELUP, + MOUSE_BUTTON_WHEELDOWN, + MOUSE_BUTTON_WHEELLEFT, + MOUSE_BUTTON_WHEELRIGHT, + + NUM_MOUSE_BUTTONS +}; + +enum +{ + AXIS_LEFTX, + AXIS_LEFTY, + AXIS_RIGHTX, + AXIS_RIGHTY, + + NUM_AXES +}; + +enum +{ + AXIS_STRAFE, + AXIS_FORWARD, + AXIS_TURN, + AXIS_LOOK, +}; + +enum +{ + GYRO_TURN, + GYRO_LOOK, + + NUM_GYRO_AXES +}; + +#endif // __DOOMKEYS__ diff --git a/prboom2/src/textscreen/fonts/README b/prboom2/src/textscreen/fonts/README new file mode 100644 index 000000000..0a1f10b99 --- /dev/null +++ b/prboom2/src/textscreen/fonts/README @@ -0,0 +1,6 @@ + +This directory contains the font used by libtextscreen: + + * hauge-8x18-v1-6.png + Copyright (C) 2026 Zokum + License: CC BY-SA https://creativecommons.org/licenses/by-sa/4.0/ diff --git a/prboom2/src/textscreen/fonts/convert-font b/prboom2/src/textscreen/fonts/convert-font new file mode 100644 index 000000000..b3d828cc5 --- /dev/null +++ b/prboom2/src/textscreen/fonts/convert-font @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +# +# Copyright(C) 2016 Simon Howard +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# +# Converts images into libtextscreen fonts. +# + +import sys +import os +import re + +GRID_COLUMNS = 16 +GRID_ROWS = 16 + +try: + import Image +except ImportError: + try: + from PIL import Image + except ImportError: + print("WARNING: Could not update %s. " + "Please install the Python Imaging library or Pillow." + % sys.argv[3]) + sys.exit(0) + + +def generate_font_data(filename): + """Read font data from the given file. + + Args: + filename: Image file to read. + Returns: + Tuple containing: + (width, height) dimensions of each font character. + Array of byte data for font. + """ + im = Image.open(filename) + width, height = im.size + assert (width % GRID_COLUMNS) == 0 + assert (height % GRID_ROWS) == 0 + + char_w, char_h = width // GRID_COLUMNS, height // GRID_ROWS + font_data_len = (width * height) // 8 + font_data = [0] * font_data_len + + for y in range(height): + for x in range(width): + px = im.getpixel((x, y)) + if px > (127, 127, 127): + char_x, char_y = x // char_w, y // char_h + x1, y1 = x % char_w, y % char_h + bit_index = ( + (char_y * GRID_COLUMNS + char_x) * (char_w * char_h) + + (y1 * char_w) + x1) + font_data[bit_index // 8] |= 1 << (bit_index % 8) + + return (char_w, char_h), font_data + +def convert_image(font_prefix, filename, output_filename): + """Convert the given image to a text output file. + + Args: + font_prefix: Prefix string to attach to constants. + filename: Input image file to read. + output_filename: Header file to write. + """ + dimensions, data = generate_font_data(filename) + + with open(output_filename, "w") as outfile: + outfile.write("/* Font data generated from %s; do not edit.\n" + " Please see textscreen/fonts/README for copyright\n" + " information. */\n\n" % filename) + outfile.write("static const uint8_t %s_font_data[] =\n{\n" % + font_prefix) + for index, b in enumerate(data): + if (index % 8) == 0: + outfile.write(" ") + outfile.write("0x%02x," % b) + if ((index + 1) % 8) == 0: + outfile.write("\n") + else: + outfile.write(" ") + outfile.write("};\n") + + outfile.write("\n") + outfile.write("static const txt_font_t %s_font =\n{\n" % font_prefix) + outfile.write(" \"%s\", %s_font_data, %d, %d,\n" % ( + font_prefix, font_prefix, + dimensions[0], dimensions[1])) + outfile.write("};\n") + +convert_image(sys.argv[1], sys.argv[2], sys.argv[3]) + diff --git a/prboom2/src/textscreen/fonts/hauge-8x18-v1-6.png b/prboom2/src/textscreen/fonts/hauge-8x18-v1-6.png new file mode 100644 index 000000000..b450516f0 Binary files /dev/null and b/prboom2/src/textscreen/fonts/hauge-8x18-v1-6.png differ diff --git a/prboom2/src/textscreen/fonts/normal.h b/prboom2/src/textscreen/fonts/normal.h new file mode 100644 index 000000000..a0d913e8a --- /dev/null +++ b/prboom2/src/textscreen/fonts/normal.h @@ -0,0 +1,590 @@ +/* Font data generated from hauge-8x18-v1-6.png; do not edit. + Please see textscreen/fonts/README for copyright + information. */ + +#include "../txt_main.h" + +static const uint8_t normal_font_data[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x41, 0x41, 0x55, + 0x41, 0x41, 0x41, 0x5d, 0x49, 0x41, 0x41, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x7f, + 0x7f, 0x6b, 0x7f, 0x7f, 0x7f, 0x63, 0x77, 0x7f, + 0x7f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x7f, + 0x3e, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, + 0x7f, 0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, + 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x18, + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, + 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x78, 0x70, 0x58, 0x4c, 0x1e, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x3c, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x4c, 0x4c, 0x7c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0f, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x66, + 0x66, 0x7e, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, + 0x77, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x99, 0x5a, 0x3c, 0xe7, 0x3c, + 0x5a, 0x99, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, + 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x70, 0x78, + 0x7c, 0x7e, 0x7f, 0x7e, 0x7c, 0x78, 0x70, 0x60, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, + 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0xde, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x63, 0x06, 0x1c, 0x36, + 0x63, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x30, 0x63, + 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, + 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x30, 0x7f, 0x30, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x7f, 0x06, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x03, 0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x36, 0x7f, 0x36, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x1c, 0x1c, 0x3e, 0x3e, 0x7f, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e, 0x1c, 0x1c, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, + 0x3c, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, + 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x36, 0x36, + 0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x3e, 0x63, 0x43, 0x03, 0x03, 0x3e, + 0x60, 0x60, 0x60, 0x60, 0x63, 0x3e, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, + 0x70, 0x38, 0x18, 0x0c, 0x0e, 0x07, 0x63, 0x61, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, + 0x36, 0x36, 0x1c, 0x6e, 0x3b, 0x33, 0x33, 0x33, + 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, + 0x0c, 0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x42, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x42, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x7e, 0x18, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x1c, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, + 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x6b, + 0x6b, 0x63, 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x1c, 0x1e, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x73, + 0x60, 0x30, 0x30, 0x18, 0x0c, 0x0c, 0x06, 0x03, + 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x63, 0x60, 0x60, 0x60, 0x1c, 0x60, 0x60, + 0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x31, + 0x7f, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, + 0x03, 0x3f, 0x60, 0x60, 0x60, 0x60, 0x63, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x06, + 0x03, 0x03, 0x03, 0x3f, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x63, 0x60, 0x60, 0x30, 0x18, 0x0c, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x3e, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, + 0x63, 0x7e, 0x60, 0x60, 0x60, 0x60, 0x30, 0x1e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, + 0x03, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x30, 0x18, + 0x0c, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x63, 0x63, 0x60, 0x70, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7b, 0x7b, + 0x7b, 0x7b, 0x7b, 0x3b, 0x03, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, + 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x66, + 0x66, 0x66, 0x66, 0x3e, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x43, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0x3e, 0x76, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x36, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x66, 0x46, 0x06, + 0x16, 0x1e, 0x16, 0x06, 0x06, 0x46, 0x66, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x66, + 0x46, 0x06, 0x16, 0x1e, 0x16, 0x06, 0x06, 0x06, + 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b, 0x63, 0x63, + 0x63, 0x67, 0x7e, 0x5c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7f, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, + 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x67, 0x66, 0x66, 0x36, 0x36, 0x1e, 0x3e, 0x36, + 0x76, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x77, 0x7f, 0x7f, + 0x7f, 0x6b, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, + 0x6f, 0x7f, 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x66, 0x3e, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x7b, 0x3e, + 0x30, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x66, + 0x66, 0x66, 0x66, 0x3e, 0x36, 0x66, 0x66, 0x66, + 0x66, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x63, 0x63, 0x03, 0x06, 0x1c, 0x30, 0x60, + 0x60, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x36, + 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x6b, 0x6b, 0x6b, + 0x6b, 0x7f, 0x77, 0x36, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x63, 0x77, 0x36, 0x3e, 0x1c, + 0x1c, 0x3e, 0x36, 0x77, 0x63, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, + 0x31, 0x30, 0x18, 0x18, 0x0c, 0x0c, 0x06, 0x47, + 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x03, 0x03, 0x06, 0x06, 0x0c, + 0x1c, 0x18, 0x30, 0x30, 0x60, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3c, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x77, + 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x33, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, + 0x06, 0x06, 0x1e, 0x36, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, + 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x30, 0x30, 0x30, 0x3c, 0x36, + 0x33, 0x33, 0x33, 0x33, 0x73, 0x6e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, + 0x26, 0x06, 0x06, 0x0f, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x3e, 0x30, 0x33, 0x1e, 0x00, + 0x00, 0x00, 0x07, 0x06, 0x06, 0x06, 0x36, 0x6e, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, + 0x00, 0x00, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, + 0x07, 0x06, 0x06, 0x06, 0x66, 0x66, 0x36, 0x1e, + 0x3e, 0x36, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x37, 0x7f, 0x6b, 0x6b, 0x6b, 0x6b, 0x63, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5e, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3e, + 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0x6e, 0x66, 0x06, 0x06, 0x06, + 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x06, 0x0c, + 0x18, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x0c, 0x0c, 0x0c, 0x3f, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x6c, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x6b, + 0x6b, 0x6b, 0x6b, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x77, + 0x36, 0x1c, 0x1c, 0x36, 0x36, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, + 0x60, 0x30, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x30, 0x18, 0x0c, 0x06, + 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x0c, 0x0c, 0x0c, 0x0c, 0x07, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x18, 0x18, 0x18, + 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x18, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x67, 0x43, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x43, 0x67, 0x3e, 0x1c, 0x18, + 0x0e, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, + 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x03, + 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x1c, 0x36, 0x00, 0x00, 0x1e, 0x30, 0x30, 0x3e, + 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x1e, 0x30, + 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x00, 0x00, + 0x1e, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x33, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x1c, + 0x00, 0x00, 0x1e, 0x30, 0x30, 0x3e, 0x33, 0x33, + 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x63, 0x3e, 0x18, 0x0e, 0x00, + 0x00, 0x08, 0x1c, 0x36, 0x00, 0x00, 0x3e, 0x63, + 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, + 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x03, 0x63, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, + 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7f, 0x03, 0x03, + 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x00, 0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x1c, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x00, 0x00, + 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x08, + 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, + 0x1c, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x18, 0x00, 0x7f, 0x66, 0x46, 0x06, 0x16, + 0x1e, 0x16, 0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x37, 0x6c, 0x6c, 0x7e, 0x1b, 0x1b, 0x1b, 0x76, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x7c, + 0x36, 0x33, 0x33, 0x7f, 0x7f, 0x33, 0x33, 0x33, + 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x1c, 0x36, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x3e, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x00, 0x00, + 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1e, 0x33, + 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x0c, 0x18, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, + 0x1e, 0x00, 0x00, 0x63, 0x00, 0x3e, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x43, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x67, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, + 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x33, 0x33, + 0x33, 0x1f, 0x23, 0x33, 0x7b, 0x33, 0x33, 0x33, + 0x33, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0xd8, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, + 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x0c, 0x06, 0x00, 0x1e, 0x30, 0x30, + 0x3e, 0x33, 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x00, 0x00, + 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x06, + 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x0c, 0x06, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x3b, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, + 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x63, 0x67, 0x6f, + 0x7f, 0x7b, 0x73, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x26, + 0x26, 0x7c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x66, 0x66, 0x3c, 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x0c, + 0x0e, 0x07, 0x03, 0x63, 0x63, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x07, 0x06, 0x46, 0x66, 0x36, 0x18, 0x0c, 0x06, + 0x3b, 0x61, 0x30, 0x18, 0x0c, 0x7c, 0x00, 0x00, + 0x00, 0x06, 0x07, 0x06, 0x46, 0x66, 0x36, 0x18, + 0x0c, 0x66, 0x73, 0x59, 0xfc, 0x60, 0x60, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6c, 0x36, 0x1b, 0x1b, 0x36, 0x6c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c, 0x6c, + 0x36, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, + 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, + 0x44, 0x11, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, + 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, + 0xaa, 0x55, 0xaa, 0x55, 0x77, 0xdd, 0x77, 0xdd, + 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, + 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, + 0x1f, 0x18, 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6f, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x18, + 0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, + 0x6f, 0x60, 0x6f, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x60, 0x6f, 0x6f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x6f, 0x60, + 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x1f, 0x1f, 0x18, 0x1f, 0x1f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0xf8, 0xf8, 0x18, 0xf8, 0xf8, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0xec, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0xec, 0x0c, + 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0xfc, 0x0c, 0xec, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0xef, 0xef, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xef, 0xef, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0xec, 0x0c, + 0xec, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0xef, 0xef, 0x00, 0xef, 0xef, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x18, 0x18, + 0x18, 0x18, 0x18, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x00, 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0xf8, 0x18, + 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xf8, 0x18, 0xf8, 0xf8, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff, 0xff, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, 0x18, + 0xff, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf8, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x3b, 0x6e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x33, 0x33, 0x33, + 0x13, 0x1b, 0x33, 0x63, 0x63, 0x63, 0x63, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, + 0x63, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x06, 0x06, 0x0c, 0x18, + 0x18, 0x0c, 0x06, 0x06, 0x63, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x0e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x3e, 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xee, 0x7b, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x7e, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, + 0x63, 0x7f, 0x7f, 0x63, 0x63, 0x63, 0x36, 0x1c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x36, + 0x63, 0x63, 0x63, 0x63, 0x77, 0x36, 0x36, 0x36, + 0x36, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x06, 0x0c, 0x18, 0x30, 0x7c, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, + 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0x7e, 0xdb, 0xdb, 0xdb, 0xcf, 0x7e, 0x06, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, + 0x06, 0x06, 0x06, 0x3e, 0x06, 0x06, 0x06, 0x06, + 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, + 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x7e, 0x7e, 0x18, 0x18, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x0c, 0x18, 0x30, 0x18, 0x0c, 0x06, 0x00, + 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, + 0x30, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0xd8, 0xd8, 0xd8, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1b, 0x1b, + 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, + 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1c, 0x36, 0x36, 0x36, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37, + 0x36, 0x36, 0x3c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x36, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, + 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x30, 0x18, + 0x0c, 0x46, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const txt_font_t normal_font = +{ + "normal", normal_font_data, 8, 18, +}; diff --git a/prboom2/src/textscreen/txt_main.h b/prboom2/src/textscreen/txt_main.h new file mode 100644 index 000000000..4746761a8 --- /dev/null +++ b/prboom2/src/textscreen/txt_main.h @@ -0,0 +1,163 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Base interface that abstracts the text mode screen. +// + +#ifndef TXT_MAIN_H +#define TXT_MAIN_H + +// For the moment, txt_sdl.c is the only implementation of the base +// text mode screen API: + +#include "txt_sdl.h" + +// textscreen key values: +// Key values are difficult because we have to support multiple conflicting +// address spaces. +// First, Doom's key constants use 0-127 as ASCII and extra values from +// 128-255 to represent special keys. Second, mouse buttons are represented +// as buttons. Finally, we want to be able to support Unicode. +// +// So we define different ranges: +// 0-255: Doom key constants, including ASCII. +// 256-511: Mouse buttons and other reserved. +// >=512: Unicode values greater than 127 are offset up into this range. + +// Special keypress values that correspond to mouse button clicks + +#define TXT_MOUSE_BASE 256 +#define TXT_MOUSE_LEFT (TXT_MOUSE_BASE + 0) +#define TXT_MOUSE_RIGHT (TXT_MOUSE_BASE + 1) +#define TXT_MOUSE_MIDDLE (TXT_MOUSE_BASE + 2) +#define TXT_MOUSE_SCROLLUP (TXT_MOUSE_BASE + 3) +#define TXT_MOUSE_SCROLLDOWN (TXT_MOUSE_BASE + 4) +#define TXT_MAX_MOUSE_BUTTONS 16 + +#define TXT_KEY_TO_MOUSE_BUTTON(x) \ + ( (x) >= TXT_MOUSE_BASE \ + && (x) < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS ? \ + (x) - TXT_MOUSE_BASE : -1 ) + +// Unicode offset. Unicode values from 128 onwards are offset up into +// this range, so TXT_UNICODE_BASE = Unicode character #128, and so on. + +#define TXT_UNICODE_BASE 512 + +// Convert a key value to a Unicode character: + +#define TXT_KEY_TO_UNICODE(x) \ + ( (x) < 128 ? (x) : \ + (x) >= TXT_UNICODE_BASE ? ((x) - TXT_UNICODE_BASE + 128) : 0 ) + +// Convert a Unicode character to a key value: + +#define TXT_UNICODE_TO_KEY(u) \ + ( (u) < 128 ? (u) : ((u) - 128 + TXT_UNICODE_BASE) ) + +// Screen size + +#define TXT_SCREEN_W 80 +#define TXT_SCREEN_H 25 + +#define TXT_COLOR_BLINKING (1 << 3) + +typedef enum +{ + TXT_COLOR_BLACK, + TXT_COLOR_BLUE, + TXT_COLOR_GREEN, + TXT_COLOR_CYAN, + TXT_COLOR_RED, + TXT_COLOR_MAGENTA, + TXT_COLOR_BROWN, + TXT_COLOR_GREY, + TXT_COLOR_DARK_GREY, + TXT_COLOR_BRIGHT_BLUE, + TXT_COLOR_BRIGHT_GREEN, + TXT_COLOR_BRIGHT_CYAN, + TXT_COLOR_BRIGHT_RED, + TXT_COLOR_BRIGHT_MAGENTA, + TXT_COLOR_YELLOW, + TXT_COLOR_BRIGHT_WHITE, +} txt_color_t; + +// Modifier keys. + +typedef enum +{ + TXT_MOD_SHIFT, + TXT_MOD_CTRL, + TXT_MOD_ALT, + TXT_NUM_MODIFIERS +} txt_modifier_t; + +// Due to the way the SDL API works, we provide different ways of configuring +// how we read input events, each of which is useful in different scenarios. +typedef enum +{ + // "Localized" output that takes software keyboard layout into account, + // but key shifting has no effect. + TXT_INPUT_NORMAL, + + // "Raw" input; the keys correspond to physical keyboard layout and + // software keyboard layout has no effect. + TXT_INPUT_RAW, + + // Used for full text input. Events are fully shifted and localized. + // However, not all keyboard keys will generate input. + // Setting this mode may activate the on-screen keyboard, depending on + // device and OS. + TXT_INPUT_TEXT, +} txt_input_mode_t; + + +#if defined(__GNUC__) || defined(__clang__) + +#define PRINTF_ATTR(fmt, first) __attribute__((format(printf, fmt, first))) + +#else // __GNUC__ + +#define PRINTF_ATTR(fmt, first) + +#endif // __GNUC__ + +// Initialize the screen +// Returns 1 if successful, 0 if failed. +int TXT_Init(void); + +// Shut down text mode emulation +void TXT_Shutdown(void); + +// Get a pointer to the buffer containing the raw screen data. +unsigned char *TXT_GetScreenData(void); + +// Update an area of the screen +void TXT_UpdateScreenArea(int x, int y, int w, int h); + +// Update the whole screen +void TXT_UpdateScreen(void); + +// Read a character from the keyboard +int TXT_GetChar(void); + +// Retrieve the current position of the mouse +void TXT_GetMousePosition(int *x, int *y); + +// Sleep until an event is received or the screen needs updating +// Optional timeout in ms (timeout == 0 : sleep forever) +void TXT_Sleep(int timeout); + +#endif /* #ifndef TXT_MAIN_H */ + diff --git a/prboom2/src/textscreen/txt_sdl.c b/prboom2/src/textscreen/txt_sdl.c new file mode 100644 index 000000000..dd0b0c16a --- /dev/null +++ b/prboom2/src/textscreen/txt_sdl.c @@ -0,0 +1,871 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Text mode emulation in SDL +// + +#include "SDL.h" +#include "SDL_opengl.h" + +#include +#include +#include +#include + +#include "doomkeys.h" + +#include "txt_main.h" +#include "txt_sdl.h" +#include "txt_utf8.h" +#include "lprintf.h" + +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline __inline +#endif + +// Direct functions to GL functions +static int is_opengl = false; + +#define FONT_CHAR_W normal_font.w +#define FONT_CHAR_H normal_font.h +#define FONT_WIDTH 128 +#define FONT_HEIGHT 288 +#define SCREEN_COLS 80 +#define SCREEN_ROWS 25 + +static GLuint gl_texture = 0; +static int glwindow_w = 0; +static int glwindow_h = 0; + +// Fonts: +#include "fonts/normal.h" + +// Time between character blinks in ms +#define BLINK_PERIOD 250 + +static SDL_Window *TXT_SDLWindow = NULL; +static SDL_Surface *screenbuffer; +static unsigned char *screendata; +static SDL_Renderer *renderer; +static SDL_Texture *texture_upscaled; + +// Current input mode. +static txt_input_mode_t input_mode = TXT_INPUT_NORMAL; + +// Dimensions of the screen image in screen coordinates (not pixels); this +// is the value that was passed to SDL_CreateWindow(). +static int screen_image_w, screen_image_h; + +static TxtSDLEventCallbackFunc event_callback; +static void *event_callback_data; + +// Font we are using: +static const txt_font_t *font; + +// Mapping from SDL keyboard scancode to internal key code. +static const int scancode_translate_table[] = SCANCODE_TO_KEYS_ARRAY; + +static const SDL_Color ega_colors[] = +{ + {0x00, 0x00, 0x00, 0xff}, // 0: Black + {0x00, 0x00, 0xa8, 0xff}, // 1: Blue + {0x00, 0xa8, 0x00, 0xff}, // 2: Green + {0x00, 0xa8, 0xa8, 0xff}, // 3: Cyan + {0xa8, 0x00, 0x00, 0xff}, // 4: Red + {0xa8, 0x00, 0xa8, 0xff}, // 5: Magenta + {0xa8, 0x54, 0x00, 0xff}, // 6: Brown + {0xa8, 0xa8, 0xa8, 0xff}, // 7: Grey + {0x54, 0x54, 0x54, 0xff}, // 8: Dark grey + {0x54, 0x54, 0xfe, 0xff}, // 9: Bright blue + {0x54, 0xfe, 0x54, 0xff}, // 10: Bright green + {0x54, 0xfe, 0xfe, 0xff}, // 11: Bright cyan + {0xfe, 0x54, 0x54, 0xff}, // 12: Bright red + {0xfe, 0x54, 0xfe, 0xff}, // 13: Bright magenta + {0xfe, 0xfe, 0x54, 0xff}, // 14: Yellow + {0xfe, 0xfe, 0xfe, 0xff}, // 15: Bright white +}; + +// +// Initialize text mode screen +// +// Returns 1 if successful, 0 if an error occurred +// + +void TXT_PreInit(SDL_Window *preset_window, SDL_Renderer *preset_renderer, int opengl) +{ + if (preset_window != NULL) + { + TXT_SDLWindow = preset_window; + } + + // OpenGL doesn't use renderer + if (opengl) + { + is_opengl = true; + return; + } + + if (preset_renderer != NULL) + { + renderer = preset_renderer; + } +} + +int TXT_Init(void) +{ + int flags = 0; + SDL_RendererInfo info; + + if (is_opengl) + return GL_TXT_Init(); + + font = &normal_font; + + screen_image_w = TXT_SCREEN_W * font->w; + screen_image_h = TXT_SCREEN_H * font->h; + + // try to initialize high dpi rendering. + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + + if (TXT_SDLWindow == NULL) + { + int w, h; + + w = 3 * screen_image_w / 2; + h = 3 * screen_image_h / 2; + + TXT_SDLWindow = SDL_CreateWindow("", + SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + w, h, flags); + SDL_SetWindowMinimumSize(TXT_SDLWindow, screen_image_w, screen_image_h); + } + + if (TXT_SDLWindow == NULL) + return 0; + + if (renderer == NULL) + { + renderer = SDL_CreateRenderer(TXT_SDLWindow, -1, SDL_RENDERER_PRESENTVSYNC); + + if (renderer == NULL) + renderer = SDL_CreateRenderer(TXT_SDLWindow, -1, SDL_RENDERER_SOFTWARE); + } + + if (renderer == NULL) + return 0; + + // Instead, we draw everything into an intermediate 8-bit surface + // the same dimensions as the screen. SDL then takes care of all the + // 8->32 bit (or whatever depth) color conversions for us. + screenbuffer = SDL_CreateRGBSurface(0, + TXT_SCREEN_W * font->w, + TXT_SCREEN_H * font->h, + 8, 0, 0, 0, 0); + + // Set width and height of the logical viewport for automatic scaling. + SDL_RenderSetLogicalSize(renderer, screenbuffer->w, screenbuffer->h); + + SDL_LockSurface(screenbuffer); + SDL_SetPaletteColors(screenbuffer->format->palette, ega_colors, 0, 16); + SDL_UnlockSurface(screenbuffer); + + screendata = malloc(TXT_SCREEN_W * TXT_SCREEN_H * 2); + memset(screendata, 0, TXT_SCREEN_W * TXT_SCREEN_H * 2); + + SDL_GetRendererInfo(renderer, &info); + + if (!(info.flags & SDL_RENDERER_SOFTWARE)) + { + // Set the scaling quality for rendering the upscaled texture to "linear", + // which looks much softer and smoother than "nearest" but does a better + // job at downscaling from the upscaled texture to screen. + + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + + texture_upscaled = SDL_CreateTexture(renderer, + SDL_GetWindowPixelFormat(TXT_SDLWindow), + SDL_TEXTUREACCESS_TARGET, + 2 * screenbuffer->w, 2 * screenbuffer->h); + } + + return 1; +} + +void TXT_Shutdown(void) +{ + if (is_opengl) + if (gl_texture != 0) + { + glDeleteTextures(1, &gl_texture); + gl_texture = 0; + } + + free(screendata); + screendata = NULL; + SDL_FreeSurface(screenbuffer); + screenbuffer = NULL; +} + +unsigned char *TXT_GetScreenData(void) +{ + return screendata; +} + +static inline void UpdateCharacter(int x, int y) +{ + unsigned char character; + const uint8_t *p; + unsigned char *s, *s1; + unsigned int bit; + int bg, fg; + unsigned int x1, y1; + + p = &screendata[(y * TXT_SCREEN_W + x) * 2]; + character = p[0]; + + fg = p[1] & 0xf; + bg = (p[1] >> 4) & 0xf; + + if (bg & 0x8) + { + // blinking + + bg &= ~0x8; + + if (((SDL_GetTicks() / BLINK_PERIOD) % 2) == 0) + { + fg = bg; + } + } + + // How many bytes per line? + p = &font->data[(character * font->w * font->h) / 8]; + bit = 0; + + s = ((unsigned char *) screenbuffer->pixels) + + (y * font->h * screenbuffer->pitch) + + (x * font->w); + + for (y1=0; y1h; ++y1) + { + s1 = s; + + for (x1=0; x1w; ++x1) + { + if (*p & (1 << bit)) + { + *s1++ = fg; + } + else + { + *s1++ = bg; + } + + ++bit; + if (bit == 8) + { + ++p; + bit = 0; + } + } + + s += screenbuffer->pitch; + } +} + +static int LimitToRange(int val, int min, int max) +{ + if (val < min) + { + return min; + } + else if (val > max) + { + return max; + } + else + { + return val; + } +} + +static void GetDestRect(SDL_Rect *rect) +{ + // Set x and y to 0 due to SDL auto-centering. + rect->x = 0; + rect->y = 0; + rect->w = screenbuffer->w; + rect->h = screenbuffer->h; +} + +void TXT_UpdateScreenArea(int x, int y, int w, int h) +{ + SDL_Texture *screentx; + SDL_Rect rect; + int x1, y1; + int x_end; + int y_end; + + SDL_LockSurface(screenbuffer); + + x_end = LimitToRange(x + w, 0, TXT_SCREEN_W); + y_end = LimitToRange(y + h, 0, TXT_SCREEN_H); + x = LimitToRange(x, 0, TXT_SCREEN_W); + y = LimitToRange(y, 0, TXT_SCREEN_H); + + for (y1=y; y1w; + screen_image_h = TXT_SCREEN_H * font->h; + + screenbuffer = SDL_CreateRGBSurface(0, screen_image_w, screen_image_h, 8, 0, 0, 0, 0); + if (!screenbuffer) + { + lprintf(LO_ERROR, "Failed to create software screenbuffer!\n"); + return 0; + } + + SDL_LockSurface(screenbuffer); + SDL_SetPaletteColors(screenbuffer->format->palette, ega_colors, 0, 16); + SDL_UnlockSurface(screenbuffer); + + screendata = malloc(TXT_SCREEN_W * TXT_SCREEN_H * 2); + memset(screendata, 0, TXT_SCREEN_W * TXT_SCREEN_H * 2); + + if (!TXT_SDLWindow) + return 0; + + SDL_GL_GetDrawableSize(TXT_SDLWindow, &glwindow_w, &glwindow_h); + + GL_TXT_SetupOrtho(glwindow_w, glwindow_h); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, FONT_WIDTH, FONT_HEIGHT, 0, GL_RED, GL_UNSIGNED_BYTE, font->data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + return 1; +} + +void GL_TXT_UpdateScreen(void) +{ + static GLubyte *texture_data; + int tex_w, tex_h, tex_w2, tex_h2; + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + SDL_LockSurface(screenbuffer); + + texture_data = NULL; + tex_w = TXT_SCREEN_W * FONT_CHAR_W; + tex_h = TXT_SCREEN_H * FONT_CHAR_H; + + // We will scale software image by 2x + // then scale back down for sharpness + tex_w2 = tex_w * 2; + tex_h2 = tex_h * 2; + + if (!texture_data) + texture_data = malloc(tex_w2 * tex_h2 * 4); + + for (int y = 0; y < TXT_SCREEN_H; y++) { + for (int x = 0; x < TXT_SCREEN_W; x++) { + unsigned char *p = &screendata[(y * TXT_SCREEN_W + x) * 2]; + unsigned char chr = p[0]; + unsigned char attr = p[1]; + int fg, bg; + SDL_Color fg_col, bg_col; + + fg = attr & 0x0F; // 16-color fg + bg = (attr >> 4) & 0x0F; // 16-color bg fixed here + + if (bg & 0x8) + { + // blinking + + bg &= ~0x8; + + if (((SDL_GetTicks() / BLINK_PERIOD) % 2) == 0) + { + fg = bg; + } + } + + fg_col = ega_colors[fg]; + bg_col = ega_colors[bg]; + + // Draw character pixels into screen_rgba + for (int cy = 0; cy < (int)FONT_CHAR_H; cy++) + { + unsigned char row = font->data[chr * FONT_CHAR_H + cy]; + for (int cx = 0; cx < (int)FONT_CHAR_W; cx++) + { + int bit = (row >> cx) & 1; + GLubyte r = bit ? fg_col.r : bg_col.r; + GLubyte g = bit ? fg_col.g : bg_col.g; + GLubyte b = bit ? fg_col.b : bg_col.b; + + int dst_x = x * FONT_CHAR_W * 2 + cx * 2; + int dst_y = y * FONT_CHAR_H * 2 + cy * 2; + for (int dy = 0; dy < 2; dy++) + for (int dx = 0; dx < 2; dx++) + { + int idx = ((dst_y + dy) * tex_w2 + (dst_x + dx)) * 4; + texture_data[idx + 0] = r; + texture_data[idx + 1] = g; + texture_data[idx + 2] = b; + texture_data[idx + 3] = 255; + } + } + } + } + } + + SDL_UnlockSurface(screenbuffer); + + // Draw 2x texture + if (gl_texture == 0) + { + glGenTextures(1, &gl_texture); + glBindTexture(GL_TEXTURE_2D, gl_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w2, tex_h2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data); + } + else + { + glBindTexture(GL_TEXTURE_2D, gl_texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_w2, tex_h2, GL_RGBA, GL_UNSIGNED_BYTE, texture_data); + } + + // Draw 2x texture (image) normal size in window + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, gl_texture); + + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(0, 0); + glTexCoord2f(1, 0); glVertex2f((GLfloat)tex_w, 0); + glTexCoord2f(1, 1); glVertex2f((GLfloat)tex_w, (GLfloat)tex_h); + glTexCoord2f(0, 1); glVertex2f(0, (GLfloat)tex_h); + glEnd(); + + glDisable(GL_TEXTURE_2D); + + SDL_GL_SwapWindow(TXT_SDLWindow); +} + +void TXT_GetMousePosition(int *x, int *y) +{ + int window_w, window_h; + + SDL_GetMouseState(x, y); + + // Translate mouse position from 'pixel' position into character position. + // We are working here in screen coordinates and not pixels, since this is + // what SDL_GetWindowSize() returns. + SDL_GetWindowSize(TXT_SDLWindow, &window_w, &window_h); + *x = ((*x) * TXT_SCREEN_W) / window_w; + *y = ((*y) * TXT_SCREEN_H) / window_h; + + if (*x < 0) + { + *x = 0; + } + else if (*x >= TXT_SCREEN_W) + { + *x = TXT_SCREEN_W - 1; + } + if (*y < 0) + { + *y = 0; + } + else if (*y >= TXT_SCREEN_H) + { + *y = TXT_SCREEN_H - 1; + } +} + +// +// Translates the SDL key +// + +// XXX: duplicate from doomtype.h +#define arrlen(array) (sizeof(array) / sizeof(*array)) + +static int TranslateScancode(SDL_Scancode scancode) +{ + switch (scancode) + { + case SDL_SCANCODE_LCTRL: + case SDL_SCANCODE_RCTRL: + return KEY_RCTRL; + + case SDL_SCANCODE_LSHIFT: + case SDL_SCANCODE_RSHIFT: + return KEY_RSHIFT; + + case SDL_SCANCODE_LALT: + return KEY_LALT; + + case SDL_SCANCODE_RALT: + return KEY_RALT; + + default: + if (scancode < arrlen(scancode_translate_table)) + { + return scancode_translate_table[scancode]; + } + else + { + return 0; + } + } +} + +static int TranslateKeysym(const SDL_Keysym *sym) +{ + int translated; + + // We cheat here and make use of TranslateScancode. The range of keys + // associated with printable characters is pretty contiguous, so if it's + // inside that range we want the localized version of the key instead. + translated = TranslateScancode(sym->scancode); + + if (translated >= 0x20 && translated < 0x7f) + { + return sym->sym; + } + else + { + return translated; + } +} + +// Convert an SDL button index to textscreen button index. +// +// Note special cases because 2 == mid in SDL, 3 == mid in textscreen/setup + +static int SDLButtonToTXTButton(int button) +{ + switch (button) + { + case SDL_BUTTON_LEFT: + return TXT_MOUSE_LEFT; + case SDL_BUTTON_RIGHT: + return TXT_MOUSE_RIGHT; + case SDL_BUTTON_MIDDLE: + return TXT_MOUSE_MIDDLE; + default: + return TXT_MOUSE_BASE + button - 1; + } +} + +// Convert an SDL wheel motion to a textscreen button index. + +static int SDLWheelToTXTButton(const SDL_MouseWheelEvent *wheel) +{ + if (wheel->y <= 0) + { + return TXT_MOUSE_SCROLLDOWN; + } + else + { + return TXT_MOUSE_SCROLLUP; + } +} + +static int MouseHasMoved(void) +{ + static int last_x = 0, last_y = 0; + int x, y; + + TXT_GetMousePosition(&x, &y); + + if (x != last_x || y != last_y) + { + last_x = x; last_y = y; + return 1; + } + else + { + return 0; + } +} + +signed int TXT_GetChar(void) +{ + SDL_Event ev; + + while (SDL_PollEvent(&ev)) + { + // If there is an event callback, allow it to intercept this + // event. + + if (event_callback != NULL) + { + if (event_callback(&ev, event_callback_data)) + { + continue; + } + } + + // Process the event. + + switch (ev.type) + { + case SDL_MOUSEBUTTONDOWN: + if (ev.button.button < TXT_MAX_MOUSE_BUTTONS) + { + return SDLButtonToTXTButton(ev.button.button); + } + break; + + case SDL_MOUSEWHEEL: + return SDLWheelToTXTButton(&ev.wheel); + + case SDL_KEYDOWN: + switch (input_mode) + { + case TXT_INPUT_RAW: + return TranslateScancode(ev.key.keysym.scancode); + case TXT_INPUT_NORMAL: + return TranslateKeysym(&ev.key.keysym); + case TXT_INPUT_TEXT: + // We ignore key inputs in this mode, except for a + // few special cases needed during text input: + if (ev.key.keysym.sym == SDLK_ESCAPE + || ev.key.keysym.sym == SDLK_BACKSPACE + || ev.key.keysym.sym == SDLK_RETURN) + { + return TranslateKeysym(&ev.key.keysym); + } + break; + } + break; + + case SDL_TEXTINPUT: + if (input_mode == TXT_INPUT_TEXT) + { + // TODO: Support input of more than just the first char? + const char *p = ev.text.text; + int result = TXT_DecodeUTF8(&p); + // 0-127 is ASCII, but we map non-ASCII Unicode chars into + // a higher range to avoid conflicts with special keys. + return TXT_UNICODE_TO_KEY(result); + } + break; + + case SDL_QUIT: + // Quit = escape + return 27; + + case SDL_MOUSEMOTION: + if (MouseHasMoved()) + { + return 0; + } + + // Force content resize on OpenGL + case SDL_WINDOWEVENT: + if (is_opengl && ev.window.event == SDL_WINDOWEVENT_RESIZED) + { + GL_TXT_SetupOrtho(ev.window.data1, ev.window.data2); + } + break; + + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: + SDL_PushEvent(&ev); + break; + + default: + break; + } + } + + return -1; +} + +// Searches the desktop screen buffer to determine whether there are any +// blinking characters. + +int TXT_ScreenHasBlinkingChars(void) +{ + int x, y; + unsigned char *p; + + // Check all characters in screen buffer + + for (y=0; y time_to_next_blink) + { + // Add one so it is always positive + + timeout = time_to_next_blink + 1; + } + } + + if (timeout == 0) + { + // We can just wait forever until an event occurs + + SDL_WaitEvent(NULL); + } + else + { + // Sit in a busy loop until the timeout expires or we have to + // redraw the blinking screen + + start_time = SDL_GetTicks(); + + while (SDL_GetTicks() < start_time + timeout) + { + if (SDL_PollEvent(NULL) != 0) + { + // Received an event, so stop waiting + + break; + } + + // Don't hog the CPU + + SDL_Delay(1); + } + } +} diff --git a/prboom2/src/textscreen/txt_sdl.h b/prboom2/src/textscreen/txt_sdl.h new file mode 100644 index 000000000..9d21da8e7 --- /dev/null +++ b/prboom2/src/textscreen/txt_sdl.h @@ -0,0 +1,48 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// +// Text mode emulation in SDL +// + +#ifndef TXT_SDL_H +#define TXT_SDL_H + +// The textscreen API itself doesn't need SDL; however, SDL needs its +// headers included where main() is defined. + +#include "SDL.h" + +// Event callback function type: a function of this type can be used +// to intercept events in the textscreen event processing loop. +// Returning 1 will cause the event to be eaten; the textscreen code +// will not see it. + +typedef int (*TxtSDLEventCallbackFunc)(SDL_Event *event, void *user_data); + +void TXT_PreInit(SDL_Window *preset_window, SDL_Renderer *preset_renderer, int opengl); + +typedef struct +{ + const char *name; + const uint8_t *data; + unsigned int w; + unsigned int h; +} txt_font_t; + +// GL stuff +extern int GL_TXT_Init(void); +extern void GL_TXT_UpdateScreen(void); + +#endif /* #ifndef TXT_SDL_H */ + diff --git a/prboom2/src/textscreen/txt_utf8.c b/prboom2/src/textscreen/txt_utf8.c new file mode 100644 index 000000000..a435c5b26 --- /dev/null +++ b/prboom2/src/textscreen/txt_utf8.c @@ -0,0 +1,71 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// + +#include +#include +#include + +#include "txt_utf8.h" + +// Decode UTF-8 character, incrementing *ptr over the decoded bytes. + +unsigned int TXT_DecodeUTF8(const char **ptr) +{ + const char *p = *ptr; + unsigned int c; + + // UTF-8 decode. + + if ((*p & 0x80) == 0) // 1 character (ASCII): + { + c = *p; + *ptr += 1; + } + else if ((p[0] & 0xe0) == 0xc0 // 2 character: + && (p[1] & 0xc0) == 0x80) + { + c = ((p[0] & 0x1f) << 6) + | (p[1] & 0x3f); + *ptr += 2; + } + else if ((p[0] & 0xf0) == 0xe0 // 3 character: + && (p[1] & 0xc0) == 0x80 + && (p[2] & 0xc0) == 0x80) + { + c = ((p[0] & 0x0f) << 12) + | ((p[1] & 0x3f) << 6) + | (p[2] & 0x3f); + *ptr += 3; + } + else if ((p[0] & 0xf8) == 0xf0 // 4 character: + && (p[1] & 0xc0) == 0x80 + && (p[2] & 0xc0) == 0x80 + && (p[3] & 0xc0) == 0x80) + { + c = ((p[0] & 0x07) << 18) + | ((p[1] & 0x3f) << 12) + | ((p[2] & 0x3f) << 6) + | (p[3] & 0x3f); + *ptr += 4; + } + else + { + // Decode failure. + // Don't bother with 5/6 byte sequences. + + c = 0; + } + + return c; +} diff --git a/prboom2/src/textscreen/txt_utf8.h b/prboom2/src/textscreen/txt_utf8.h new file mode 100644 index 000000000..5ac1b9ab4 --- /dev/null +++ b/prboom2/src/textscreen/txt_utf8.h @@ -0,0 +1,22 @@ +// +// Copyright(C) 2005-2014 Simon Howard +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// + +#ifndef TXT_UTF8_H +#define TXT_UTF8_H + +#include + +unsigned int TXT_DecodeUTF8(const char **ptr); + +#endif /* #ifndef TXT_UTF8_H */