diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index bd4ebe8da..23eaa330f 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -705,6 +705,7 @@ set (PCH_SOURCES common/2d/v_draw.cpp common/2d/v_drawtext.cpp common/2d/renderstyle.cpp + common/2d/screentext.cpp common/fonts/font.cpp common/fonts/hexfont.cpp diff --git a/source/blood/CMakeLists.txt b/source/blood/CMakeLists.txt index 263bcf1ea..0723a07aa 100644 --- a/source/blood/CMakeLists.txt +++ b/source/blood/CMakeLists.txt @@ -63,7 +63,7 @@ set( PCH_SOURCES src/replace.cpp src/resource.cpp src/screen.cpp - src/screentext.cpp + src/text.cpp src/sectorfx.cpp src/seq.cpp src/sfx.cpp diff --git a/source/blood/src/blood.h b/source/blood/src/blood.h index 0df1bebef..25d71601a 100644 --- a/source/blood/src/blood.h +++ b/source/blood/src/blood.h @@ -99,6 +99,7 @@ struct GameInterface : ::GameInterface void DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool bg) override; void QuitToTitle() override; FString GetCoordString() override; + int GetStringTile(int font, const char* t, int f) override; GameStats getStats() override; }; diff --git a/source/blood/src/common_game.h b/source/blood/src/common_game.h index 3c5e82ec4..4ea644975 100644 --- a/source/blood/src/common_game.h +++ b/source/blood/src/common_game.h @@ -478,10 +478,6 @@ enum searchpathtypes_t { SEARCHPATH_REMOVE = 1<<0, }; -#define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \ - if (alpha < 0) { blend = -alpha; alpha = 0; orientation |= RS_TRANS1; } \ -} while (0) - extern int loaddefinitions_game(const char *fn, int32_t preload); extern void G_ExtInit(void); diff --git a/source/blood/src/screentext.h b/source/blood/src/screentext.h deleted file mode 100644 index 693b64976..000000000 --- a/source/blood/src/screentext.h +++ /dev/null @@ -1,96 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2016 EDuke32 developers and contributors - -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -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. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- - -#pragma once - -BEGIN_BLD_NS - -#define USERQUOTE_LEFTOFFSET 5 -#define USERQUOTE_RIGHTOFFSET 14 - -extern int32_t minitext_lowercase; -extern int32_t minitext_yofs; - -enum ScreenTextFlags_t { - TEXT_XRIGHT = 0x00000001, - TEXT_XCENTER = 0x00000002, - TEXT_YBOTTOM = 0x00000004, - TEXT_YCENTER = 0x00000008, - TEXT_INTERNALSPACE = 0x00000010, - TEXT_TILESPACE = 0x00000020, - TEXT_INTERNALLINE = 0x00000040, - TEXT_TILELINE = 0x00000080, - TEXT_XOFFSETZERO = 0x00000100, - TEXT_XJUSTIFY = 0x00000200, - TEXT_YOFFSETZERO = 0x00000400, - TEXT_YJUSTIFY = 0x00000800, - TEXT_LINEWRAP = 0x00001000, - TEXT_UPPERCASE = 0x00002000, - TEXT_INVERTCASE = 0x00004000, - TEXT_IGNOREESCAPE = 0x00008000, - TEXT_LITERALESCAPE = 0x00010000, - TEXT_BACKWARDS = 0x00020000, - TEXT_GAMETEXTNUMHACK = 0x00040000, - TEXT_DIGITALNUMBER = 0x00080000, - // TEXT_BIGALPHANUM = 0x00100000, - // TEXT_GRAYFONT = 0x00200000, -}; - -//extern int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb); -//extern void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f); -//extern void captionmenutext(int32_t x, int32_t y, char const *t); -//extern vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f); -//extern void gametext_simple(int32_t x, int32_t y, const char *t); -//#define mpgametext_x (5<<16) -//extern vec2_t mpgametext(int32_t x, int32_t y, char const * t, int32_t s, int32_t o, int32_t a, int32_t f); -//extern vec2_t mpgametextsize(char const * t, int32_t f); -//extern int32_t textsc(int32_t sc); -// -//#define minitextshade(x, y, t, s, p, sb) minitext_(x,y,t,s,p,sb) -//#define minitext(x, y, t, p, sb) minitext_(x,y,t,0,p,sb) -//#define menutext(x, y, t) menutext_((x), (y), 0, (t), 10|16, 0) -//#define menutext_centeralign(x, y, t) menutext_((x), (y), 0, (t), 10|16, TEXT_XCENTER|TEXT_YCENTER) -//#define menutext_center(y, t) menutext_(160<<16, (y)<<16, 0, (t), 10|16, TEXT_XCENTER) -//#define gametext(x, y, t) gametext_simple((x)<<16, (y)<<16, (t)) -//#define gametext_widenumber(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 1024, 0, TEXT_GAMETEXTNUMHACK) -//#define gametext_number(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_GAMETEXTNUMHACK) -//#define gametext_pal(x, y, t, p) gametext_((x)<<16, (y)<<16, (t), 0, (p), 0, 0, 0) -//#define gametext_center(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER) -//#define gametext_center_number(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER|TEXT_GAMETEXTNUMHACK) -//#define gametext_center_shade(y, t, s) gametext_(160<<16, (y)<<16, (t), (s), MF_Bluefont.pal, 0, 0, TEXT_XCENTER) -//#define gametext_center_shade_pal(y, t, s, p) gametext_(160<<16, (y)<<16, (t), (s), (p), 0, 0, TEXT_XCENTER) -// -//extern void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, -// int32_t s, int32_t p, int32_t o, -// int32_t x1, int32_t y1, int32_t x2, int32_t y2, -// int32_t z, int32_t a); -// -extern int32_t G_GetStringLineLength(const char *text, const char *end, int32_t iter); -extern int32_t G_GetStringNumLines(const char *text, const char *end, int32_t iter); -extern char* G_GetSubString(const char *text, const char *end, int32_t iter, int32_t length); -extern int32_t G_GetStringTile(int32_t font, char *t, int32_t f); -extern vec2_t G_ScreenTextSize(int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, const char *str, int32_t o, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); -extern void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, int32_t magnitude); -extern vec2_t G_ScreenText(int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, int32_t charangle, const char *str, int32_t shade, int32_t pal, int32_t o, int32_t alpha, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); -extern vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy, int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, int32_t charangle, const char *str, int32_t shade, int32_t pal, int32_t o, int32_t alpha, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); - -END_BLD_NS diff --git a/source/blood/src/text.cpp b/source/blood/src/text.cpp new file mode 100644 index 000000000..cf3e90bf7 --- /dev/null +++ b/source/blood/src/text.cpp @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! +#include "compat.h" +#include "blood.h" +#include "common_game.h" +#include "screentext.h" + +BEGIN_BLD_NS + +// assign the character's tilenum +int GameInterface::GetStringTile(int font, const char *t, int f) +{ + if (f & TEXT_DIGITALNUMBER) + return *t - '0' + font; // copied from digitalnumber + else + return *t - ' ' + font; // uses ASCII order +} + + + + +END_BLD_NS + diff --git a/source/blood/src/text.h b/source/blood/src/text.h new file mode 100644 index 000000000..3a0b877a5 --- /dev/null +++ b/source/blood/src/text.h @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- + +#pragma once + +#include "screentext.h" + +BEGIN_BLD_NS + +extern int32_t minitext_lowercase; +extern int32_t minitext_yofs; + + +END_BLD_NS diff --git a/source/build/include/baselayer.h b/source/build/include/baselayer.h index 1ec810cad..5c354ff6e 100644 --- a/source/build/include/baselayer.h +++ b/source/build/include/baselayer.h @@ -138,6 +138,7 @@ struct GameInterface virtual void QuitToTitle() {} virtual void SetAmbience(bool on) {} virtual FString GetCoordString() { return "'stat coord' not implemented"; } + virtual int GetStringTile(int font, const char* t, int f) { return -1; } }; diff --git a/source/build/include/build.h b/source/build/include/build.h index 5f95fb651..8b31afc6e 100644 --- a/source/build/include/build.h +++ b/source/build/include/build.h @@ -358,6 +358,10 @@ typedef struct { #define SPREXT_TSPRACCESS 16 #define SPREXT_TEMPINVISIBLE 32 +#define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \ + if ((alpha) < 0) { (blend) = -(alpha); (alpha) = 0; (orientation) |= RS_TRANS1; } \ +} while (0) + // using the clipdist field enum { diff --git a/source/blood/src/screentext.cpp b/source/common/2d/screentext.cpp similarity index 93% rename from source/blood/src/screentext.cpp rename to source/common/2d/screentext.cpp index c0cc18735..dfc165f02 100644 --- a/source/blood/src/screentext.cpp +++ b/source/common/2d/screentext.cpp @@ -1,8 +1,9 @@ //------------------------------------------------------------------------- /* Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2019 Christoph Oelckers -This file is part of EDuke32. +This file is part of Raze. EDuke32 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 @@ -18,15 +19,16 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -//------------------------------------------------------------------------- +//------------------------------------------------------------------------- -#include "ns.h" // Must come before everything else! -#include "compat.h" -#include "blood.h" -#include "common_game.h" #include "screentext.h" +#include "build.h" -BEGIN_BLD_NS +static inline void SetIfGreater(int32_t *variable, int32_t potentialValue) +{ + if (potentialValue > *variable) + *variable = potentialValue; +} // get the string length until the next '\n' int32_t G_GetStringLineLength(const char *text, const char *end, const int32_t iter) @@ -77,17 +79,11 @@ char* G_GetSubString(const char *text, const char *end, const int32_t iter, cons return line; } -// assign the character's tilenum -int32_t G_GetStringTile(int32_t font, char *t, int32_t f) -{ - if (f & TEXT_DIGITALNUMBER) - return *t - '0' + font; // copied from digitalnumber - else - return *t - ' ' + font; // uses ASCII order -} - #define NUMHACKACTIVE ((f & TEXT_GAMETEXTNUMHACK) && t >= '0' && t <= '9') +#define USERQUOTE_RIGHTOFFSET 14 + + // qstrdim vec2_t G_ScreenTextSize(const int32_t font, int32_t x, int32_t y, const int32_t z, const int32_t blockangle, @@ -175,7 +171,7 @@ vec2_t G_ScreenTextSize(const int32_t font, } // translate the character to a tilenum - tile = G_GetStringTile(font, &t, f); + tile = gi->GetStringTile(font, &t, f); // reset this here because we haven't printed anything yet this loop extent.x = 0; @@ -193,10 +189,10 @@ vec2_t G_ScreenTextSize(const int32_t font, if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE)) { - char space = ' '; // this is subject to change as an implementation detail + char space = '.'; // this is subject to change as an implementation detail if (f & TEXT_TILESPACE) space = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &space, f); + tile = gi->GetStringTile(font, &space, f); extent.x += (tilesiz[tile].x * z); } @@ -210,7 +206,7 @@ vec2_t G_ScreenTextSize(const int32_t font, char line = 'A'; // this is subject to change as an implementation detail if (f & TEXT_TILELINE) line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); + tile = gi->GetStringTile(font, &line, f); tempyextent += tilesiz[tile].y * z; } @@ -243,7 +239,7 @@ vec2_t G_ScreenTextSize(const int32_t font, char line = 'A'; // this is subject to change as an implementation detail if (f & TEXT_TILELINE) line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); + tile = gi->GetStringTile(font, &line, f); tempyextent += tilesiz[tile].y * z; } @@ -268,11 +264,10 @@ vec2_t G_ScreenTextSize(const int32_t font, // width extent.x = tilesiz[tile].x * z; - // obnoxious hardcoded functionality from gametext if (NUMHACKACTIVE) { char numeral = '0'; // this is subject to change as an implementation detail - extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z; + extent.x = (tilesiz[gi->GetStringTile(font, &numeral, f)].x-1) * z; } // height @@ -289,7 +284,7 @@ vec2_t G_ScreenTextSize(const int32_t font, offset.x += extent.x; // account for text spacing - if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff + if (!NUMHACKACTIVE && t != '\n' && !(f & TEXT_XJUSTIFY)) // to prevent overflow offset.x += xbetween; @@ -333,7 +328,7 @@ vec2_t G_ScreenTextSize(const int32_t font, char line = 'A'; // this is subject to change as an implementation detail if (f & TEXT_TILELINE) line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); + tile = gi->GetStringTile(font, &line, f); tempyextent += tilesiz[tile].y * z; } @@ -416,6 +411,7 @@ vec2_t G_ScreenText(const int32_t font, vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line const vec2_t Xdirection = { sintable[(blockangle+512)&2047], sintable[blockangle&2047], }; const vec2_t Ydirection = { sintable[(blockangle+1024)&2047], sintable[(blockangle+512)&2047], }; + const int32_t z2 = (f & TEXT_RRMENUTEXTHACK) ? 26214 : z; int32_t blendidx=0, tile; char t; @@ -563,7 +559,7 @@ vec2_t G_ScreenText(const int32_t font, } // translate the character to a tilenum - tile = G_GetStringTile(font, &t, f); + tile = gi->GetStringTile(font, &t, f); switch (t) { @@ -583,7 +579,7 @@ vec2_t G_ScreenText(const int32_t font, G_AddCoordsFromRotation(&location, &Xdirection, pos.x); G_AddCoordsFromRotation(&location, &Ydirection, pos.y); - rotatesprite_(location.x, location.y, z, angle, tile, shade, pal, orientation, alpha, blendidx, x1, y1, x2, y2); + rotatesprite_(location.x, location.y, z2, angle, tile, shade, pal, orientation, alpha, blendidx, x1, y1, x2, y2); break; } @@ -602,10 +598,10 @@ vec2_t G_ScreenText(const int32_t font, if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE)) { - char space = ' '; // this is subject to change as an implementation detail + char space = '.'; // this is subject to change as an implementation detail if (f & TEXT_TILESPACE) space = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &space, f); + tile = gi->GetStringTile(font, &space, f); extent.x += (tilesiz[tile].x * z); } @@ -619,7 +615,7 @@ vec2_t G_ScreenText(const int32_t font, char line = 'A'; // this is subject to change as an implementation detail if (f & TEXT_TILELINE) line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); + tile = gi->GetStringTile(font, &line, f); tempyextent += tilesiz[tile].y * z; } @@ -647,7 +643,7 @@ vec2_t G_ScreenText(const int32_t font, char line = 'A'; // this is subject to change as an implementation detail if (f & TEXT_TILELINE) line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); + tile = gi->GetStringTile(font, &line, f); tempyextent += tilesiz[tile].y * z; } @@ -695,11 +691,10 @@ vec2_t G_ScreenText(const int32_t font, // width extent.x = tilesiz[tile].x * z; - // obnoxious hardcoded functionality from gametext if (NUMHACKACTIVE) { char numeral = '0'; // this is subject to change as an implementation detail - extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z; + extent.x = (tilesiz[gi->GetStringTile(font, &numeral, f)].x-1) * z; } // height @@ -717,7 +712,7 @@ vec2_t G_ScreenText(const int32_t font, xoffset += extent.x; // account for text spacing - if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff + if (!NUMHACKACTIVE && t != '\n') xoffset += xbetween; @@ -757,7 +752,7 @@ vec2_t G_ScreenText(const int32_t font, char line = 'A'; // this is subject to change as an implementation detail if (f & TEXT_TILELINE) line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); + tile = gi->GetStringTile(font, &line, f); tempyextent += tilesiz[tile].y * z; } @@ -830,7 +825,3 @@ vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy, return size; } - - -END_BLD_NS - diff --git a/source/rr/src/screentext.h b/source/common/2d/screentext.h similarity index 56% rename from source/rr/src/screentext.h rename to source/common/2d/screentext.h index f9eb0abee..4707f2311 100644 --- a/source/rr/src/screentext.h +++ b/source/common/2d/screentext.h @@ -22,15 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once -#include "menus.h" - -BEGIN_RR_NS - -#define MAXUSERQUOTES 6 - -extern int32_t user_quote_time[MAXUSERQUOTES]; -extern int32_t minitext_lowercase; -extern int32_t minitext_yofs; +#include "compat.h" enum ScreenTextFlags_t { TEXT_XRIGHT = 0x00000001, @@ -58,42 +50,10 @@ enum ScreenTextFlags_t { TEXT_RRMENUTEXTHACK = 0x00400000, }; -extern int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb); -extern void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f); -extern void captionmenutext(int32_t x, int32_t y, char const *t); -extern vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f); -extern void gametext_simple(int32_t x, int32_t y, const char *t); -#define mpgametext_x (5<<16) -extern vec2_t mpgametext(int32_t x, int32_t y, char const * t, int32_t s, int32_t o, int32_t a, int32_t f); -extern vec2_t mpgametextsize(char const * t, int32_t f); -extern int32_t textsc(int32_t sc); - -#define minitextshade(x, y, t, s, p, sb) minitext_(x,y,t,s,p,sb) -#define minitext(x, y, t, p, sb) minitext_(x,y,t,0,p,sb) -#define menutext(x, y, t) menutext_((x)<<16, (y)<<16, 0, (t), 10|16, 0) -#define menutext_centeralign(x, y, t) menutext_((x), (y), 0, (t), 10|16, TEXT_XCENTER|TEXT_YCENTER) -#define menutext_center(y, t) menutext_(160<<16, (y)<<16, 0, (t), 10|16, TEXT_XCENTER) -#define gametext(x, y, t) gametext_simple((x)<<16, (y)<<16, (t)) -#define gametext_widenumber(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 1024, 0, TEXT_GAMETEXTNUMHACK) -#define gametext_number(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_GAMETEXTNUMHACK) -#define gametext_pal(x, y, t, p) gametext_((x)<<16, (y)<<16, (t), 0, (p), 0, 0, 0) -#define gametext_center(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER) -#define gametext_center_number(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER|TEXT_GAMETEXTNUMHACK) -#define gametext_center_shade(y, t, s) gametext_(160<<16, (y)<<16, (t), (s), MF_Bluefont.pal, 0, 0, TEXT_XCENTER) -#define gametext_center_shade_pal(y, t, s, p) gametext_(160<<16, (y)<<16, (t), (s), (p), 0, 0, TEXT_XCENTER) - -extern void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, - int32_t s, int32_t p, int32_t o, - int32_t x1, int32_t y1, int32_t x2, int32_t y2, - int32_t z, int32_t a); - extern int32_t G_GetStringLineLength(const char *text, const char *end, int32_t iter); extern int32_t G_GetStringNumLines(const char *text, const char *end, int32_t iter); extern char* G_GetSubString(const char *text, const char *end, int32_t iter, int32_t length); -extern int32_t G_GetStringTile(int32_t font, char *t, int32_t f); extern vec2_t G_ScreenTextSize(int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, const char *str, int32_t o, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); extern void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, int32_t magnitude); extern vec2_t G_ScreenText(int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, int32_t charangle, const char *str, int32_t shade, int32_t pal, int32_t o, int32_t alpha, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); extern vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy, int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, int32_t charangle, const char *str, int32_t shade, int32_t pal, int32_t o, int32_t alpha, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); - -END_RR_NS diff --git a/source/duke3d/CMakeLists.txt b/source/duke3d/CMakeLists.txt index 585e8ae4c..cb852ddc7 100644 --- a/source/duke3d/CMakeLists.txt +++ b/source/duke3d/CMakeLists.txt @@ -24,7 +24,7 @@ set( PCH_SOURCES src/savegame.cpp src/sbar.cpp src/screens.cpp - src/screentext.cpp + src/text.cpp src/sector.cpp src/sounds.cpp src/soundsdyn.cpp diff --git a/source/duke3d/src/duke3d.h b/source/duke3d/src/duke3d.h index d19145968..454a6765f 100644 --- a/source/duke3d/src/duke3d.h +++ b/source/duke3d/src/duke3d.h @@ -122,10 +122,10 @@ EDUKE32_STATIC_ASSERT(7 <= MAXTILES-MAXUSERTILES); #include "player.h" #include "quotes.h" #include "rts.h" -#include "screentext.h" #include "sector.h" #include "sounds.h" #include "soundsdyn.h" +#include "text.h" BEGIN_DUKE_NS @@ -171,6 +171,7 @@ struct GameInterface : ::GameInterface void DrawPlayerSprite(const DVector2& origin, bool onteam) override; void QuitToTitle() override; FString GetCoordString() override; + int GetStringTile(int font, const char* t, int f) override; }; diff --git a/source/duke3d/src/game.h b/source/duke3d/src/game.h index 2ac45b188..70b68cc7b 100644 --- a/source/duke3d/src/game.h +++ b/source/duke3d/src/game.h @@ -43,16 +43,7 @@ BEGIN_DUKE_NS // Compile game-side legacy Room over Room code? #define LEGACY_ROR 1 -#define USERQUOTE_LEFTOFFSET 5 -#define USERQUOTE_RIGHTOFFSET 14 - -#if defined(GEKKO) || defined(__OPENDINGUX__) -# define VIEWSCREENFACTOR 0 -#elif defined(__ANDROID__) -# define VIEWSCREENFACTOR 1 -#else # define VIEWSCREENFACTOR 2 -#endif enum GametypeFlags_t { GAMETYPE_COOP = 0x00000001, @@ -288,10 +279,6 @@ void G_UpdatePlayerFromMenu(void); void P_DoQuote(int32_t q,DukePlayer_t *p); void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, ESetPalFlags flags); -#define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \ - if (alpha < 0) { blend = -alpha; alpha = 0; orientation |= RS_TRANS1; } \ -} while (0) - // Cstat protection mask for (currently) spawned MASKWALL* sprites. // TODO: look at more cases of cstat=(cstat&PROTECTED)|ADDED in A_Spawn()? // 2048+(32+16)+8+4 @@ -447,8 +434,6 @@ static inline int G_GetMusicIdx(const char *str) } -EXTERN_INLINE_HEADER void SetIfGreater(int32_t *variable, int32_t potentialValue); - #endif @@ -474,14 +459,6 @@ static inline int G_GetViewscreenSizeShift(T const * spr) #if defined game_c_ || !defined DISABLE_INLINING -// the point of this is to prevent re-running a function or calculation passed to potentialValue -// without making a new variable under each individual circumstance -EXTERN_INLINE void SetIfGreater(int32_t *variable, int32_t potentialValue) -{ - if (potentialValue > *variable) - *variable = potentialValue; -} - #endif #endif diff --git a/source/duke3d/src/screentext.cpp b/source/duke3d/src/screentext.cpp deleted file mode 100644 index 792d70d89..000000000 --- a/source/duke3d/src/screentext.cpp +++ /dev/null @@ -1,1196 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2016 EDuke32 developers and contributors - -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -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. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- - -#include "ns.h" // Must come before everything else! - -#include "duke3d.h" -#include "compat.h" -#include "sbar.h" -#include "menus.h" -#include "gstrings.h" -#include "quotemgr.h" - -#include "c_dispatch.h" -BEGIN_DUKE_NS - -// get the string length until the next '\n' -int32_t G_GetStringLineLength(const char *text, const char *end, const int32_t iter) -{ - int32_t length = 0; - - while (text != end && *text != '\n') - { - ++length; - - text += iter; - } - - return length; -} - -int32_t G_GetStringNumLines(const char *text, const char *end, const int32_t iter) -{ - int32_t count = 1; - - while (text != end) - { - if (*text == '\n') - ++count; - text += iter; - } - - return count; -} -// Note: Neither of these care about TEXT_LINEWRAP. This is intended. - -// This function requires you to Xfree() the returned char*. -char* G_GetSubString(const char *text, const char *end, const int32_t iter, const int32_t length) -{ - char *line = (char*) Xmalloc((length+1) * sizeof(char)); - int32_t counter = 0; - - while (counter < length && text != end) - { - line[counter] = *text; - - text += iter; - ++counter; - } - - line[counter] = '\0'; - - return line; -} - -// assign the character's tilenum -int32_t G_GetStringTile(int32_t font, char *t, int32_t f) -{ - if (f & TEXT_DIGITALNUMBER) - return *t - '0' + font; // copied from digitalnumber - else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT)) - { - int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0; - - if (*t >= '0' && *t <= '9') - return *t - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10); - else if (*t >= 'a' && *t <= 'z') - return *t - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26); - else if (*t >= 'A' && *t <= 'Z') - return *t - 'A' + font; - else switch (*t) - { - case '_': - case '-': - return font - (11 + offset); - break; - case '.': - return font + (BIGPERIOD - (BIGALPHANUM + offset)); - break; - case ',': - return font + (BIGCOMMA - (BIGALPHANUM + offset)); - break; - case '!': - return font + (BIGX_ - (BIGALPHANUM + offset)); - break; - case '?': - return font + (BIGQ - (BIGALPHANUM + offset)); - break; - case ';': - return font + (BIGSEMI - (BIGALPHANUM + offset)); - break; - case ':': - return font + (BIGCOLIN - (BIGALPHANUM + offset)); - break; - case '\\': - case '/': - return font + (68 - offset); // 3008-2940 - break; - case '%': - return font + (69 - offset); // 3009-2940 - break; - case '`': - case '\"': // could be better hacked in - case '\'': - return font + (BIGAPPOS - (BIGALPHANUM + offset)); - break; - default: // unknown character - *t = ' '; // whitespace-ize - fallthrough__; - case '\t': - case ' ': - case '\n': - case '\x7F': - return font; - break; - } - } - else - return *t - '!' + font; // uses ASCII order -} - -#define NUMHACKACTIVE ((f & TEXT_GAMETEXTNUMHACK) && t >= '0' && t <= '9') - -// qstrdim -vec2_t G_ScreenTextSize(const int32_t font, - int32_t x, int32_t y, const int32_t z, const int32_t blockangle, - const char *str, const int32_t o, - int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, - const int32_t f, - int32_t x1, int32_t y1, int32_t x2, int32_t y2) -{ - vec2_t size = { 0, 0, }; // eventually the return value - vec2_t pos = { 0, 0, }; // holds the coordinate position as we draw each character tile of the string - vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line - vec2_t offset = { 0, 0, }; // temporary; holds the last movement made in both directions - - int32_t tile; - char t; - - // set the start and end points depending on direction - int32_t iter = (f & TEXT_BACKWARDS) ? -1 : 1; // iteration direction - - const char *end; - const char *text; - - if (str == NULL) - return size; - - end = (f & TEXT_BACKWARDS) ? str-1 : Bstrchr(str, '\0'); - text = (f & TEXT_BACKWARDS) ? Bstrchr(str, '\0')-1 : str; - - // optimization: justification in both directions - if ((f & TEXT_XJUSTIFY) && (f & TEXT_YJUSTIFY)) - { - size.x = xbetween; - size.y = ybetween; - return size; - } - - // for best results, we promote 320x200 coordinates to full precision before any math - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - xspace <<= 16; - yline <<= 16; - xbetween <<= 16; - ybetween <<= 16; - } - // coordinate values should be shifted left by 16 - - // handle zooming where applicable - xspace = mulscale16(xspace, z); - yline = mulscale16(yline, z); - xbetween = mulscale16(xbetween, z); - ybetween = mulscale16(ybetween, z); - // size/width/height/spacing/offset values should be multiplied or scaled by $z, zoom (since 100% is 65536, the same as 1<<16) - - // loop through the string - while (text != end && (t = *text)) - { - // handle escape sequences - if (t == '^' && Bisdigit(*(text+iter)) && !(f & TEXT_LITERALESCAPE)) - { - text += iter + iter; - if (Bisdigit(*text)) - text += iter; - continue; - } - - // handle case bits - if (f & TEXT_UPPERCASE) - { - if (f & TEXT_INVERTCASE) // optimization...? - { // v^ important that these two ifs remain separate due to the else below - if (Bisupper(t)) - t = Btolower(t); - } - else if (Bislower(t)) - t = Btoupper(t); - } - else if (f & TEXT_INVERTCASE) - { - if (Bisupper(t)) - t = Btolower(t); - else if (Bislower(t)) - t = Btoupper(t); - } - - // translate the character to a tilenum - tile = G_GetStringTile(font, &t, f); - - // reset this here because we haven't printed anything yet this loop - extent.x = 0; - - // reset this here because the act of printing something on this line means that we include the margin above in the total size - offset.y = 0; - - // handle each character itself in the context of screen drawing - switch (t) - { - case '\t': - case ' ': - // width - extent.x = xspace; - - if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE)) - { - char space = '.'; // this is subject to change as an implementation detail - if (f & TEXT_TILESPACE) - space = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &space, f); - - extent.x += (tilesiz[tile].x * z); - } - - // prepare the height // near-CODEDUP the other two near-CODEDUPs for this section - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - if (t == '\t') - extent.x <<= 2; // *= 4 - - break; - - case '\n': // near-CODEDUP "if (wrap)" - extent.x = 0; - - // save the position - if (!(f & TEXT_XOFFSETZERO)) // we want the entire offset to count as the character width - pos.x -= offset.x; - SetIfGreater(&size.x, pos.x); - - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - offset.y = (f & TEXT_YJUSTIFY) ? 0 : ybetween; // ternary to prevent overflow - pos.y += offset.y; - - break; - - default: - // width - extent.x = tilesiz[tile].x * z; - - // obnoxious hardcoded functionality from gametext - if (NUMHACKACTIVE) - { - char numeral = '0'; // this is subject to change as an implementation detail - extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z; - } - - // height - SetIfGreater(&extent.y, (tilesiz[tile].y * z)); - - break; - } - - // incrementing the coordinate counters - offset.x = 0; - - // advance the x coordinate - if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE) - offset.x += extent.x; - - // account for text spacing - if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff - && t != '\n' - && !(f & TEXT_XJUSTIFY)) // to prevent overflow - offset.x += xbetween; - - // line wrapping - if ((f & TEXT_LINEWRAP) && !(f & TEXT_XRIGHT) && !(f & TEXT_XCENTER) && blockangle % 512 == 0) - { - int32_t wrap = 0; - const int32_t ang = blockangle % 2048; - - // this is the only place in qstrdim where angle actually affects direction, but only in the wrapping measurement - switch (ang) - { - case 0: - wrap = (x + (pos.x + offset.x) > ((o & 2) ? (320<<16) : ((x2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 512: - wrap = (y + (pos.x + offset.x) > ((o & 2) ? (200<<16) : ((y2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1024: - wrap = (x - (pos.x + offset.x) < ((o & 2) ? 0 : ((x1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1536: - wrap = (y - (pos.x + offset.x) < ((o & 2) ? 0 : ((y1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - } - if (wrap) // near-CODEDUP "case '\n':" - { - // save the position - SetIfGreater(&size.x, pos.x); - - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - offset.y = (f & TEXT_YJUSTIFY) ? 0 : ybetween; // ternary to prevent overflow - pos.y += offset.y; - } - else - pos.x += offset.x; - } - else - pos.x += offset.x; - - // save some trouble with calculation in case the line breaks - if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE) - offset.x -= extent.x; - - // iterate to the next character in the string - text += iter; - } - - // calculate final size - if (!(f & TEXT_XOFFSETZERO)) - pos.x -= offset.x; - - if (!(f & TEXT_YOFFSETZERO)) - { - pos.y -= offset.y; - pos.y += extent.y; - } - else - pos.y += ybetween; - - SetIfGreater(&size.x, pos.x); - SetIfGreater(&size.y, pos.y); - - // justification where only one of the two directions is set, so we have to iterate - if (f & TEXT_XJUSTIFY) - size.x = xbetween; - if (f & TEXT_YJUSTIFY) - size.y = ybetween; - - // return values in the same manner we receive them - if (!(o & ROTATESPRITE_FULL16)) - { - size.x >>= 16; - size.y >>= 16; - } - - return size; -} - -void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, const int32_t magnitude) -{ - coords->x += mulscale14(magnitude, unitDirection->x); - coords->y += mulscale14(magnitude, unitDirection->y); -} - -// screentext -vec2_t G_ScreenText(const int32_t font, - int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle, - const char *str, const int32_t shade, int32_t pal, int32_t o, int32_t alpha, - int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f, - const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2) -{ - vec2_t size = { 0, 0, }; // eventually the return value - vec2_t origin = { 0, 0, }; // where to start, depending on the alignment - vec2_t pos = { 0, 0, }; // holds the coordinate position as we draw each character tile of the string - vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line - const vec2_t Xdirection = { sintable[(blockangle+512)&2047], sintable[blockangle&2047], }; - const vec2_t Ydirection = { sintable[(blockangle+1024)&2047], sintable[(blockangle+512)&2047], }; - - int32_t blendidx=0, tile; - char t; - - // set the start and end points depending on direction - int32_t iter = (f & TEXT_BACKWARDS) ? -1 : 1; // iteration direction - - const char *end; - const char *text; - - if (str == NULL) - return size; - - NEG_ALPHA_TO_BLEND(alpha, blendidx, o); - - end = (f & TEXT_BACKWARDS) ? str-1 : Bstrchr(str, '\0'); - text = (f & TEXT_BACKWARDS) ? Bstrchr(str, '\0')-1 : str; - - // for best results, we promote 320x200 coordinates to full precision before any math - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - xspace <<= 16; - yline <<= 16; - xbetween <<= 16; - ybetween <<= 16; - } - // coordinate values should be shifted left by 16 - - // eliminate conflicts, necessary here to get the correct size value - // especially given justification's special handling in G_ScreenTextSize() - if ((f & TEXT_XRIGHT) || (f & TEXT_XCENTER) || (f & TEXT_XJUSTIFY) || (f & TEXT_YJUSTIFY) || blockangle % 512 != 0) - o &= ~TEXT_LINEWRAP; - - // size is the return value, and we need it for alignment - size = G_ScreenTextSize(font, x, y, z, blockangle, str, o | ROTATESPRITE_FULL16, xspace, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY), x1, y1, x2, y2); - - int32_t const xspace_orig = xspace; - int32_t const yline_orig = yline; - int32_t const xbetween_orig = xbetween; - int32_t const ybetween_orig = ybetween; - // handle zooming where applicable - xspace = mulscale16(xspace, z); - yline = mulscale16(yline, z); - xbetween = mulscale16(xbetween, z); - ybetween = mulscale16(ybetween, z); - // size/width/height/spacing/offset values should be multiplied or scaled by $z, zoom (since 100% is 65536, the same as 1<<16) - - // alignment - // near-CODEDUP "case '\n':" - { - int32_t lines = G_GetStringNumLines(text, end, iter); - - if ((f & TEXT_XJUSTIFY) || (f & TEXT_XRIGHT) || (f & TEXT_XCENTER)) - { - const int32_t length = G_GetStringLineLength(text, end, iter); - - int32_t linewidth = size.x; - - if (lines != 1) - { - char *line = G_GetSubString(text, end, iter, length); - - linewidth = G_ScreenTextSize(font, x, y, z, blockangle, line, o | ROTATESPRITE_FULL16, xspace_orig, yline_orig, (f & TEXT_XJUSTIFY) ? 0 : xbetween_orig, (f & TEXT_YJUSTIFY) ? 0 : ybetween_orig, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; - - Xfree(line); - } - - if (f & TEXT_XJUSTIFY) - { - size.x = xbetween; - - xbetween = (length == 1) ? 0 : tabledivide32_noinline((xbetween - linewidth), (length - 1)); - - linewidth = size.x; - } - - if (f & TEXT_XRIGHT) - origin.x = -(linewidth/z*z); - else if (f & TEXT_XCENTER) - origin.x = -(linewidth/2/z*z); - } - - if (f & TEXT_YJUSTIFY) - { - const int32_t tempswap = ybetween; - ybetween = (lines == 1) ? 0 : tabledivide32_noinline(ybetween - size.y, lines - 1); - size.y = tempswap; - } - - if (f & TEXT_YBOTTOM) - origin.y = -(size.y/z*z); - else if (f & TEXT_YCENTER) - origin.y = -(size.y/2/z*z); - } - - // loop through the string - while (text != end && (t = *text)) - { - int32_t orientation = o; - int32_t angle = blockangle + charangle; - - // handle escape sequences - if (t == '^' && Bisdigit(*(text+iter)) && !(f & TEXT_LITERALESCAPE)) - { - char smallbuf[4]; - - text += iter; - smallbuf[0] = *text; - - text += iter; - if (Bisdigit(*text)) - { - smallbuf[1] = *text; - smallbuf[2] = '\0'; - text += iter; - } - else - smallbuf[1] = '\0'; - - if (!(f & TEXT_IGNOREESCAPE)) - pal = Batoi(smallbuf); - - continue; - } - - // handle case bits - if (f & TEXT_UPPERCASE) - { - if (f & TEXT_INVERTCASE) // optimization...? - { // v^ important that these two ifs remain separate due to the else below - if (Bisupper(t)) - t = Btolower(t); - } - else if (Bislower(t)) - t = Btoupper(t); - } - else if (f & TEXT_INVERTCASE) - { - if (Bisupper(t)) - t = Btolower(t); - else if (Bislower(t)) - t = Btoupper(t); - } - - // translate the character to a tilenum - tile = G_GetStringTile(font, &t, f); - - switch (t) - { - case '\t': - case ' ': - case '\n': - case '\x7F': - break; - - default: - { - vec2_t location = { x, y, }; - - G_AddCoordsFromRotation(&location, &Xdirection, origin.x); - G_AddCoordsFromRotation(&location, &Ydirection, origin.y); - - G_AddCoordsFromRotation(&location, &Xdirection, pos.x); - G_AddCoordsFromRotation(&location, &Ydirection, pos.y); - - rotatesprite_(location.x, location.y, z, angle, tile, shade, pal, orientation, alpha, blendidx, x1, y1, x2, y2); - - break; - } - } - - // reset this here because we haven't printed anything yet this loop - extent.x = 0; - - // handle each character itself in the context of screen drawing - switch (t) - { - case '\t': - case ' ': - // width - extent.x = xspace; - - if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE)) - { - char space = '.'; // this is subject to change as an implementation detail - if (f & TEXT_TILESPACE) - space = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &space, f); - - extent.x += (tilesiz[tile].x * z); - } - - // prepare the height // near-CODEDUP the other two near-CODEDUPs for this section - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - if (t == '\t') - extent.x <<= 2; // *= 4 - - break; - - case '\n': // near-CODEDUP "if (wrap)" - extent.x = 0; - - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - pos.y += ybetween; - - // near-CODEDUP "alignments" - if ((f & TEXT_XJUSTIFY) || (f & TEXT_XRIGHT) || (f & TEXT_XCENTER)) - { - const int32_t length = G_GetStringLineLength(text+1, end, iter); - - char *line = G_GetSubString(text+1, end, iter, length); - - int32_t linewidth = G_ScreenTextSize(font, x, y, z, blockangle, line, o | ROTATESPRITE_FULL16, xspace_orig, yline_orig, (f & TEXT_XJUSTIFY) ? 0 : xbetween_orig, (f & TEXT_YJUSTIFY) ? 0 : ybetween_orig, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; - - Xfree(line); - - if (f & TEXT_XJUSTIFY) - { - xbetween = (length == 1) ? 0 : tabledivide32_noinline(xbetween - linewidth, length - 1); - - linewidth = size.x; - } - - if (f & TEXT_XRIGHT) - origin.x = -linewidth; - else if (f & TEXT_XCENTER) - origin.x = -(linewidth / 2); - } - - break; - - default: - // width - extent.x = tilesiz[tile].x * z; - - // obnoxious hardcoded functionality from gametext - if (NUMHACKACTIVE) - { - char numeral = '0'; // this is subject to change as an implementation detail - extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z; - } - - // height - SetIfGreater(&extent.y, (tilesiz[tile].y * z)); - - break; - } - - // incrementing the coordinate counters - { - int32_t xoffset = 0; - - // advance the x coordinate - if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE) - xoffset += extent.x; - - // account for text spacing - if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff - && t != '\n') - xoffset += xbetween; - - // line wrapping - if (f & TEXT_LINEWRAP) - { - int32_t wrap = 0; - const int32_t ang = blockangle % 2048; - - // it's safe to make some assumptions and not go through G_AddCoordsFromRotation() since we limit to four directions - switch (ang) - { - case 0: - wrap = (x + (pos.x + xoffset) > ((orientation & 2) ? (320<<16) : ((x2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 512: - wrap = (y + (pos.x + xoffset) > ((orientation & 2) ? (200<<16) : ((y2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1024: - wrap = (x - (pos.x + xoffset) < ((orientation & 2) ? 0 : ((x1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1536: - wrap = (y - (pos.x + xoffset) < ((orientation & 2) ? 0 : ((y1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - } - if (wrap) // near-CODEDUP "case '\n':" - { - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - pos.y += ybetween; - } - else - pos.x += xoffset; - } - else - pos.x += xoffset; - } - - // iterate to the next character in the string - text += iter; - } - - // return values in the same manner we receive them - if (!(o & ROTATESPRITE_FULL16)) - { - size.x >>= 16; - size.y >>= 16; - } - - return size; -} - -vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy, - const int32_t font, - int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle, - const char *str, const int32_t shade, int32_t pal, int32_t o, const int32_t alpha, - int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f, - const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2) -{ - vec2_t size = { 0, 0, }; // eventually the return value - - if (!(o & ROTATESPRITE_FULL16)) - { - sx <<= 16; - sy <<= 16; - x <<= 16; - y <<= 16; - xspace <<= 16; - yline <<= 16; - xbetween <<= 16; - ybetween <<= 16; - } - - G_ScreenText(font, x + mulscale16(sx, z), y + mulscale16(sy, z), z, blockangle, charangle, str, 127, 4, o|ROTATESPRITE_FULL16, alpha, xspace, yline, xbetween, ybetween, f, x1, y1, x2, y2); - - size = G_ScreenText(font, x, y, z, blockangle, charangle, str, shade, pal, o|ROTATESPRITE_FULL16, alpha, xspace, yline, xbetween, ybetween, f, x1, y1, x2, y2); - - // return values in the same manner we receive them - if (!(o & ROTATESPRITE_FULL16)) - { - size.x >>= 16; - size.y >>= 16; - } - - return size; -} - -void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, - int32_t s, int32_t p, int32_t o, - int32_t x1, int32_t y1, int32_t x2, int32_t y2, - int32_t z, int32_t a) -{ - int32_t f = TEXT_GAMETEXTNUMHACK; - - if (t == NULL) - return; - - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - } - - if (x == (160<<16)) - f |= TEXT_XCENTER; - - G_ScreenText(tile, x, y, z, 0, 0, t, s, p, 2|o|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, x1, y1, x2, y2); -} - -vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f) -{ - return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, s, p, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); -} -void gametext_simple(int32_t x, int32_t y, const char *t) -{ - G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1); -} -vec2_t mpgametext(int32_t x, int32_t y, const char *t, int32_t s, int32_t o, int32_t a, int32_t f) -{ - return G_ScreenText(MF_Bluefont.tilenum, x, y, textsc(MF_Bluefont.zoom), 0, 0, t, s, MF_Bluefont.pal, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); -} -vec2_t mpgametextsize(const char *t, int32_t f) -{ - return G_ScreenTextSize(MF_Bluefont.tilenum, 0, 0, textsc(MF_Bluefont.zoom), 0, t, 2|8|16|ROTATESPRITE_FULL16, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); -} - -// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords, -// (sb&ROTATESPRITE_MAX) only. -int32_t minitext_yofs = 0; -int32_t minitext_lowercase = 0; -int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb) -{ - vec2_t dim; - int32_t z = MF_Minifont.zoom; - - if (t == NULL) - { - OSD_Printf("minitext: NULL text!\n"); - return 0; - } - - if (!(sb & ROTATESPRITE_FULL16)) - { - x<<=16; - y<<=16; - } - - if (sb & ROTATESPRITE_MAX) - { - x = sbarx16(x); - y = minitext_yofs+sbary16(y); - z = sbarsc(z); - } - - sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; - - dim = G_ScreenText(MF_Minifont.tilenum, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, MF_Minifont.emptychar.x, MF_Minifont.emptychar.y, MF_Minifont.between.x, MF_Minifont.between.y, MF_Minifont.textflags, 0, 0, xdim-1, ydim-1); - - x += dim.x; - - if (!(sb & ROTATESPRITE_FULL16)) - x >>= 16; - - return x; -} - -void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f) -{ - G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, s, MF_Redfont.pal, o|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, f|MF_Redfont.textflags|TEXT_LITERALESCAPE, 0, 0, xdim-1, ydim-1); -} - -void captionmenutext(int32_t x, int32_t y, char const *t) -{ - G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, 0, ud.menutitle_pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_XCENTER|TEXT_YCENTER, 0, 0, xdim-1, ydim-1); -} - - -int32_t user_quote_time[MAXUSERQUOTES]; -static char user_quote[MAXUSERQUOTES][178]; - -void G_AddUserQuote(const char *daquote) -{ - int32_t i; - - if (hud_messages == 0) return; - Printf(PRINT_MEDIUM | PRINT_NOTIFY, "%s\n", daquote); - if (hud_messages == 1) - { - for (i = MAXUSERQUOTES - 1; i > 0; i--) - { - Bstrcpy(user_quote[i], user_quote[i - 1]); - user_quote_time[i] = user_quote_time[i - 1]; - } - Bstrcpy(user_quote[0], daquote); - - user_quote_time[0] = hud_messagetime; - pub = NUMPAGES; - } -} - -int32_t textsc(int32_t sc) -{ - return scale(sc, hud_textscale, 400); -} - - - -#define FTAOPAQUETIME 30 - -// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required -static inline int32_t textsh(uint32_t t) -{ - return (hud_glowingquotes && ((videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) || t >= FTAOPAQUETIME)) - ? sintable[(t << 7) & 2047] >> 11 - : (sintable[(FTAOPAQUETIME << 7) & 2047] >> 11); -} - -// orientation flags depending on time that a quote has still to be displayed -static inline int32_t texto(int32_t t) -{ - if (videoGetRenderMode() != REND_CLASSIC || numalphatabs >= 15 || t > 4) - return 0; - - if (t > 2) - return 1; - - return 1|32; -} - -static inline int32_t texta(int32_t t) -{ - if (videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) - return 0; - - return 255 - clamp(t<<3, 0, 255); -} - -static FORCE_INLINE int32_t text_ypos(void) -{ - if (hud_position == 1 && ud.screen_size == 4 && ud.althud == 1) - return 32<<16; - -#ifdef GEKKO - return 16<<16; -#elif defined EDUKE32_TOUCH_DEVICES - return 24<<16; -#else - return 1<<16; -#endif -} - -static FString text_quote; // To put text into the quote display that does not come from the quote array. (Is it really necessary to implement everything as a hack??? :( ) - -// this handles both multiplayer and item pickup message type text -// both are passed on to gametext -void G_PrintGameQuotes(int32_t snum) -{ - auto const ps = g_player[snum].ps; - const int32_t reserved_quote = (ps->ftq >= QUOTE_RESERVED && ps->ftq <= QUOTE_RESERVED3); - // NOTE: QUOTE_RESERVED4 is not included. - - int32_t const ybase = (fragbarheight()<<16) + text_ypos(); - int32_t height = 0; - int32_t k = ps->fta; - - - // primary quote - - do - { - if (k <= 1) - break; - - int32_t y = ybase; - if (reserved_quote) - { -#ifdef SPLITSCREEN_MOD_HACKS - if (!g_fakeMultiMode) - y = 140<<16; - else - y = 70<<16; -#else - y = 140<<16; -#endif - } - - int32_t pal = 0; - int32_t x = 160<<16; - -#ifdef SPLITSCREEN_MOD_HACKS - if (g_fakeMultiMode) - { - pal = g_player[snum].pcolor; - const int32_t sidebyside = ud.screen_size != 0; - - if (sidebyside) - x = snum == 1 ? 240<<16 : 80<<16; - else if (snum == 1) - y += 100<<16; - } -#endif - - if (text_quote.IsNotEmpty() && ps->ftq == -32768) height = gametext_(x, y, text_quote, textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); - else height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16); - } - while (0); - - - // userquotes - - int32_t y = ybase; - - if (k > 1 && !reserved_quote) - y += k <= 8 ? (height * (k-1))>>3 : height; - - for (int i = 0; i < MAXUSERQUOTES; i++) - { - k = user_quote_time[i]; - - if (k <= 0) - continue; - - // int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0; - - height = mpgametext(mpgametext_x, y, user_quote[i], textsh(k), texto(k), texta(k), TEXT_LINEWRAP).y + textsc(1<<16); - y += k <= 4 ? (height * (k-1))>>2 : height; - } -} - -void P_DoQuote(int32_t q, DukePlayer_t *p) -{ - int32_t cq = 0; - - if (hud_messages == 0 || q < 0 || !(p->gm & MODE_GAME)) - return; - - if (q & MAXQUOTES) - { - cq = 1; - q &= ~MAXQUOTES; - } - - if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) - if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; - - if (p->ftq != q) - { - auto qu = quoteMgr.GetQuote(q); - if (p == g_player[screenpeek].ps && qu[0] != '\0') - Printf((cq? PRINT_LOW : PRINT_MEDIUM) | PRINT_NOTIFY, "%s\n", qu); - - } - - if (hud_messages == 1) - { - p->ftq = q; - p->fta = 100; - pub = NUMPAGES; - pus = NUMPAGES; - } -} - -void GameInterface::DoPrintMessage(int prio, const char* t) -{ - auto p = g_player[myconnectindex].ps; // text quotes always belong to the local player. - int32_t cq = 0; - - if (hud_messages == 0 || !(p->gm & MODE_GAME)) - return; - - if (p->fta > 0) - if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; - - if (p == g_player[screenpeek].ps) - Printf(prio | PRINT_NOTIFY, cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", t); - - if (hud_messages == 1) - { - p->fta = 100; - p->ftq = -32768; - text_quote = t; - pub = NUMPAGES; - pus = NUMPAGES; - } - -} - - -END_DUKE_NS diff --git a/source/duke3d/src/text.cpp b/source/duke3d/src/text.cpp new file mode 100644 index 000000000..1a588c04b --- /dev/null +++ b/source/duke3d/src/text.cpp @@ -0,0 +1,401 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "compat.h" +#include "sbar.h" +#include "menus.h" +#include "gstrings.h" +#include "quotemgr.h" + +#include "c_dispatch.h" +BEGIN_DUKE_NS + +// assign the character's tilenum +int GameInterface::GetStringTile(int font, const char* t, int f) +{ + if (f & TEXT_DIGITALNUMBER) + return *t - '0' + font; // copied from digitalnumber + else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT)) + { + int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0; + + if (*t >= '0' && *t <= '9') + return *t - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10); + else if (*t >= 'a' && *t <= 'z') + return *t - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26); + else if (*t >= 'A' && *t <= 'Z') + return *t - 'A' + font; + else switch (*t) + { + case '_': + case '-': + return font - (11 + offset); + break; + case '.': + return font + (BIGPERIOD - (BIGALPHANUM + offset)); + break; + case ',': + return font + (BIGCOMMA - (BIGALPHANUM + offset)); + break; + case '!': + return font + (BIGX_ - (BIGALPHANUM + offset)); + break; + case '?': + return font + (BIGQ - (BIGALPHANUM + offset)); + break; + case ';': + return font + (BIGSEMI - (BIGALPHANUM + offset)); + break; + case ':': + return font + (BIGCOLIN - (BIGALPHANUM + offset)); + break; + case '\\': + case '/': + return font + (68 - offset); // 3008-2940 + break; + case '%': + return font + (69 - offset); // 3009-2940 + break; + case '`': + case '\"': // could be better hacked in + case '\'': + return font + (BIGAPPOS - (BIGALPHANUM + offset)); + break; + default: // unknown character + fallthrough__; + case '\t': + case ' ': + case '\n': + case '\x7F': + return font; + break; + } + } + else + return *t - '!' + font; // uses ASCII order +} + +void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, + int32_t s, int32_t p, int32_t o, + int32_t x1, int32_t y1, int32_t x2, int32_t y2, + int32_t z, int32_t a) +{ + int32_t f = TEXT_GAMETEXTNUMHACK; + + if (t == NULL) + return; + + if (!(o & ROTATESPRITE_FULL16)) + { + x <<= 16; + y <<= 16; + } + + if (x == (160<<16)) + f |= TEXT_XCENTER; + + G_ScreenText(tile, x, y, z, 0, 0, t, s, p, 2|o|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, x1, y1, x2, y2); +} + +vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, s, p, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} +void gametext_simple(int32_t x, int32_t y, const char *t) +{ + G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1); +} +vec2_t mpgametext(int32_t x, int32_t y, const char *t, int32_t s, int32_t o, int32_t a, int32_t f) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, textsc(MF_Bluefont.zoom), 0, 0, t, s, MF_Bluefont.pal, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} +vec2_t mpgametextsize(const char *t, int32_t f) +{ + return G_ScreenTextSize(MF_Bluefont.tilenum, 0, 0, textsc(MF_Bluefont.zoom), 0, t, 2|8|16|ROTATESPRITE_FULL16, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} + +// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords, +// (sb&ROTATESPRITE_MAX) only. +int32_t minitext_yofs = 0; +int32_t minitext_lowercase = 0; +int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb) +{ + vec2_t dim; + int32_t z = MF_Minifont.zoom; + + if (t == NULL) + { + OSD_Printf("minitext: NULL text!\n"); + return 0; + } + + if (!(sb & ROTATESPRITE_FULL16)) + { + x<<=16; + y<<=16; + } + + if (sb & ROTATESPRITE_MAX) + { + x = sbarx16(x); + y = minitext_yofs+sbary16(y); + z = sbarsc(z); + } + + sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; + + dim = G_ScreenText(MF_Minifont.tilenum, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, MF_Minifont.emptychar.x, MF_Minifont.emptychar.y, MF_Minifont.between.x, MF_Minifont.between.y, MF_Minifont.textflags, 0, 0, xdim-1, ydim-1); + + x += dim.x; + + if (!(sb & ROTATESPRITE_FULL16)) + x >>= 16; + + return x; +} + +void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f) +{ + G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, s, MF_Redfont.pal, o|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, f|MF_Redfont.textflags|TEXT_LITERALESCAPE, 0, 0, xdim-1, ydim-1); +} + +void captionmenutext(int32_t x, int32_t y, char const *t) +{ + G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, 0, ud.menutitle_pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_XCENTER|TEXT_YCENTER, 0, 0, xdim-1, ydim-1); +} + + +int32_t user_quote_time[MAXUSERQUOTES]; +static char user_quote[MAXUSERQUOTES][178]; + +void G_AddUserQuote(const char *daquote) +{ + int32_t i; + + if (hud_messages == 0) return; + Printf(PRINT_MEDIUM | PRINT_NOTIFY, "%s\n", daquote); + if (hud_messages == 1) + { + for (i = MAXUSERQUOTES - 1; i > 0; i--) + { + Bstrcpy(user_quote[i], user_quote[i - 1]); + user_quote_time[i] = user_quote_time[i - 1]; + } + Bstrcpy(user_quote[0], daquote); + + user_quote_time[0] = hud_messagetime; + pub = NUMPAGES; + } +} + +int32_t textsc(int32_t sc) +{ + return scale(sc, hud_textscale, 400); +} + + + +#define FTAOPAQUETIME 30 + +// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required +static inline int32_t textsh(uint32_t t) +{ + return (hud_glowingquotes && ((videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) || t >= FTAOPAQUETIME)) + ? sintable[(t << 7) & 2047] >> 11 + : (sintable[(FTAOPAQUETIME << 7) & 2047] >> 11); +} + +// orientation flags depending on time that a quote has still to be displayed +static inline int32_t texto(int32_t t) +{ + if (videoGetRenderMode() != REND_CLASSIC || numalphatabs >= 15 || t > 4) + return 0; + + if (t > 2) + return 1; + + return 1|32; +} + +static inline int32_t texta(int32_t t) +{ + if (videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) + return 0; + + return 255 - clamp(t<<3, 0, 255); +} + +static FORCE_INLINE int32_t text_ypos(void) +{ + if (hud_position == 1 && ud.screen_size == 4 && ud.althud == 1) + return 32<<16; + +#ifdef GEKKO + return 16<<16; +#elif defined EDUKE32_TOUCH_DEVICES + return 24<<16; +#else + return 1<<16; +#endif +} + +static FString text_quote; // To put text into the quote display that does not come from the quote array. (Is it really necessary to implement everything as a hack??? :( ) + +// this handles both multiplayer and item pickup message type text +// both are passed on to gametext +void G_PrintGameQuotes(int32_t snum) +{ + auto const ps = g_player[snum].ps; + const int32_t reserved_quote = (ps->ftq >= QUOTE_RESERVED && ps->ftq <= QUOTE_RESERVED3); + // NOTE: QUOTE_RESERVED4 is not included. + + int32_t const ybase = (fragbarheight()<<16) + text_ypos(); + int32_t height = 0; + int32_t k = ps->fta; + + + // primary quote + + do + { + if (k <= 1) + break; + + int32_t y = ybase; + if (reserved_quote) + { +#ifdef SPLITSCREEN_MOD_HACKS + if (!g_fakeMultiMode) + y = 140<<16; + else + y = 70<<16; +#else + y = 140<<16; +#endif + } + + int32_t pal = 0; + int32_t x = 160<<16; + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode) + { + pal = g_player[snum].pcolor; + const int32_t sidebyside = ud.screen_size != 0; + + if (sidebyside) + x = snum == 1 ? 240<<16 : 80<<16; + else if (snum == 1) + y += 100<<16; + } +#endif + + if (text_quote.IsNotEmpty() && ps->ftq == -32768) height = gametext_(x, y, text_quote, textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); + else height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1<<16); + } + while (0); + + + // userquotes + + int32_t y = ybase; + + if (k > 1 && !reserved_quote) + y += k <= 8 ? (height * (k-1))>>3 : height; + + for (int i = 0; i < MAXUSERQUOTES; i++) + { + k = user_quote_time[i]; + + if (k <= 0) + continue; + + // int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0; + + height = mpgametext(mpgametext_x, y, user_quote[i], textsh(k), texto(k), texta(k), TEXT_LINEWRAP).y + textsc(1<<16); + y += k <= 4 ? (height * (k-1))>>2 : height; + } +} + +void P_DoQuote(int32_t q, DukePlayer_t *p) +{ + int32_t cq = 0; + + if (hud_messages == 0 || q < 0 || !(p->gm & MODE_GAME)) + return; + + if (q & MAXQUOTES) + { + cq = 1; + q &= ~MAXQUOTES; + } + + if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + if (p->ftq != q) + { + auto qu = quoteMgr.GetQuote(q); + if (p == g_player[screenpeek].ps && qu[0] != '\0') + Printf((cq? PRINT_LOW : PRINT_MEDIUM) | PRINT_NOTIFY, "%s\n", qu); + + } + + if (hud_messages == 1) + { + p->ftq = q; + p->fta = 100; + pub = NUMPAGES; + pus = NUMPAGES; + } +} + +void GameInterface::DoPrintMessage(int prio, const char* t) +{ + auto p = g_player[myconnectindex].ps; // text quotes always belong to the local player. + int32_t cq = 0; + + if (hud_messages == 0 || !(p->gm & MODE_GAME)) + return; + + if (p->fta > 0) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + if (p == g_player[screenpeek].ps) + Printf(prio | PRINT_NOTIFY, cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", t); + + if (hud_messages == 1) + { + p->fta = 100; + p->ftq = -32768; + text_quote = t; + pub = NUMPAGES; + pus = NUMPAGES; + } + +} + + +END_DUKE_NS diff --git a/source/duke3d/src/screentext.h b/source/duke3d/src/text.h similarity index 59% rename from source/duke3d/src/screentext.h rename to source/duke3d/src/text.h index 951796631..aeda2952d 100644 --- a/source/duke3d/src/screentext.h +++ b/source/duke3d/src/text.h @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once +#include "screentext.h" #include "menus.h" BEGIN_DUKE_NS @@ -33,29 +34,7 @@ extern int32_t user_quote_time[MAXUSERQUOTES]; extern int32_t minitext_lowercase; extern int32_t minitext_yofs; -enum ScreenTextFlags_t { - TEXT_XRIGHT = 0x00000001, - TEXT_XCENTER = 0x00000002, - TEXT_YBOTTOM = 0x00000004, - TEXT_YCENTER = 0x00000008, - TEXT_INTERNALSPACE = 0x00000010, - TEXT_TILESPACE = 0x00000020, - TEXT_INTERNALLINE = 0x00000040, - TEXT_TILELINE = 0x00000080, - TEXT_XOFFSETZERO = 0x00000100, - TEXT_XJUSTIFY = 0x00000200, - TEXT_YOFFSETZERO = 0x00000400, - TEXT_YJUSTIFY = 0x00000800, - TEXT_LINEWRAP = 0x00001000, - TEXT_UPPERCASE = 0x00002000, - TEXT_INVERTCASE = 0x00004000, - TEXT_IGNOREESCAPE = 0x00008000, - TEXT_LITERALESCAPE = 0x00010000, - TEXT_BACKWARDS = 0x00020000, - TEXT_GAMETEXTNUMHACK = 0x00040000, - TEXT_DIGITALNUMBER = 0x00080000, - TEXT_BIGALPHANUM = 0x00100000, - TEXT_GRAYFONT = 0x00200000, +enum { }; extern int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb); @@ -87,13 +66,4 @@ extern void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t z, int32_t a); -extern int32_t G_GetStringLineLength(const char *text, const char *end, int32_t iter); -extern int32_t G_GetStringNumLines(const char *text, const char *end, int32_t iter); -extern char* G_GetSubString(const char *text, const char *end, int32_t iter, int32_t length); -extern int32_t G_GetStringTile(int32_t font, char *t, int32_t f); -extern vec2_t G_ScreenTextSize(int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, const char *str, int32_t o, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); -extern void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, int32_t magnitude); -extern vec2_t G_ScreenText(int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, int32_t charangle, const char *str, int32_t shade, int32_t pal, int32_t o, int32_t alpha, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); -extern vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy, int32_t font, int32_t x, int32_t y, int32_t z, int32_t blockangle, int32_t charangle, const char *str, int32_t shade, int32_t pal, int32_t o, int32_t alpha, int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, int32_t f, int32_t x1, int32_t y1, int32_t x2, int32_t y2); - END_DUKE_NS diff --git a/source/rr/CMakeLists.txt b/source/rr/CMakeLists.txt index 67afc60fb..ca8eeeb42 100644 --- a/source/rr/CMakeLists.txt +++ b/source/rr/CMakeLists.txt @@ -21,7 +21,7 @@ set( PCH_SOURCES src/savegame.cpp src/sbar.cpp src/screens.cpp - src/screentext.cpp + src/text.cpp src/sector.cpp src/sounds.cpp src/soundsdyn.cpp diff --git a/source/rr/src/duke3d.h b/source/rr/src/duke3d.h index 09c5adb42..a51ec6a40 100644 --- a/source/rr/src/duke3d.h +++ b/source/rr/src/duke3d.h @@ -125,7 +125,7 @@ END_RR_NS #include "player.h" #include "quotes.h" #include "rts.h" -#include "screentext.h" +#include "text.h" #include "sector.h" #include "sounds.h" #include "soundsdyn.h" @@ -171,6 +171,7 @@ struct GameInterface : ::GameInterface void DrawPlayerSprite(const DVector2& origin, bool onteam) override; void QuitToTitle() override; FString GetCoordString() override; + int GetStringTile(int font, const char* t, int f) override; }; END_RR_NS diff --git a/source/rr/src/game.h b/source/rr/src/game.h index 776d7547b..b66637ff1 100644 --- a/source/rr/src/game.h +++ b/source/rr/src/game.h @@ -40,16 +40,7 @@ BEGIN_RR_NS // Compile game-side legacy Room over Room code? #define LEGACY_ROR 1 -#define USERQUOTE_LEFTOFFSET 5 -#define USERQUOTE_RIGHTOFFSET 14 - -#if defined(GEKKO) || defined(__OPENDINGUX__) -# define VIEWSCREENFACTOR 0 -#elif defined(__ANDROID__) -# define VIEWSCREENFACTOR 1 -#else # define VIEWSCREENFACTOR 2 -#endif enum GametypeFlags_t { GAMETYPE_COOP = 0x00000001, @@ -285,10 +276,6 @@ void G_OffMotorcycle(DukePlayer_t *pPlayer); void G_OnBoat(DukePlayer_t *pPlayer, int spriteNum); void G_OffBoat(DukePlayer_t *pPlayer); -#define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \ - if (alpha < 0) { blend = -alpha; alpha = 0; orientation |= RS_TRANS1; } \ -} while (0) - // Cstat protection mask for (currently) spawned MASKWALL* sprites. // TODO: look at more cases of cstat=(cstat&PROTECTED)|ADDED in A_Spawn()? // 2048+(32+16)+8+4 diff --git a/source/rr/src/screentext.cpp b/source/rr/src/screentext.cpp deleted file mode 100644 index 5719d5bd9..000000000 --- a/source/rr/src/screentext.cpp +++ /dev/null @@ -1,1193 +0,0 @@ -//------------------------------------------------------------------------- -/* -Copyright (C) 2016 EDuke32 developers and contributors - -This file is part of EDuke32. - -EDuke32 is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 2 -as published by the Free Software Foundation. - -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. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -//------------------------------------------------------------------------- -#include "ns.h" // Must come before everything else! - -#include "duke3d.h" -#include "compat.h" -#include "sbar.h" -#include "menus.h" -#include "gstrings.h" - -BEGIN_RR_NS - -// get the string length until the next '\n' -int32_t G_GetStringLineLength(const char *text, const char *end, const int32_t iter) -{ - int32_t length = 0; - - while (text != end && *text != '\n') - { - ++length; - - text += iter; - } - - return length; -} - -int32_t G_GetStringNumLines(const char *text, const char *end, const int32_t iter) -{ - int32_t count = 1; - - while (text != end) - { - if (*text == '\n') - ++count; - text += iter; - } - - return count; -} -// Note: Neither of these care about TEXT_LINEWRAP. This is intended. - -// This function requires you to Bfree() the returned char*. -char* G_GetSubString(const char *text, const char *end, const int32_t iter, const int32_t length) -{ - char *line = (char*) Xmalloc((length+1) * sizeof(char)); - int32_t counter = 0; - - while (counter < length && text != end) - { - line[counter] = *text; - - text += iter; - ++counter; - } - - line[counter] = '\0'; - - return line; -} - -// assign the character's tilenum -int32_t G_GetStringTile(int32_t font, char *t, int32_t f) -{ - if (f & TEXT_DIGITALNUMBER) - return *t - '0' + font; // copied from digitalnumber - else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT)) - { - int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0; - - if (*t >= '0' && *t <= '9') - return *t - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10); - else if (*t >= 'a' && *t <= 'z') - return *t - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26); - else if (*t >= 'A' && *t <= 'Z') - return *t - 'A' + font; - else switch (*t) - { - case '_': - case '-': - return font - (11 + offset); - break; - case '.': - return font + (BIGPERIOD - (BIGALPHANUM + offset)); - break; - case ',': - return font + (BIGCOMMA - (BIGALPHANUM + offset)); - break; - case '!': - return font + (BIGX_ - (BIGALPHANUM + offset)); - break; - case '?': - return font + (BIGQ - (BIGALPHANUM + offset)); - break; - case ';': - return font + (BIGSEMI - (BIGALPHANUM + offset)); - break; - case ':': - return font + (BIGCOLIN - (BIGALPHANUM + offset)); - break; - case '\\': - case '/': - return font + (68 - offset); // 3008-2940 - break; - case '%': - return font + (69 - offset); // 3009-2940 - break; - case '`': - case '\"': // could be better hacked in - case '\'': - return font + (BIGAPPOS - (BIGALPHANUM + offset)); - break; - default: // unknown character - *t = ' '; // whitespace-ize - fallthrough__; - case '\t': - case ' ': - case '\n': - case '\x7F': - return font; - break; - } - } - else - return *t - '!' + font; // uses ASCII order -} - -#define NUMHACKACTIVE ((f & TEXT_GAMETEXTNUMHACK) && t >= '0' && t <= '9') - -// qstrdim -vec2_t G_ScreenTextSize(const int32_t font, - int32_t x, int32_t y, const int32_t z, const int32_t blockangle, - const char *str, const int32_t o, - int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, - const int32_t f, - int32_t x1, int32_t y1, int32_t x2, int32_t y2) -{ - vec2_t size = { 0, 0, }; // eventually the return value - vec2_t pos = { 0, 0, }; // holds the coordinate position as we draw each character tile of the string - vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line - vec2_t offset = { 0, 0, }; // temporary; holds the last movement made in both directions - - int32_t tile; - char t; - - // set the start and end points depending on direction - int32_t iter = (f & TEXT_BACKWARDS) ? -1 : 1; // iteration direction - - const char *end; - const char *text; - - if (str == NULL) - return size; - - end = (f & TEXT_BACKWARDS) ? str-1 : Bstrchr(str, '\0'); - text = (f & TEXT_BACKWARDS) ? Bstrchr(str, '\0')-1 : str; - - // optimization: justification in both directions - if ((f & TEXT_XJUSTIFY) && (f & TEXT_YJUSTIFY)) - { - size.x = xbetween; - size.y = ybetween; - return size; - } - - // for best results, we promote 320x200 coordinates to full precision before any math - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - xspace <<= 16; - yline <<= 16; - xbetween <<= 16; - ybetween <<= 16; - } - // coordinate values should be shifted left by 16 - - // handle zooming where applicable - xspace = mulscale16(xspace, z); - yline = mulscale16(yline, z); - xbetween = mulscale16(xbetween, z); - ybetween = mulscale16(ybetween, z); - // size/width/height/spacing/offset values should be multiplied or scaled by $z, zoom (since 100% is 65536, the same as 1<<16) - - // loop through the string - while (text != end && (t = *text)) - { - // handle escape sequences - if (t == '^' && Bisdigit(*(text+iter)) && !(f & TEXT_LITERALESCAPE)) - { - text += iter + iter; - if (Bisdigit(*text)) - text += iter; - continue; - } - - // handle case bits - if (f & TEXT_UPPERCASE) - { - if (f & TEXT_INVERTCASE) // optimization...? - { // v^ important that these two ifs remain separate due to the else below - if (Bisupper(t)) - t = Btolower(t); - } - else if (Bislower(t)) - t = Btoupper(t); - } - else if (f & TEXT_INVERTCASE) - { - if (Bisupper(t)) - t = Btolower(t); - else if (Bislower(t)) - t = Btoupper(t); - } - - // translate the character to a tilenum - tile = G_GetStringTile(font, &t, f); - - // reset this here because we haven't printed anything yet this loop - extent.x = 0; - - // reset this here because the act of printing something on this line means that we include the margin above in the total size - offset.y = 0; - - // handle each character itself in the context of screen drawing - switch (t) - { - case '\t': - case ' ': - // width - extent.x = xspace; - - if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE)) - { - char space = '.'; // this is subject to change as an implementation detail - if (f & TEXT_TILESPACE) - space = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &space, f); - - extent.x += (tilesiz[tile].x * z); - } - - // prepare the height // near-CODEDUP the other two near-CODEDUPs for this section - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - if (t == '\t') - extent.x <<= 2; // *= 4 - - break; - - case '\n': // near-CODEDUP "if (wrap)" - extent.x = 0; - - // save the position - if (!(f & TEXT_XOFFSETZERO)) // we want the entire offset to count as the character width - pos.x -= offset.x; - SetIfGreater(&size.x, pos.x); - - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - offset.y = (f & TEXT_YJUSTIFY) ? 0 : ybetween; // ternary to prevent overflow - pos.y += offset.y; - - break; - - default: - // width - extent.x = tilesiz[tile].x * z; - - // obnoxious hardcoded functionality from gametext - if (NUMHACKACTIVE) - { - char numeral = '0'; // this is subject to change as an implementation detail - extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z; - } - - // height - SetIfGreater(&extent.y, (tilesiz[tile].y * z)); - - break; - } - - // incrementing the coordinate counters - offset.x = 0; - - // advance the x coordinate - if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE) - offset.x += extent.x; - - // account for text spacing - if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff - && t != '\n' - && !(f & TEXT_XJUSTIFY)) // to prevent overflow - offset.x += xbetween; - - // line wrapping - if ((f & TEXT_LINEWRAP) && !(f & TEXT_XRIGHT) && !(f & TEXT_XCENTER) && blockangle % 512 == 0) - { - int32_t wrap = 0; - const int32_t ang = blockangle % 2048; - - // this is the only place in qstrdim where angle actually affects direction, but only in the wrapping measurement - switch (ang) - { - case 0: - wrap = (x + (pos.x + offset.x) > ((o & 2) ? (320<<16) : ((x2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 512: - wrap = (y + (pos.x + offset.x) > ((o & 2) ? (200<<16) : ((y2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1024: - wrap = (x - (pos.x + offset.x) < ((o & 2) ? 0 : ((x1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1536: - wrap = (y - (pos.x + offset.x) < ((o & 2) ? 0 : ((y1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - } - if (wrap) // near-CODEDUP "case '\n':" - { - // save the position - SetIfGreater(&size.x, pos.x); - - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - offset.y = (f & TEXT_YJUSTIFY) ? 0 : ybetween; // ternary to prevent overflow - pos.y += offset.y; - } - else - pos.x += offset.x; - } - else - pos.x += offset.x; - - // save some trouble with calculation in case the line breaks - if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE) - offset.x -= extent.x; - - // iterate to the next character in the string - text += iter; - } - - // calculate final size - if (!(f & TEXT_XOFFSETZERO)) - pos.x -= offset.x; - - if (!(f & TEXT_YOFFSETZERO)) - { - pos.y -= offset.y; - pos.y += extent.y; - } - else - pos.y += ybetween; - - SetIfGreater(&size.x, pos.x); - SetIfGreater(&size.y, pos.y); - - // justification where only one of the two directions is set, so we have to iterate - if (f & TEXT_XJUSTIFY) - size.x = xbetween; - if (f & TEXT_YJUSTIFY) - size.y = ybetween; - - // return values in the same manner we receive them - if (!(o & ROTATESPRITE_FULL16)) - { - size.x >>= 16; - size.y >>= 16; - } - - return size; -} - -void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, const int32_t magnitude) -{ - coords->x += mulscale14(magnitude, unitDirection->x); - coords->y += mulscale14(magnitude, unitDirection->y); -} - -// screentext -vec2_t G_ScreenText(const int32_t font, - int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle, - const char *str, const int32_t shade, int32_t pal, int32_t o, int32_t alpha, - int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f, - const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2) -{ - vec2_t size = { 0, 0, }; // eventually the return value - vec2_t origin = { 0, 0, }; // where to start, depending on the alignment - vec2_t pos = { 0, 0, }; // holds the coordinate position as we draw each character tile of the string - vec2_t extent = { 0, 0, }; // holds the x-width of each character and the greatest y-height of each line - const vec2_t Xdirection = { sintable[(blockangle+512)&2047], sintable[blockangle&2047], }; - const vec2_t Ydirection = { sintable[(blockangle+1024)&2047], sintable[(blockangle+512)&2047], }; - const int32_t z2 = (RR && (f & TEXT_RRMENUTEXTHACK) != 0) ? 26214 : z; - - int32_t blendidx=0, tile; - char t; - - // set the start and end points depending on direction - int32_t iter = (f & TEXT_BACKWARDS) ? -1 : 1; // iteration direction - - const char *end; - const char *text; - - if (str == NULL) - return size; - - NEG_ALPHA_TO_BLEND(alpha, blendidx, o); - - end = (f & TEXT_BACKWARDS) ? str-1 : Bstrchr(str, '\0'); - text = (f & TEXT_BACKWARDS) ? Bstrchr(str, '\0')-1 : str; - - // for best results, we promote 320x200 coordinates to full precision before any math - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - xspace <<= 16; - yline <<= 16; - xbetween <<= 16; - ybetween <<= 16; - } - // coordinate values should be shifted left by 16 - - // eliminate conflicts, necessary here to get the correct size value - // especially given justification's special handling in G_ScreenTextSize() - if ((f & TEXT_XRIGHT) || (f & TEXT_XCENTER) || (f & TEXT_XJUSTIFY) || (f & TEXT_YJUSTIFY) || blockangle % 512 != 0) - o &= ~TEXT_LINEWRAP; - - // size is the return value, and we need it for alignment - size = G_ScreenTextSize(font, x, y, z, blockangle, str, o | ROTATESPRITE_FULL16, xspace, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY), x1, y1, x2, y2); - - int32_t const xspace_orig = xspace; - int32_t const yline_orig = yline; - int32_t const xbetween_orig = xbetween; - int32_t const ybetween_orig = ybetween; - // handle zooming where applicable - xspace = mulscale16(xspace, z); - yline = mulscale16(yline, z); - xbetween = mulscale16(xbetween, z); - ybetween = mulscale16(ybetween, z); - // size/width/height/spacing/offset values should be multiplied or scaled by $z, zoom (since 100% is 65536, the same as 1<<16) - - // alignment - // near-CODEDUP "case '\n':" - { - int32_t lines = G_GetStringNumLines(text, end, iter); - - if ((f & TEXT_XJUSTIFY) || (f & TEXT_XRIGHT) || (f & TEXT_XCENTER)) - { - const int32_t length = G_GetStringLineLength(text, end, iter); - - int32_t linewidth = size.x; - - if (lines != 1) - { - char *line = G_GetSubString(text, end, iter, length); - - linewidth = G_ScreenTextSize(font, x, y, z, blockangle, line, o | ROTATESPRITE_FULL16, xspace_orig, yline_orig, (f & TEXT_XJUSTIFY) ? 0 : xbetween_orig, (f & TEXT_YJUSTIFY) ? 0 : ybetween_orig, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; - - Xfree(line); - } - - if (f & TEXT_XJUSTIFY) - { - size.x = xbetween; - - xbetween = (length == 1) ? 0 : tabledivide32_noinline((xbetween - linewidth), (length - 1)); - - linewidth = size.x; - } - - if (f & TEXT_XRIGHT) - origin.x = -linewidth; - else if (f & TEXT_XCENTER) - origin.x = -(linewidth / 2); - } - - if (f & TEXT_YJUSTIFY) - { - const int32_t tempswap = ybetween; - ybetween = (lines == 1) ? 0 : tabledivide32_noinline(ybetween - size.y, lines - 1); - size.y = tempswap; - } - - if (f & TEXT_YBOTTOM) - origin.y = -size.y; - else if (f & TEXT_YCENTER) - origin.y = -(size.y / 2); - } - - // loop through the string - while (text != end && (t = *text)) - { - int32_t orientation = o; - int32_t angle = blockangle + charangle; - - // handle escape sequences - if (t == '^' && Bisdigit(*(text+iter)) && !(f & TEXT_LITERALESCAPE)) - { - char smallbuf[4]; - - text += iter; - smallbuf[0] = *text; - - text += iter; - if (Bisdigit(*text)) - { - smallbuf[1] = *text; - smallbuf[2] = '\0'; - text += iter; - } - else - smallbuf[1] = '\0'; - - if (!(f & TEXT_IGNOREESCAPE)) - pal = Batoi(smallbuf); - - continue; - } - - // handle case bits - if (f & TEXT_UPPERCASE) - { - if (f & TEXT_INVERTCASE) // optimization...? - { // v^ important that these two ifs remain separate due to the else below - if (Bisupper(t)) - t = Btolower(t); - } - else if (Bislower(t)) - t = Btoupper(t); - } - else if (f & TEXT_INVERTCASE) - { - if (Bisupper(t)) - t = Btolower(t); - else if (Bislower(t)) - t = Btoupper(t); - } - - // translate the character to a tilenum - tile = G_GetStringTile(font, &t, f); - - switch (t) - { - case '\t': - case ' ': - case '\n': - case '\x7F': - break; - - default: - { - vec2_t location = { x, y, }; - - G_AddCoordsFromRotation(&location, &Xdirection, origin.x); - G_AddCoordsFromRotation(&location, &Ydirection, origin.y); - - G_AddCoordsFromRotation(&location, &Xdirection, pos.x); - G_AddCoordsFromRotation(&location, &Ydirection, pos.y); - - rotatesprite_(location.x, location.y, z2, angle, tile, shade, pal, orientation, alpha, blendidx, x1, y1, x2, y2); - - break; - } - } - - // reset this here because we haven't printed anything yet this loop - extent.x = 0; - - // handle each character itself in the context of screen drawing - switch (t) - { - case '\t': - case ' ': - // width - extent.x = xspace; - - if (f & (TEXT_INTERNALSPACE|TEXT_TILESPACE)) - { - char space = '.'; // this is subject to change as an implementation detail - if (f & TEXT_TILESPACE) - space = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &space, f); - - extent.x += (tilesiz[tile].x * z); - } - - // prepare the height // near-CODEDUP the other two near-CODEDUPs for this section - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - if (t == '\t') - extent.x <<= 2; // *= 4 - - break; - - case '\n': // near-CODEDUP "if (wrap)" - extent.x = 0; - - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - pos.y += ybetween; - - // near-CODEDUP "alignments" - if ((f & TEXT_XJUSTIFY) || (f & TEXT_XRIGHT) || (f & TEXT_XCENTER)) - { - const int32_t length = G_GetStringLineLength(text+1, end, iter); - - char *line = G_GetSubString(text+1, end, iter, length); - - int32_t linewidth = G_ScreenTextSize(font, x, y, z, blockangle, line, o | ROTATESPRITE_FULL16, xspace_orig, yline_orig, (f & TEXT_XJUSTIFY) ? 0 : xbetween_orig, (f & TEXT_YJUSTIFY) ? 0 : ybetween_orig, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; - - Xfree(line); - - if (f & TEXT_XJUSTIFY) - { - xbetween = (length == 1) ? 0 : tabledivide32_noinline(xbetween - linewidth, length - 1); - - linewidth = size.x; - } - - if (f & TEXT_XRIGHT) - origin.x = -linewidth; - else if (f & TEXT_XCENTER) - origin.x = -(linewidth / 2); - } - - break; - - default: - // width - extent.x = tilesiz[tile].x * z; - - // obnoxious hardcoded functionality from gametext - if (NUMHACKACTIVE) - { - char numeral = '0'; // this is subject to change as an implementation detail - extent.x = (tilesiz[G_GetStringTile(font, &numeral, f)].x-1) * z; - } - - // height - SetIfGreater(&extent.y, (tilesiz[tile].y * z)); - - break; - } - - // incrementing the coordinate counters - { - int32_t xoffset = 0; - - // advance the x coordinate - if (!(f & TEXT_XOFFSETZERO) || NUMHACKACTIVE) - xoffset += extent.x; - - // account for text spacing - if (!NUMHACKACTIVE // this "if" line ONLY == replicating hardcoded stuff - && t != '\n') - xoffset += xbetween; - - // line wrapping - if (f & TEXT_LINEWRAP) - { - int32_t wrap = 0; - const int32_t ang = blockangle % 2048; - - // it's safe to make some assumptions and not go through G_AddCoordsFromRotation() since we limit to four directions - switch (ang) - { - case 0: - wrap = (x + (pos.x + xoffset) > ((orientation & 2) ? (320<<16) : ((x2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 512: - wrap = (y + (pos.x + xoffset) > ((orientation & 2) ? (200<<16) : ((y2 - USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1024: - wrap = (x - (pos.x + xoffset) < ((orientation & 2) ? 0 : ((x1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - case 1536: - wrap = (y - (pos.x + xoffset) < ((orientation & 2) ? 0 : ((y1 + USERQUOTE_RIGHTOFFSET)<<16))); - break; - } - if (wrap) // near-CODEDUP "case '\n':" - { - // reset the position - pos.x = 0; - - // prepare the height - { - int32_t tempyextent = yline; - - if (f & (TEXT_INTERNALLINE|TEXT_TILELINE)) - { - char line = 'A'; // this is subject to change as an implementation detail - if (f & TEXT_TILELINE) - line = '\x7F'; // tile after '~' - tile = G_GetStringTile(font, &line, f); - - tempyextent += tilesiz[tile].y * z; - } - - SetIfGreater(&extent.y, tempyextent); - } - - // move down the line height - if (!(f & TEXT_YOFFSETZERO)) - pos.y += extent.y; - - // reset the current height - extent.y = 0; - - // line spacing - pos.y += ybetween; - } - else - pos.x += xoffset; - } - else - pos.x += xoffset; - } - - // iterate to the next character in the string - text += iter; - } - - // return values in the same manner we receive them - if (!(o & ROTATESPRITE_FULL16)) - { - size.x >>= 16; - size.y >>= 16; - } - - return size; -} - -vec2_t G_ScreenTextShadow(int32_t sx, int32_t sy, - const int32_t font, - int32_t x, int32_t y, const int32_t z, const int32_t blockangle, const int32_t charangle, - const char *str, const int32_t shade, int32_t pal, int32_t o, const int32_t alpha, - int32_t xspace, int32_t yline, int32_t xbetween, int32_t ybetween, const int32_t f, - const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2) -{ - vec2_t size = { 0, 0, }; // eventually the return value - - if (!(o & ROTATESPRITE_FULL16)) - { - sx <<= 16; - sy <<= 16; - x <<= 16; - y <<= 16; - xspace <<= 16; - yline <<= 16; - xbetween <<= 16; - ybetween <<= 16; - } - - G_ScreenText(font, x + mulscale16(sx, z), y + mulscale16(sy, z), z, blockangle, charangle, str, 127, 4, o|ROTATESPRITE_FULL16, alpha, xspace, yline, xbetween, ybetween, f, x1, y1, x2, y2); - - size = G_ScreenText(font, x, y, z, blockangle, charangle, str, shade, pal, o|ROTATESPRITE_FULL16, alpha, xspace, yline, xbetween, ybetween, f, x1, y1, x2, y2); - - // return values in the same manner we receive them - if (!(o & ROTATESPRITE_FULL16)) - { - size.x >>= 16; - size.y >>= 16; - } - - return size; -} - -void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, - int32_t s, int32_t p, int32_t o, - int32_t x1, int32_t y1, int32_t x2, int32_t y2, - int32_t z, int32_t a) -{ - int32_t f = TEXT_GAMETEXTNUMHACK; - - if (t == NULL) - return; - - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - } - - if (x == (160<<16)) - f |= TEXT_XCENTER; - - G_ScreenText(tile, x, y, z, 0, 0, t, s, p, 2|o|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, x1, y1, x2, y2); -} - -vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f) -{ - return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, s, p, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); -} -void gametext_simple(int32_t x, int32_t y, const char *t) -{ - G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1); -} -vec2_t mpgametext(int32_t x, int32_t y, const char *t, int32_t s, int32_t o, int32_t a, int32_t f) -{ - return G_ScreenText(MF_Bluefont.tilenum, x, y, textsc(MF_Bluefont.zoom), 0, 0, t, s, MF_Bluefont.pal, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); -} -vec2_t mpgametextsize(const char *t, int32_t f) -{ - return G_ScreenTextSize(MF_Bluefont.tilenum, 0, 0, textsc(MF_Bluefont.zoom), 0, t, 2|8|16|ROTATESPRITE_FULL16, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); -} - -// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords, -// (sb&ROTATESPRITE_MAX) only. -int32_t minitext_yofs = 0; -int32_t minitext_lowercase = 0; -int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb) -{ - vec2_t dim; - int32_t z = MF_Minifont.zoom; - - if (t == NULL) - { - OSD_Printf("minitext: NULL text!\n"); - return 0; - } - - if (!(sb & ROTATESPRITE_FULL16)) - { - x<<=16; - y<<=16; - } - - if (sb & ROTATESPRITE_MAX) - { - if (sb & RS_ALIGN_R) - x = sbarxr16(x); - else - x = sbarx16(x); - y = minitext_yofs+sbary16(y); - z = sbarsc(z); - } - - sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; - - dim = G_ScreenText(MF_Minifont.tilenum, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, MF_Minifont.emptychar.x, MF_Minifont.emptychar.y, MF_Minifont.between.x, MF_Minifont.between.y, MF_Minifont.textflags, 0, 0, xdim-1, ydim-1); - - x += dim.x; - - if (!(sb & ROTATESPRITE_FULL16)) - x >>= 16; - - return x; -} - -void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f) -{ - G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, s, MF_Redfont.pal, o|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, f|MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_RRMENUTEXTHACK, 0, 0, xdim-1, ydim-1); -} - -void captionmenutext(int32_t x, int32_t y, char const *t) -{ - G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, 0, ud.menutitle_pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_XCENTER|TEXT_YCENTER, 0, 0, xdim-1, ydim-1); -} - - -int32_t user_quote_time[MAXUSERQUOTES]; -static char user_quote[MAXUSERQUOTES][178]; - -void G_AddUserQuote(const char* daquote) -{ - int32_t i; - - if (hud_messages == 0) return; - Printf(PRINT_MEDIUM | PRINT_NOTIFY, "%s\n", daquote); - if (hud_messages == 1) - { - for (i = MAXUSERQUOTES - 1; i > 0; i--) - { - Bstrcpy(user_quote[i], user_quote[i - 1]); - user_quote_time[i] = user_quote_time[i - 1]; - } - Bstrcpy(user_quote[0], daquote); - - user_quote_time[0] = hud_messagetime; - pub = NUMPAGES; - } -} - -int32_t textsc(int32_t sc) -{ - return scale(sc, hud_textscale, 400); -} - -#define FTAOPAQUETIME 30 - -// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required -static inline int32_t textsh(uint32_t t) -{ - return (hud_glowingquotes && ((videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) || t >= FTAOPAQUETIME)) - ? sintable[(t << 7) & 2047] >> 11 - : (sintable[(FTAOPAQUETIME << 7) & 2047] >> 11); -} - -// orientation flags depending on time that a quote has still to be displayed -static inline int32_t texto(int32_t t) -{ - if (videoGetRenderMode() != REND_CLASSIC || numalphatabs >= 15 || t > 4) - return 0; - - if (t > 2) - return 1; - - return 1|32; -} - -static inline int32_t texta(int32_t t) -{ - if (videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) - return 0; - - return 255 - clamp(t<<3, 0, 255); -} - -static FORCE_INLINE int32_t text_ypos(void) -{ - if (hud_position == 1 && ud.screen_size == 4 && ud.althud == 1) - return 32<<16; - -#ifdef GEKKO - return 16<<16; -#elif defined EDUKE32_TOUCH_DEVICES - return 24<<16; -#else - return 1<<16; -#endif -} - -static FString text_quote; // To put text into the quote display that does not come from the quote array. (Is it really necessary to implement everything as a hack??? :( ) - -// this handles both multiplayer and item pickup message type text -// both are passed on to gametext -void G_PrintGameQuotes(int32_t snum) -{ - const DukePlayer_t *const ps = g_player[snum].ps; - const int32_t reserved_quote = (ps->ftq >= QUOTE_RESERVED && ps->ftq <= QUOTE_RESERVED3); - // NOTE: QUOTE_RESERVED4 is not included. - - int32_t const ybase = (fragbarheight()<<16) + text_ypos(); - int32_t height = 0; - int32_t k = ps->fta; - - - // primary quote - - do - { - if (k <= 1) - break; - - int32_t y = ybase; - if (reserved_quote) - { -#ifdef SPLITSCREEN_MOD_HACKS - if (!g_fakeMultiMode) - y = 140<<16; - else - y = 70<<16; -#else - y = 140<<16; -#endif - } - - int32_t pal = 0; - int32_t x = 160<<16; - -#ifdef SPLITSCREEN_MOD_HACKS - if (g_fakeMultiMode) - { - pal = g_player[snum].pcolor; - const int32_t sidebyside = ud.screen_size != 0; - - if (sidebyside) - x = snum == 1 ? 240<<16 : 80<<16; - else if (snum == 1) - y += 100<<16; - } -#endif - - if (text_quote.IsNotEmpty() && ps->ftq == -32768) height = gametext_(x, y, text_quote, textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); - else height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); - } - while (0); - - - // userquotes - - int32_t y = ybase; - - if (k > 1 && !reserved_quote) - y += k <= 8 ? (height * (k-1))>>3 : height; - - for (size_t i = MAXUSERQUOTES-1; i < MAXUSERQUOTES; --i) - { - k = user_quote_time[i]; - - if (k <= 0) - continue; - - // int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0; - - height = mpgametext(mpgametext_x, y, user_quote[i], textsh(k), texto(k), texta(k), TEXT_LINEWRAP).y + textsc(1<<16); - y += k <= 4 ? (height * (k-1))>>2 : height; - } -} - -void P_DoQuote(int32_t q, DukePlayer_t *p) -{ - int32_t cq = 0; - - if (hud_messages == 0 || q < 0 || !(p->gm & MODE_GAME)) - return; - - if (q & MAXQUOTES) - { - cq = 1; - q &= ~MAXQUOTES; - } - - if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) - if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; - - if (p->ftq != q) - { - auto qu = quoteMgr.GetQuote(q); - if (p == g_player[screenpeek].ps && qu[0] != '\0') - Printf((cq ? PRINT_LOW : PRINT_MEDIUM) | PRINT_NOTIFY, "%s\n", qu); - - } - - if (hud_messages == 1) - { - p->ftq = q; - p->fta = 100; - pub = NUMPAGES; - pus = NUMPAGES; - } -} - -void GameInterface::DoPrintMessage(int prio, const char* t) -{ - auto p = g_player[myconnectindex].ps; // text quotes always belong to the local player. - int32_t cq = 0; - - if (hud_messages == 0 || !(p->gm & MODE_GAME)) - return; - - if (p->fta > 0) - if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; - - if (p == g_player[screenpeek].ps) - Printf(prio|PRINT_NOTIFY, cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", t); - - if (hud_messages == 1) - { - p->fta = 100; - p->ftq = -32768; - text_quote = t; - pub = NUMPAGES; - pus = NUMPAGES; - } -} - -END_RR_NS diff --git a/source/rr/src/text.cpp b/source/rr/src/text.cpp new file mode 100644 index 000000000..b86f0c666 --- /dev/null +++ b/source/rr/src/text.cpp @@ -0,0 +1,377 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "compat.h" +#include "sbar.h" +#include "menus.h" +#include "gstrings.h" + +BEGIN_RR_NS + +// assign the character's tilenum +int GameInterface::GetStringTile(int font, const char* t, int f) +{ + if (f & TEXT_DIGITALNUMBER) + return *t - '0' + font; // copied from digitalnumber + else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT)) + { + int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0; + + if (*t >= '0' && *t <= '9') + return *t - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10); + else if (*t >= 'a' && *t <= 'z') + return *t - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26); + else if (*t >= 'A' && *t <= 'Z') + return *t - 'A' + font; + else switch (*t) + { + case '_': + case '-': + return font - (11 + offset); + break; + case '.': + return font + (BIGPERIOD - (BIGALPHANUM + offset)); + break; + case ',': + return font + (BIGCOMMA - (BIGALPHANUM + offset)); + break; + case '!': + return font + (BIGX_ - (BIGALPHANUM + offset)); + break; + case '?': + return font + (BIGQ - (BIGALPHANUM + offset)); + break; + case ';': + return font + (BIGSEMI - (BIGALPHANUM + offset)); + break; + case ':': + return font + (BIGCOLIN - (BIGALPHANUM + offset)); + break; + case '\\': + case '/': + return font + (68 - offset); // 3008-2940 + break; + case '%': + return font + (69 - offset); // 3009-2940 + break; + case '`': + case '\"': // could be better hacked in + case '\'': + return font + (BIGAPPOS - (BIGALPHANUM + offset)); + break; + default: // unknown character + fallthrough__; + case '\t': + case ' ': + case '\n': + case '\x7F': + return font; + break; + } + } + else + return *t - '!' + font; // uses ASCII order +} + + +vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, s, p, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} +void gametext_simple(int32_t x, int32_t y, const char *t) +{ + G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1); +} +vec2_t mpgametext(int32_t x, int32_t y, const char *t, int32_t s, int32_t o, int32_t a, int32_t f) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, textsc(MF_Bluefont.zoom), 0, 0, t, s, MF_Bluefont.pal, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} +vec2_t mpgametextsize(const char *t, int32_t f) +{ + return G_ScreenTextSize(MF_Bluefont.tilenum, 0, 0, textsc(MF_Bluefont.zoom), 0, t, 2|8|16|ROTATESPRITE_FULL16, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} + +// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords, +// (sb&ROTATESPRITE_MAX) only. +int32_t minitext_yofs = 0; +int32_t minitext_lowercase = 0; +int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb) +{ + vec2_t dim; + int32_t z = MF_Minifont.zoom; + + if (t == NULL) + { + OSD_Printf("minitext: NULL text!\n"); + return 0; + } + + if (!(sb & ROTATESPRITE_FULL16)) + { + x<<=16; + y<<=16; + } + + if (sb & ROTATESPRITE_MAX) + { + if (sb & RS_ALIGN_R) + x = sbarxr16(x); + else + x = sbarx16(x); + y = minitext_yofs+sbary16(y); + z = sbarsc(z); + } + + sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; + + dim = G_ScreenText(MF_Minifont.tilenum, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, MF_Minifont.emptychar.x, MF_Minifont.emptychar.y, MF_Minifont.between.x, MF_Minifont.between.y, MF_Minifont.textflags, 0, 0, xdim-1, ydim-1); + + x += dim.x; + + if (!(sb & ROTATESPRITE_FULL16)) + x >>= 16; + + return x; +} + +void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f) +{ + if (RR) f |= TEXT_RRMENUTEXTHACK; + G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, s, MF_Redfont.pal, o|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, f|MF_Redfont.textflags|TEXT_LITERALESCAPE, 0, 0, xdim-1, ydim-1); +} + +void captionmenutext(int32_t x, int32_t y, char const *t) +{ + G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, 0, ud.menutitle_pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_XCENTER|TEXT_YCENTER, 0, 0, xdim-1, ydim-1); +} + + +int32_t user_quote_time[MAXUSERQUOTES]; +static char user_quote[MAXUSERQUOTES][178]; + +void G_AddUserQuote(const char* daquote) +{ + int32_t i; + + if (hud_messages == 0) return; + Printf(PRINT_MEDIUM | PRINT_NOTIFY, "%s\n", daquote); + if (hud_messages == 1) + { + for (i = MAXUSERQUOTES - 1; i > 0; i--) + { + Bstrcpy(user_quote[i], user_quote[i - 1]); + user_quote_time[i] = user_quote_time[i - 1]; + } + Bstrcpy(user_quote[0], daquote); + + user_quote_time[0] = hud_messagetime; + pub = NUMPAGES; + } +} + +int32_t textsc(int32_t sc) +{ + return scale(sc, hud_textscale, 400); +} + +#define FTAOPAQUETIME 30 + +// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required +static inline int32_t textsh(uint32_t t) +{ + return (hud_glowingquotes && ((videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) || t >= FTAOPAQUETIME)) + ? sintable[(t << 7) & 2047] >> 11 + : (sintable[(FTAOPAQUETIME << 7) & 2047] >> 11); +} + +// orientation flags depending on time that a quote has still to be displayed +static inline int32_t texto(int32_t t) +{ + if (videoGetRenderMode() != REND_CLASSIC || numalphatabs >= 15 || t > 4) + return 0; + + if (t > 2) + return 1; + + return 1|32; +} + +static inline int32_t texta(int32_t t) +{ + if (videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) + return 0; + + return 255 - clamp(t<<3, 0, 255); +} + +static FORCE_INLINE int32_t text_ypos(void) +{ + if (hud_position == 1 && ud.screen_size == 4 && ud.althud == 1) + return 32<<16; + +#ifdef GEKKO + return 16<<16; +#elif defined EDUKE32_TOUCH_DEVICES + return 24<<16; +#else + return 1<<16; +#endif +} + +static FString text_quote; // To put text into the quote display that does not come from the quote array. (Is it really necessary to implement everything as a hack??? :( ) + +// this handles both multiplayer and item pickup message type text +// both are passed on to gametext +void G_PrintGameQuotes(int32_t snum) +{ + const DukePlayer_t *const ps = g_player[snum].ps; + const int32_t reserved_quote = (ps->ftq >= QUOTE_RESERVED && ps->ftq <= QUOTE_RESERVED3); + // NOTE: QUOTE_RESERVED4 is not included. + + int32_t const ybase = (fragbarheight()<<16) + text_ypos(); + int32_t height = 0; + int32_t k = ps->fta; + + + // primary quote + + do + { + if (k <= 1) + break; + + int32_t y = ybase; + if (reserved_quote) + { +#ifdef SPLITSCREEN_MOD_HACKS + if (!g_fakeMultiMode) + y = 140<<16; + else + y = 70<<16; +#else + y = 140<<16; +#endif + } + + int32_t pal = 0; + int32_t x = 160<<16; + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode) + { + pal = g_player[snum].pcolor; + const int32_t sidebyside = ud.screen_size != 0; + + if (sidebyside) + x = snum == 1 ? 240<<16 : 80<<16; + else if (snum == 1) + y += 100<<16; + } +#endif + + if (text_quote.IsNotEmpty() && ps->ftq == -32768) height = gametext_(x, y, text_quote, textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); + else height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); + } + while (0); + + + // userquotes + + int32_t y = ybase; + + if (k > 1 && !reserved_quote) + y += k <= 8 ? (height * (k-1))>>3 : height; + + for (size_t i = MAXUSERQUOTES-1; i < MAXUSERQUOTES; --i) + { + k = user_quote_time[i]; + + if (k <= 0) + continue; + + // int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0; + + height = mpgametext(mpgametext_x, y, user_quote[i], textsh(k), texto(k), texta(k), TEXT_LINEWRAP).y + textsc(1<<16); + y += k <= 4 ? (height * (k-1))>>2 : height; + } +} + +void P_DoQuote(int32_t q, DukePlayer_t *p) +{ + int32_t cq = 0; + + if (hud_messages == 0 || q < 0 || !(p->gm & MODE_GAME)) + return; + + if (q & MAXQUOTES) + { + cq = 1; + q &= ~MAXQUOTES; + } + + if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + if (p->ftq != q) + { + auto qu = quoteMgr.GetQuote(q); + if (p == g_player[screenpeek].ps && qu[0] != '\0') + Printf((cq ? PRINT_LOW : PRINT_MEDIUM) | PRINT_NOTIFY, "%s\n", qu); + + } + + if (hud_messages == 1) + { + p->ftq = q; + p->fta = 100; + pub = NUMPAGES; + pus = NUMPAGES; + } +} + +void GameInterface::DoPrintMessage(int prio, const char* t) +{ + auto p = g_player[myconnectindex].ps; // text quotes always belong to the local player. + int32_t cq = 0; + + if (hud_messages == 0 || !(p->gm & MODE_GAME)) + return; + + if (p->fta > 0) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + if (p == g_player[screenpeek].ps) + Printf(prio|PRINT_NOTIFY, cq ? OSDTEXT_DEFAULT "%s\n" : "%s\n", t); + + if (hud_messages == 1) + { + p->fta = 100; + p->ftq = -32768; + text_quote = t; + pub = NUMPAGES; + pus = NUMPAGES; + } +} + +END_RR_NS diff --git a/source/rr/src/text.h b/source/rr/src/text.h new file mode 100644 index 000000000..b4c3d9259 --- /dev/null +++ b/source/rr/src/text.h @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- + +#pragma once + +#include "menus.h" +#include "screentext.h" + +BEGIN_RR_NS + +#define MAXUSERQUOTES 6 + +extern int32_t user_quote_time[MAXUSERQUOTES]; +extern int32_t minitext_lowercase; +extern int32_t minitext_yofs; + + +extern int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb); +extern void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f); +extern void captionmenutext(int32_t x, int32_t y, char const *t); +extern vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f); +extern void gametext_simple(int32_t x, int32_t y, const char *t); +#define mpgametext_x (5<<16) +extern vec2_t mpgametext(int32_t x, int32_t y, char const * t, int32_t s, int32_t o, int32_t a, int32_t f); +extern vec2_t mpgametextsize(char const * t, int32_t f); +extern int32_t textsc(int32_t sc); + +#define minitextshade(x, y, t, s, p, sb) minitext_(x,y,t,s,p,sb) +#define minitext(x, y, t, p, sb) minitext_(x,y,t,0,p,sb) +#define menutext(x, y, t) menutext_((x)<<16, (y)<<16, 0, (t), 10|16, 0) +#define menutext_centeralign(x, y, t) menutext_((x), (y), 0, (t), 10|16, TEXT_XCENTER|TEXT_YCENTER) +#define menutext_center(y, t) menutext_(160<<16, (y)<<16, 0, (t), 10|16, TEXT_XCENTER) +#define gametext(x, y, t) gametext_simple((x)<<16, (y)<<16, (t)) +#define gametext_widenumber(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 1024, 0, TEXT_GAMETEXTNUMHACK) +#define gametext_number(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_GAMETEXTNUMHACK) +#define gametext_pal(x, y, t, p) gametext_((x)<<16, (y)<<16, (t), 0, (p), 0, 0, 0) +#define gametext_center(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER) +#define gametext_center_number(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER|TEXT_GAMETEXTNUMHACK) +#define gametext_center_shade(y, t, s) gametext_(160<<16, (y)<<16, (t), (s), MF_Bluefont.pal, 0, 0, TEXT_XCENTER) +#define gametext_center_shade_pal(y, t, s, p) gametext_(160<<16, (y)<<16, (t), (s), (p), 0, 0, TEXT_XCENTER) + + +END_RR_NS