From 023bc4002042fcfad6779c0e8bd797c5a7069a89 Mon Sep 17 00:00:00 2001 From: terminx Date: Sun, 7 Feb 2016 02:38:23 +0000 Subject: [PATCH] Break all of the text printing stuff out of game.c and into a separate screentext.c/h git-svn-id: https://svn.eduke32.com/eduke32@5614 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/Makefile | 2 +- polymer/eduke32/Makefile.deps | 1 + polymer/eduke32/Makefile.msvc | 1 + polymer/eduke32/eduke32.vcxproj | 2 + polymer/eduke32/eduke32.vcxproj.filters | 6 + polymer/eduke32/source/duke3d.h | 1 + polymer/eduke32/source/game.c | 1213 +--------------------- polymer/eduke32/source/game.h | 62 +- polymer/eduke32/source/sbar.c | 10 + polymer/eduke32/source/sbar.h | 8 + polymer/eduke32/source/screentext.c | 1218 +++++++++++++++++++++++ polymer/eduke32/source/screentext.h | 80 ++ 12 files changed, 1339 insertions(+), 1265 deletions(-) create mode 100644 polymer/eduke32/source/screentext.c create mode 100644 polymer/eduke32/source/screentext.h diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index 032fe0416..3499bef82 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -230,7 +230,7 @@ MAPSTER32_TARGET:=$(MAPSTER32)$(EXESUFFIX) COMMON_OBJS=rev COMMON_EDITOR_OBJS=m32common m32def m32exec m32vars rev -DUKE3D_OBJS=game global actors gamedef gameexec gamevars player premap sector anim animsounds common config demo input menus namesdyn net savegame rts osdfuncs osdcmds grpscan sounds soundsdyn cheats sbar +DUKE3D_OBJS=game global actors gamedef gameexec gamevars player premap sector anim animsounds common config demo input menus namesdyn net savegame rts osdfuncs osdcmds grpscan sounds soundsdyn cheats sbar screentext DUKE3D_EDITOR_OBJS=astub common grpscan sounds_mapster32 ifneq ($(USE_LIBVPX),0) diff --git a/polymer/eduke32/Makefile.deps b/polymer/eduke32/Makefile.deps index a8bab462d..e80ad9425 100644 --- a/polymer/eduke32/Makefile.deps +++ b/polymer/eduke32/Makefile.deps @@ -56,6 +56,7 @@ $(DUKE3D_OBJ)/player.$o: $(DUKE3D_SRC)/player.c $(duke3d_h) $(DUKE3D_OBJ)/premap.$o: $(DUKE3D_SRC)/premap.c $(duke3d_h) $(ENGINE_INC)/osd.h $(DUKE3D_OBJ)/savegame.$o: $(DUKE3D_SRC)/savegame.c $(duke3d_h) $(DUKE3D_SRC)/savegame.h $(DUKE3D_OBJ)/sbar.$o: $(DUKE3D_SRC)/sbar.c $(DUKE3D_SRC)/sbar.h +$(DUKE3D_OBJ)/screentext.$o: $(DUKE3D_SRC)/screentext.c $(DUKE3D_SRC)/screentext.h $(DUKE3D_OBJ)/sector.$o: $(DUKE3D_SRC)/sector.c $(duke3d_h) $(DUKE3D_SRC)/input.h $(DUKE3D_OBJ)/sounds.$o: $(DUKE3D_SRC)/sounds.c $(duke3d_h) $(DUKE3D_OBJ)/soundsdyn.$o: $(DUKE3D_SRC)/soundsdyn.c $(duke3d_h) diff --git a/polymer/eduke32/Makefile.msvc b/polymer/eduke32/Makefile.msvc index 7ec924a09..45545d6d3 100644 --- a/polymer/eduke32/Makefile.msvc +++ b/polymer/eduke32/Makefile.msvc @@ -197,6 +197,7 @@ DUKE3D_OBJS=$(DUKE3D_OBJ)\game.$o \ $(DUKE3D_OBJ)\animvpx.$o \ $(DUKE3D_OBJ)\cheats.$o \ $(DUKE3D_OBJ)\sbar.$o \ + $(DUKE3D_OBJ)\screentext.$o \ $(DUKE3D_OBJ)\common.$o \ $(DUKE3D_OBJ)\demo.$o \ $(DUKE3D_OBJ)\gamedef.$o \ diff --git a/polymer/eduke32/eduke32.vcxproj b/polymer/eduke32/eduke32.vcxproj index 99ff1b73a..9ee08d9b4 100644 --- a/polymer/eduke32/eduke32.vcxproj +++ b/polymer/eduke32/eduke32.vcxproj @@ -194,6 +194,7 @@ + @@ -343,6 +344,7 @@ + diff --git a/polymer/eduke32/eduke32.vcxproj.filters b/polymer/eduke32/eduke32.vcxproj.filters index 92f754425..4d562c7b3 100644 --- a/polymer/eduke32/eduke32.vcxproj.filters +++ b/polymer/eduke32/eduke32.vcxproj.filters @@ -516,6 +516,9 @@ eduke32\source\editor + + eduke32\headers + @@ -905,6 +908,9 @@ eduke32\source + + eduke32\source + diff --git a/polymer/eduke32/source/duke3d.h b/polymer/eduke32/source/duke3d.h index 644fc73ee..1a739453d 100644 --- a/polymer/eduke32/source/duke3d.h +++ b/polymer/eduke32/source/duke3d.h @@ -143,6 +143,7 @@ EDUKE32_STATIC_ASSERT(7 <= MAXTILES-MAXUSERTILES); #include "gamedef.h" #include "gameexec.h" #include "gamevars.h" +#include "screentext.h" #ifdef LUNATIC # include "lunatic_game.h" diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index d093e48a1..29674faa6 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "colmatch.h" #include "cheats.h" #include "sbar.h" + #ifdef __ANDROID__ #include "android.h" #endif @@ -107,11 +108,6 @@ const char *g_rtsNamePtr = NULL; int32_t g_Shareware = 0; -#define MAXUSERQUOTES 6 -int32_t quotebot, quotebotgoal; -static int32_t user_quote_time[MAXUSERQUOTES]; -static char user_quote[MAXUSERQUOTES][178]; - // This was 32 for a while, but I think lowering it to 24 will help things like the Dingoo. // Ideally, we would look at our memory usage on our most cramped platform and figure out // how much of that is needed for the underlying OS and things like SDL instead of guessing @@ -131,27 +127,8 @@ static void G_DrawCameraText(int16_t i); GAME_STATIC GAME_INLINE int32_t G_MoveLoop(void); static void G_DoOrderScreen(void); -#define FTAOPAQUETIME 30 - -// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required -#define ftapulseshade \ - ((hud_glowingquotes && ((getrendermode() == REND_CLASSIC && numalphatabs < 16) || ps->fta >= FTAOPAQUETIME)) ? \ - (sintable[((uint32_t)ps->fta << 7) & 2047] >> 11) : \ - (sintable[((uint32_t)FTAOPAQUETIME << 7) & 2047] >> 11)) - #define quotepulseshade (sintable[((uint32_t)totalclock<<5)&2047]>>11) -int32_t althud_numbertile = 2930; -int32_t althud_numberpal = 0; - -#ifdef EDUKE32_TOUCH_DEVICES -int32_t althud_shadows = 0; -#else -int32_t althud_shadows = 1; -#endif - -int32_t althud_flashing = 1; -int32_t hud_glowingquotes = 1; int32_t hud_showmapname = 1; int32_t g_levelTextTime = 0; @@ -211,20 +188,6 @@ enum gametokens T_GLOBALGAMEFLAGS, }; -int32_t textsc(int32_t sc) -{ - // prevent ridiculousness to a degree - if (xdim <= 320) return sc; - else if (xdim <= 640) return scale(sc,min(200,ud.textscale),100); - else if (xdim <= 800) return scale(sc,min(300,ud.textscale),100); - else if (xdim <= 1024) return scale(sc,min(350,ud.textscale),100); - return scale(sc,ud.textscale,100); -} -static int32_t gtextsc(int32_t sc) -{ - return scale(sc,ud.textscale,400); -} - void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, int32_t set) { if (palid >= MAXBASEPALS) @@ -238,982 +201,6 @@ void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, int32_t set) setbrightness(ud.brightness>>2, palid, set); } -// 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 != '\n' && text != end) - { - ++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 - case '\n': - 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 = scale(xspace, z, 65536); - yline = scale(yline, z, 65536); - xbetween = scale(xbetween, z, 65536); - ybetween = scale(ybetween, z, 65536); - // 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 ((t = *text) && text != end) - { - // 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 += scale(magnitude, unitDirection->x, 16384); - coords->y += scale(magnitude, unitDirection->y, 16384); -} - -// 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); - - // handle zooming where applicable - xspace = scale(xspace, z, 65536); - yline = scale(yline, z, 65536); - xbetween = scale(xbetween, z, 65536); - ybetween = scale(ybetween, z, 65536); - // 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, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; - - Bfree(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 ((t = *text) && text != end) - { - 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, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; - - Bfree(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 + scale(sx,z,65536), y + scale(sy,z,65536), 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; -} - -// flags -// 4: small font, wrap strings? -int32_t G_PrintGameText(int32_t hack, 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) -{ - vec2_t dim; - int32_t f = TEXT_GAMETEXTNUMHACK; - int32_t xbetween = 0; - const int32_t orient = (hack & 4) || (hack & 1) ? (8|16|(o&1)|(o&32)) : (2|o); - - if (t == NULL) - return -1; - - if (!(o & ROTATESPRITE_FULL16)) - { - x <<= 16; - y <<= 16; - } - - if (hack & 4) - { - x = textsc(x); - z = textsc(z); - f |= TEXT_LINEWRAP; - } - - if (hack & 8) - { - f |= TEXT_XOFFSETZERO; - xbetween = 8; - } - - // order is important, this bit comes after the rest - if ((hack & 2) && !NAM_WW2GI) // squishtext - --xbetween; - - if (x == (160<<16)) - f |= TEXT_XCENTER; - - dim = G_ScreenText(tile, x, y, z, 0, 0, t, s, p, orient|ROTATESPRITE_FULL16, a, (5<<16), (8<<16), (xbetween<<16), 0, f, x1, y1, x2, y2); - - x += dim.x; - - if (!(o & ROTATESPRITE_FULL16)) - x >>= 16; - - return x; -} - -int32_t G_GameTextLen(int32_t x,const char *t) -{ - vec2_t dim; - - if (t == NULL) - return -1; - - dim = G_ScreenTextSize(STARTALPHANUM, x, 0, textsc(65536L), 0, t, 2, 5, 8, 0, 0, TEXT_GAMETEXTNUMHACK, 0, 0, xdim-1, ydim-1); - - x += dim.x; - - return x; -} - -// 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 = 65536L; - int32_t f = 0; - - if (t == NULL) - { - OSD_Printf("minitext: NULL text!\n"); - return 0; - } - - if (!(sb & ROTATESPRITE_FULL16)) - { - x<<=16; - y<<=16; - } - - if (!minitext_lowercase) - f |= TEXT_UPPERCASE; - - if (sb & ROTATESPRITE_MAX) - { - x = sbarx16(x); - y = minitext_yofs+sbary16(y); - z = sbarsc(z); - } - - sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; - - dim = G_ScreenText(MINIFONT, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, (4<<16), (8<<16), (1<<16), 0, f, 0, 0, xdim-1, ydim-1); - - x += dim.x; - - if (!(sb & ROTATESPRITE_FULL16)) - x >>= 16; - - return x; -} - -void G_AddUserQuote(const char *daquote) -{ - int32_t i; - - 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); - OSD_Printf("%s\n",daquote); - - user_quote_time[0] = ud.msgdisptime; - pub = NUMPAGES; -} - void G_HandleSpecialKeys(void) { // we need CONTROL_GetInput in order to pick up joystick button presses @@ -1589,199 +576,6 @@ static void G_PrintCoords(int32_t snum) } -// orientation flags depending on time that a quote has still to be displayed -static inline int32_t texto(int32_t t) -{ - if (t > 4) return 2+8+16; - if (t > 2) return 2+8+16+1; - return 2+8+16+1+32; -} - -static inline int32_t texta(int32_t t) -{ - if (getrendermode() == REND_CLASSIC && numalphatabs < 16) - { - if (t > 4) return 0; - if (t > 2) return 85; - return 169; - } - - t = clamp(t<<3, 0, 255); - return 255 - t; -} - -static int32_t calc_ybase(int32_t begy) -{ - int32_t k = begy; - - if (GTFLAGS(GAMETYPE_FRAGBAR) && ud.screen_size > 0 -#ifdef SPLITSCREEN_MOD_HACKS - && !g_fakeMultiMode -#endif - && (g_netServer || ud.multimode > 1)) - { - int32_t i, j = 0; - - k += 8; - for (TRAVERSE_CONNECT(i)) - if (i > j) - j = i; - - if (j >= 4 && j <= 8) k += 8; - else if (j > 8 && j <= 12) k += 16; - else if (j > 12) k += 24; - } - - return k; -} - -// this handles both multiplayer and item pickup message type text -// both are passed on to gametext -void G_PrintGameQuotes(int32_t snum) -{ - int32_t i, j, k; - - 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. - - k = calc_ybase(1); - - if (ps->fta > 1 && !reserved_quote) - { - k += min(7, ps->fta); - } - - j = scale(k, ydim, 200); - - for (i=MAXUSERQUOTES-1; i>=0; i--) - { - int32_t sh, l; - - if (user_quote_time[i] <= 0) - continue; - - k = user_quote_time[i]; - - sh = hud_glowingquotes ? (sintable[((totalclock+(i<<2))<<5)&2047]>>11) : 0; - - mpgametext(j, user_quote[i], sh, texto(k)); - j += textsc(k > 4 ? 8 : (k<<1)); - - l = G_GameTextLen(USERQUOTE_LEFTOFFSET, OSD_StripColors(tempbuf,user_quote[i])); - while (l > (ud.config.ScreenWidth - USERQUOTE_RIGHTOFFSET)) - { - l -= (ud.config.ScreenWidth-USERQUOTE_RIGHTOFFSET); - j += textsc(k > 4 ? 8 : (k<<1)); - } - } - - if (klabs(quotebotgoal-quotebot) <= 16 && ud.screen_size <= 8) - quotebot += ksgn(quotebotgoal-quotebot); - else - quotebot = quotebotgoal; - - if (ps->fta <= 1) - return; - - if (EDUKE32_PREDICT_FALSE(ScriptQuotes[ps->ftq] == NULL)) - { - OSD_Printf(OSD_ERROR "%s %d null quote %d\n",__FILE__,__LINE__,ps->ftq); - return; - } - - k = calc_ybase(0); - - if (k == 0) - { - if (reserved_quote) - { -#ifdef SPLITSCREEN_MOD_HACKS - if (!g_fakeMultiMode) - k = 140; // quotebot-8-4; - else - k = 50; -#else - k = 140; -#endif - } - else - { - if (ud.althud == 2) - k = 32; - else -#ifdef GEKKO - k = 16; -#elif defined EDUKE32_TOUCH_DEVICES - k = 24; -#else - k = 1; -#endif - } - } - - int32_t pal = 0; - -#ifdef SPLITSCREEN_MOD_HACKS - if (g_fakeMultiMode) - { - pal = g_player[snum].pcolor; - - if (snum == 1) - { - const int32_t sidebyside = (ud.screen_size != 0); - - // NOTE: setting gametext's x -= 80 doesn't do the expected thing. - // Needs looking into. - if (sidebyside) - k += 9; - else - k += 101; - } - } -#endif - - gametextpalbits(160, k, ScriptQuotes[ps->ftq], ftapulseshade, pal, 2 + 8 + 16, texta(ps->fta)); -} - -void P_DoQuote(int32_t q, DukePlayer_t *p) -{ - int32_t cq = 0; - - if (ud.fta_on == 0 || q < 0 || !(p->gm & MODE_GAME)) - return; - - if (q & MAXQUOTES) - { - cq = 1; - q &= ~MAXQUOTES; - } - - if (EDUKE32_PREDICT_FALSE(ScriptQuotes[q] == NULL)) - { - OSD_Printf(OSD_ERROR "%s %d null quote %d\n",__FILE__,__LINE__,q); - return; - } - - if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) - if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; - - p->fta = 100; - - if (p->ftq != q) - { - if (p == g_player[screenpeek].ps - && Bstrcmp(ScriptQuotes[q],"")) // avoid printing blank quotes - { - if (cq) OSD_Printf(OSDTEXT_BLUE "%s\n",ScriptQuotes[q]); - else OSD_Printf("%s\n",ScriptQuotes[q]); - } - - p->ftq = q; - } - pub = NUMPAGES; - pus = NUMPAGES; -} ////////// OFTEN-USED FEW-LINERS ////////// @@ -2509,6 +1303,11 @@ static void G_FadePalaccum(const palaccum_t *pa) } +static int32_t gtextsc(int32_t sc) +{ + return scale(sc, ud.textscale, 400); +} + ////////// DISPLAYREST ////////// void G_DisplayRest(int32_t smoothratio) diff --git a/polymer/eduke32/source/game.h b/polymer/eduke32/source/game.h index 940ed0f61..fe1ad989b 100644 --- a/polymer/eduke32/source/game.h +++ b/polymer/eduke32/source/game.h @@ -1,6 +1,6 @@ //------------------------------------------------------------------------- /* -Copyright (C) 2010 EDuke32 developers and contributors +Copyright (C) 2016 EDuke32 developers and contributors This file is part of EDuke32. @@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- +#pragma once + #ifndef game_h_ #define game_h_ @@ -96,31 +98,6 @@ enum LogoFlags_t { LOGO_NODUKETEAMPIC = 0x00100000, }; -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, -}; - void A_DeleteSprite(int32_t s); static inline int32_t G_GetLogoFlags(void) @@ -275,11 +252,6 @@ extern char ror_protectedsectors[MAXSECTORS]; extern float r_ambientlight; -extern int32_t althud_flashing; -extern int32_t althud_numberpal; -extern int32_t althud_numbertile; -extern int32_t althud_shadows; - extern int32_t g_Debug; extern int32_t g_Shareware; #if !defined LUNATIC @@ -316,16 +288,11 @@ extern uint32_t g_frameDelay; extern user_defs ud; int32_t A_CheckInventorySprite(spritetype *s); -int32_t A_InsertSprite(int16_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int16_t s_pn,int8_t s_s,uint8_t s_xr,uint8_t s_yr,int16_t s_a,int16_t s_ve,int16_t s_zv,int16_t s_ow,int16_t s_ss); +int32_t A_InsertSprite(int16_t whatsect, int32_t s_x, int32_t s_y, int32_t s_z, int16_t s_pn, int8_t s_s, uint8_t s_xr, + uint8_t s_yr, int16_t s_a, int16_t s_ve, int16_t s_zv, int16_t s_ow, int16_t s_ss); int32_t A_Spawn(int32_t j,int32_t pn); int32_t G_DoMoveThings(void); //int32_t G_EndOfLevel(void); -int32_t G_GameTextLen(int32_t x,const char *t); -int32_t G_PrintGameText(int32_t hack,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 minitext_lowercase; -extern int32_t minitext_yofs; -int32_t minitext_(int32_t x,int32_t y,const char *t,int32_t s,int32_t p,int32_t sb); -int32_t mpgametext(int32_t y,const char *t,int32_t s,int32_t dabits); #ifdef YAX_ENABLE void Yax_SetBunchZs(int32_t sectnum, int32_t cf, int32_t daz); @@ -379,18 +346,8 @@ void G_Shutdown(void); void G_UpdatePlayerFromMenu(void); void M32RunScript(const char *s); void P_DoQuote(int32_t q,DukePlayer_t *p); -extern int32_t textsc(int32_t sc); void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, int32_t set); -extern int32_t G_GetStringLineLength(const char *text, const char *end, const int32_t iter); -extern int32_t G_GetStringNumLines(const char *text, const char *end, const int32_t iter); -extern char* G_GetSubString(const char *text, const char *end, const int32_t iter, const int32_t length); -extern int32_t G_GetStringTile(int32_t font, char *t, int32_t f); -extern 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, const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2); -extern void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, const int32_t magnitude); -extern 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, int32_t x1, int32_t y1, int32_t x2, int32_t y2); -extern 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, int32_t x1, int32_t y1, int32_t x2, int32_t y2); - #define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \ if (alpha < 0) { blend = -alpha; alpha = 0; orientation |= RS_TRANS1; } \ } while (0) @@ -414,15 +371,6 @@ static inline int32_t G_GetTeamPalette(int32_t team) return pal[team]; } -#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,s,p,t) menutext_(x,y,s,p,OSD_StripColors(menutextbuf,t),10+16) -#define gametext(x,y,t,s,dabits) G_PrintGameText(0,STARTALPHANUM, x,y,t,s,0,dabits,0, 0, xdim-1, ydim-1, 65536, 0) -#define gametextscaled(x,y,t,s,dabits) G_PrintGameText(1,STARTALPHANUM, x,y,t,s,0,dabits,0, 0, xdim-1, ydim-1, 65536, 0) -#define gametextpal(x,y,t,s,p) G_PrintGameText(0,STARTALPHANUM, x,y,t,s,p,26,0, 0, xdim-1, ydim-1, 65536, 0) -#define gametextpalbits(x,y,t,s,p,dabits,a) G_PrintGameText(0,STARTALPHANUM, x,y,t,s,p,dabits,0, 0, xdim-1, ydim-1, 65536, a) -#define mpgametext(y, t, s, dabits) G_PrintGameText(4,STARTALPHANUM, 5,y,t,s,0,dabits,0, 0, xdim-1, ydim-1, 65536, 0); - #define A_CheckSpriteFlags(iActor, iType) (((g_tile[sprite[iActor].picnum].flags^actor[iActor].flags) & iType) != 0) // (unsigned)iPicnum check: AMC TC Rusty Nails, bayonet MG alt. fire, iPicnum == -1 (via aplWeaponShoots) #define A_CheckSpriteTileFlags(iPicnum, iType) (((unsigned)iPicnum < MAXTILES) && (g_tile[iPicnum].flags & iType) != 0) diff --git a/polymer/eduke32/source/sbar.c b/polymer/eduke32/source/sbar.c index dde86ccba..5bd04c46e 100644 --- a/polymer/eduke32/source/sbar.c +++ b/polymer/eduke32/source/sbar.c @@ -24,6 +24,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "compat.h" #include "sbar.h" +int32_t althud_flashing = 1; +int32_t althud_numbertile = 2930; +int32_t althud_numberpal = 0; + +#ifdef EDUKE32_TOUCH_DEVICES +int32_t althud_shadows = 0; +#else +int32_t althud_shadows = 1; +#endif + int32_t sbarsc(int32_t sc) { return scale(sc, ud.statusbarscale, 100); diff --git a/polymer/eduke32/source/sbar.h b/polymer/eduke32/source/sbar.h index dce0ab255..4ffa52269 100644 --- a/polymer/eduke32/source/sbar.h +++ b/polymer/eduke32/source/sbar.h @@ -19,6 +19,14 @@ 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 + +extern int32_t althud_flashing; +extern int32_t althud_numberpal; +extern int32_t althud_numbertile; +extern int32_t althud_shadows; + int32_t sbarsc(int32_t sc); int32_t sbarx16(int32_t x); int32_t sbary16(int32_t y); diff --git a/polymer/eduke32/source/screentext.c b/polymer/eduke32/source/screentext.c new file mode 100644 index 000000000..c7b8dd2cc --- /dev/null +++ b/polymer/eduke32/source/screentext.c @@ -0,0 +1,1218 @@ +//------------------------------------------------------------------------- +/* +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 "duke3d.h" +#include "compat.h" +#include "sbar.h" + +int32_t quotebot, quotebotgoal; +int32_t user_quote_time[MAXUSERQUOTES]; +static char user_quote[MAXUSERQUOTES][178]; +int32_t hud_glowingquotes = 1; + +#define FTAOPAQUETIME 30 + +// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required +#define ftapulseshade \ + ((hud_glowingquotes && ((getrendermode() == REND_CLASSIC && numalphatabs < 16) || ps->fta >= FTAOPAQUETIME)) ? \ + (sintable[((uint32_t)ps->fta << 7) & 2047] >> 11) : \ + (sintable[((uint32_t)FTAOPAQUETIME << 7) & 2047] >> 11)) + +int32_t textsc(int32_t sc) +{ + // prevent ridiculousness to a degree + if (xdim <= 320) return sc; + else if (xdim <= 640) return scale(sc, min(200, ud.textscale), 100); + else if (xdim <= 800) return scale(sc, min(300, ud.textscale), 100); + else if (xdim <= 1024) return scale(sc, min(350, ud.textscale), 100); + return scale(sc, ud.textscale, 100); +} + +// 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 != '\n' && text != end) + { + ++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 + case '\n': + 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 = scale(xspace, z, 65536); + yline = scale(yline, z, 65536); + xbetween = scale(xbetween, z, 65536); + ybetween = scale(ybetween, z, 65536); + // 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 ((t = *text) && text != end) + { + // 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 += scale(magnitude, unitDirection->x, 16384); + coords->y += scale(magnitude, unitDirection->y, 16384); +} + +// 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); + + // handle zooming where applicable + xspace = scale(xspace, z, 65536); + yline = scale(yline, z, 65536); + xbetween = scale(xbetween, z, 65536); + ybetween = scale(ybetween, z, 65536); + // 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, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; + + Bfree(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 ((t = *text) && text != end) + { + 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, yline, (f & TEXT_XJUSTIFY) ? 0 : xbetween, (f & TEXT_YJUSTIFY) ? 0 : ybetween, f & ~(TEXT_XJUSTIFY|TEXT_YJUSTIFY|TEXT_BACKWARDS), x1, y1, x2, y2).x; + + Bfree(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 + scale(sx, z, 65536), y + scale(sy, z, 65536), 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; +} + +// flags +// 4: small font, wrap strings? +int32_t G_PrintGameText(int32_t hack, 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) +{ + vec2_t dim; + int32_t f = TEXT_GAMETEXTNUMHACK; + int32_t xbetween = 0; + const int32_t orient = (hack & 4) || (hack & 1) ? (8|16|(o&1)|(o&32)) : (2|o); + + if (t == NULL) + return -1; + + if (!(o & ROTATESPRITE_FULL16)) + { + x <<= 16; + y <<= 16; + } + + if (hack & 4) + { + x = textsc(x); + z = textsc(z); + f |= TEXT_LINEWRAP; + } + + if (hack & 8) + { + f |= TEXT_XOFFSETZERO; + xbetween = 8; + } + + // order is important, this bit comes after the rest + if ((hack & 2) && !NAM_WW2GI) // squishtext + --xbetween; + + if (x == (160<<16)) + f |= TEXT_XCENTER; + + dim = G_ScreenText(tile, x, y, z, 0, 0, t, s, p, orient|ROTATESPRITE_FULL16, a, (5<<16), (8<<16), (xbetween<<16), 0, f, x1, y1, x2, y2); + + x += dim.x; + + if (!(o & ROTATESPRITE_FULL16)) + x >>= 16; + + return x; +} + +int32_t G_GameTextLen(int32_t x, const char *t) +{ + vec2_t dim; + + if (t == NULL) + return -1; + + dim = G_ScreenTextSize(STARTALPHANUM, x, 0, textsc(65536L), 0, t, 2, 5, 8, 0, 0, TEXT_GAMETEXTNUMHACK, 0, 0, xdim-1, ydim-1); + + x += dim.x; + + return x; +} + +// 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 = 65536L; + int32_t f = 0; + + if (t == NULL) + { + OSD_Printf("minitext: NULL text!\n"); + return 0; + } + + if (!(sb & ROTATESPRITE_FULL16)) + { + x<<=16; + y<<=16; + } + + if (!minitext_lowercase) + f |= TEXT_UPPERCASE; + + if (sb & ROTATESPRITE_MAX) + { + x = sbarx16(x); + y = minitext_yofs+sbary16(y); + z = sbarsc(z); + } + + sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; + + dim = G_ScreenText(MINIFONT, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, (4<<16), (8<<16), (1<<16), 0, f, 0, 0, xdim-1, ydim-1); + + x += dim.x; + + if (!(sb & ROTATESPRITE_FULL16)) + x >>= 16; + + return x; +} + +void G_AddUserQuote(const char *daquote) +{ + int32_t i; + + 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); + OSD_Printf("%s\n", daquote); + + user_quote_time[0] = ud.msgdisptime; + pub = NUMPAGES; +} + +// orientation flags depending on time that a quote has still to be displayed +static inline int32_t texto(int32_t t) +{ + if (t > 4) return 2+8+16; + if (t > 2) return 2+8+16+1; + return 2+8+16+1+32; +} + +static inline int32_t texta(int32_t t) +{ + if (getrendermode() == REND_CLASSIC && numalphatabs < 16) + { + if (t > 4) return 0; + if (t > 2) return 85; + return 169; + } + + t = clamp(t<<3, 0, 255); + return 255 - t; +} + +static int32_t calc_ybase(int32_t begy) +{ + int32_t k = begy; + + if (GTFLAGS(GAMETYPE_FRAGBAR) && ud.screen_size > 0 +#ifdef SPLITSCREEN_MOD_HACKS + && !g_fakeMultiMode +#endif + && (g_netServer || ud.multimode > 1)) + { + int32_t i, j = 0; + + k += 8; + for (TRAVERSE_CONNECT(i)) + if (i > j) + j = i; + + if (j >= 4 && j <= 8) k += 8; + else if (j > 8 && j <= 12) k += 16; + else if (j > 12) k += 24; + } + + return k; +} + +// this handles both multiplayer and item pickup message type text +// both are passed on to gametext +void G_PrintGameQuotes(int32_t snum) +{ + int32_t i, j, k; + + 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. + + k = calc_ybase(1); + + if (ps->fta > 1 && !reserved_quote) + { + k += min(7, ps->fta); + } + + j = scale(k, ydim, 200); + + for (i=MAXUSERQUOTES-1; i>=0; i--) + { + int32_t sh, l; + + if (user_quote_time[i] <= 0) + continue; + + k = user_quote_time[i]; + + sh = hud_glowingquotes ? (sintable[((totalclock+(i<<2))<<5)&2047]>>11) : 0; + + mpgametext(j, user_quote[i], sh, texto(k)); + j += textsc(k > 4 ? 8 : (k<<1)); + + l = G_GameTextLen(USERQUOTE_LEFTOFFSET, OSD_StripColors(tempbuf, user_quote[i])); + while (l > (ud.config.ScreenWidth - USERQUOTE_RIGHTOFFSET)) + { + l -= (ud.config.ScreenWidth-USERQUOTE_RIGHTOFFSET); + j += textsc(k > 4 ? 8 : (k<<1)); + } + } + + if (klabs(quotebotgoal-quotebot) <= 16 && ud.screen_size <= 8) + quotebot += ksgn(quotebotgoal-quotebot); + else + quotebot = quotebotgoal; + + if (ps->fta <= 1) + return; + + if (EDUKE32_PREDICT_FALSE(ScriptQuotes[ps->ftq] == NULL)) + { + OSD_Printf(OSD_ERROR "%s %d null quote %d\n", __FILE__, __LINE__, ps->ftq); + return; + } + + k = calc_ybase(0); + + if (k == 0) + { + if (reserved_quote) + { +#ifdef SPLITSCREEN_MOD_HACKS + if (!g_fakeMultiMode) + k = 140; // quotebot-8-4; + else + k = 50; +#else + k = 140; +#endif + } + else + { + if (ud.althud == 2) + k = 32; + else +#ifdef GEKKO + k = 16; +#elif defined EDUKE32_TOUCH_DEVICES + k = 24; +#else + k = 1; +#endif + } + } + + int32_t pal = 0; + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode) + { + pal = g_player[snum].pcolor; + + if (snum == 1) + { + const int32_t sidebyside = (ud.screen_size != 0); + + // NOTE: setting gametext's x -= 80 doesn't do the expected thing. + // Needs looking into. + if (sidebyside) + k += 9; + else + k += 101; + } + } +#endif + + gametextpalbits(160, k, ScriptQuotes[ps->ftq], ftapulseshade, pal, 2 + 8 + 16, texta(ps->fta)); +} + +void P_DoQuote(int32_t q, DukePlayer_t *p) +{ + int32_t cq = 0; + + if (ud.fta_on == 0 || q < 0 || !(p->gm & MODE_GAME)) + return; + + if (q & MAXQUOTES) + { + cq = 1; + q &= ~MAXQUOTES; + } + + if (EDUKE32_PREDICT_FALSE(ScriptQuotes[q] == NULL)) + { + OSD_Printf(OSD_ERROR "%s %d null quote %d\n", __FILE__, __LINE__, q); + return; + } + + if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + p->fta = 100; + + if (p->ftq != q) + { + if (p == g_player[screenpeek].ps + && Bstrcmp(ScriptQuotes[q], "")) // avoid printing blank quotes + { + if (cq) OSD_Printf(OSDTEXT_BLUE "%s\n", ScriptQuotes[q]); + else OSD_Printf("%s\n", ScriptQuotes[q]); + } + + p->ftq = q; + } + pub = NUMPAGES; + pus = NUMPAGES; +} diff --git a/polymer/eduke32/source/screentext.h b/polymer/eduke32/source/screentext.h new file mode 100644 index 000000000..2361a32be --- /dev/null +++ b/polymer/eduke32/source/screentext.h @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------- +/* +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 + +#define MAXUSERQUOTES 6 + +extern int32_t quotebot, quotebotgoal; +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, +}; + +extern int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb); +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,s,p,t) menutext_(x,y,s,p,OSD_StripColors(menutextbuf,t),10+16) +#define gametext(x,y,t,s,dabits) G_PrintGameText(0,STARTALPHANUM, x,y,t,s,0,dabits,0, 0, xdim-1, ydim-1, 65536, 0) +#define gametextscaled(x,y,t,s,dabits) G_PrintGameText(1,STARTALPHANUM, x,y,t,s,0,dabits,0, 0, xdim-1, ydim-1, 65536, 0) +#define gametextpal(x,y,t,s,p) G_PrintGameText(0,STARTALPHANUM, x,y,t,s,p,26,0, 0, xdim-1, ydim-1, 65536, 0) +#define gametextpalbits(x,y,t,s,p,dabits,a) G_PrintGameText(0,STARTALPHANUM, x,y,t,s,p,dabits,0, 0, xdim-1, ydim-1, 65536, a) +#define mpgametext(y, t, s, dabits) G_PrintGameText(4,STARTALPHANUM, 5,y,t,s,0,dabits,0, 0, xdim-1, ydim-1, 65536, 0); + +extern int32_t G_GameTextLen(int32_t x, const char *t); +extern int32_t G_PrintGameText(int32_t hack, 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, const int32_t iter); +extern int32_t G_GetStringNumLines(const char *text, const char *end, const int32_t iter); +extern char* G_GetSubString(const char *text, const char *end, const int32_t iter, const int32_t length); +extern int32_t G_GetStringTile(int32_t font, char *t, int32_t f); +extern 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, const int32_t x1, const int32_t y1, const int32_t x2, const int32_t y2); +extern void G_AddCoordsFromRotation(vec2_t *coords, const vec2_t *unitDirection, const int32_t magnitude); +extern 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, int32_t x1, int32_t y1, int32_t x2, int32_t y2); +extern 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, int32_t x1, int32_t y1, int32_t x2, int32_t y2);