From a1e4479f5d4e15c9957ddd92b56582c8a2a1fad7 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 05:02:48 -0800 Subject: [PATCH 1/9] String drawing: remove support for transparency character codes - Frees up 5-7 bit range when 8th bit is set --- src/v_video.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index e49e07a24..64c111692 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -1796,7 +1796,7 @@ void V_DrawCharacterScaled( if (notColored == true) { - if (( c & 0x80 )) + if (( c & 0xF0 ) == 0x80) { colormap = V_GetStringColormap( ( ( c & 0x7f ) << V_CHARCOLORSHIFT ) & V_CHARCOLORMASK @@ -2530,7 +2530,7 @@ void V_DrawStringScaled( cx = x; break; default: - if (( c & 0x80 )) + if (( c & 0xF0 ) == 0x80) { if (notcolored) { @@ -2662,7 +2662,7 @@ fixed_t V_StringScaledWidth( cx = 0; break; default: - if (( c & 0x80 )) + if (( c & 0xF0 ) == 0x80) continue; if (uppercase) @@ -2794,7 +2794,7 @@ char * V_ScaledWordWrap( startwriter = 0; break; default: - if (( c & 0x80 )) + if (( c & 0xF0 ) == 0x80) ; else { From 0d07b838968ae1e332ede29bee38a5184d1db1d4 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 05:12:12 -0800 Subject: [PATCH 2/9] String drawing: fix width calculation not accounting for string dance character code --- src/v_video.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 64c111692..56af02f29 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -2662,7 +2662,7 @@ fixed_t V_StringScaledWidth( cx = 0; break; default: - if (( c & 0xF0 ) == 0x80) + if (( c & 0xF0 ) == 0x80 || c == V_STRINGDANCE) continue; if (uppercase) @@ -2794,7 +2794,7 @@ char * V_ScaledWordWrap( startwriter = 0; break; default: - if (( c & 0xF0 ) == 0x80) + if (( c & 0xF0 ) == 0x80 || c == V_STRINGDANCE) ; else { From 0e4222ae99ad45f7a4b3f96b4f1c096363009ef3 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 05:13:06 -0800 Subject: [PATCH 3/9] String drawing: add support for button character codes - Bits 5 and 6 define the button state - 0xB0 - unpressed (neutral state) - 0xA0 - animating between pressed and unpressed - 0X90 - pressed down - Bits 1 - 4 define the button type - 0x00 - up - 0x01 - down - 0x02 - right - 0x03 - left - 0x07 - R shoulder - 0x08 - L shoulder - 0x09 - start - 0x0A - A - 0x0B - B - 0x0C - C - 0x0D - X - 0x0E - Y - 0x0F - Z - Button offsets and dimensions tweaked to my own taste --- src/v_video.cpp | 118 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/src/v_video.cpp b/src/v_video.cpp index 56af02f29..0e0e4477a 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -14,6 +14,7 @@ /// Functions to blit a block to the screen. #include +#include #include @@ -45,6 +46,7 @@ #include "k_hud.h" #include "k_boss.h" #include "i_time.h" +#include "v_draw.hpp" using namespace srb2; @@ -2413,6 +2415,41 @@ static void V_GetFontSpecification(int fontno, INT32 flags, fontspec_t *result) } } +static UINT8 V_GetButtonCodeWidth(UINT8 c) +{ + UINT8 x = 0; + + switch (c & 0x0F) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + // arrows + x = 12; + break; + + case 0x07: + case 0x08: + case 0x09: + // shoulders, start + x = 14; + break; + + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + // faces + x = 10; + break; + } + + return x + 2; +} + void V_DrawStringScaled( fixed_t x, fixed_t y, @@ -2427,6 +2464,7 @@ void V_DrawStringScaled( INT32 hchw;/* half-width for centering */ INT32 dupx; + INT32 dupy; fixed_t right; fixed_t bot; @@ -2491,18 +2529,20 @@ void V_DrawStringScaled( if (( flags & V_NOSCALESTART )) { dupx = vid.dupx; + dupy = vid.dupy; hchw *= dupx; fontspec.chw *= dupx; fontspec.spacew *= dupx; - fontspec.lfh *= vid.dupy; + fontspec.lfh *= dupy; right = vid.width; } else { dupx = 1; + dupy = 1; right = ( vid.width / vid.dupx ); if (!( flags & V_SNAPTOLEFT )) @@ -2572,6 +2612,68 @@ void V_DrawStringScaled( cyoff = V_DanceYOffset(dancecounter) * FRACUNIT; } + if (( c & 0xB0 ) & 0x80) // button prompts + { + using srb2::Draw; + + struct BtConf + { + UINT8 x, y; + Draw::Button type; + }; + + auto bt_inst = [c]() -> std::optional + { + switch (c & 0x0F) + { + case 0x00: return {{0, 3, Draw::Button::up}}; + case 0x01: return {{0, 3, Draw::Button::down}}; + case 0x02: return {{0, 3, Draw::Button::right}}; + case 0x03: return {{0, 3, Draw::Button::left}}; + + case 0x07: return {{0, 1, Draw::Button::r}}; + case 0x08: return {{0, 1, Draw::Button::l}}; + + case 0x09: return {{0, 1, Draw::Button::start}}; + + case 0x0A: return {{2, 1, Draw::Button::a}}; + case 0x0B: return {{2, 1, Draw::Button::b}}; + case 0x0C: return {{2, 1, Draw::Button::c}}; + + case 0x0D: return {{2, 1, Draw::Button::x}}; + case 0x0E: return {{2, 1, Draw::Button::y}}; + case 0x0F: return {{2, 1, Draw::Button::z}}; + + default: return {}; + } + }(); + + if (bt_inst) + { + auto bt_translate_press = [c]() -> std::optional + { + switch (c & 0xB0) + { + default: + case 0x90: return true; + case 0xA0: return {}; + case 0xB0: return false; + } + }; + + Draw( + FixedToFloat(cx) - (bt_inst->x * dupx), + FixedToFloat(cy + cyoff) - (bt_inst->y * dupy)) + .flags(flags) + .small_button(bt_inst->type, bt_translate_press()); + } + + cw = V_GetButtonCodeWidth(c) * dupx; + cx += cw * scale; + + break; + } + c -= font->start; if (V_CharacterValid(font, c) == true) { @@ -2665,6 +2767,14 @@ fixed_t V_StringScaledWidth( if (( c & 0xF0 ) == 0x80 || c == V_STRINGDANCE) continue; + if (( c & 0xB0 ) & 0x80) + { + cw = V_GetButtonCodeWidth(c) * dupx; + cx += cw * scale; + right = cx; + break; + } + if (uppercase) { c = toupper(c); @@ -2796,6 +2906,12 @@ char * V_ScaledWordWrap( default: if (( c & 0xF0 ) == 0x80 || c == V_STRINGDANCE) ; + else if (( c & 0xB0 ) & 0x80) // button prompts + { + cw = V_GetButtonCodeWidth(c) * dupx; + cx += cw * scale; + right = cx; + } else { if (uppercase) From 1d1d1d8a273f14d7a3b59c5f0b37746a7c2ce3ed Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 05:20:17 -0800 Subject: [PATCH 4/9] srb2::Draw: add missing small_button method --- src/v_draw.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v_draw.hpp b/src/v_draw.hpp index f283b25cd..5e4c93ae9 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -245,6 +245,7 @@ public: VOID_METHOD(thumbnail); VOID_METHOD(fill); VOID_METHOD(button); + VOID_METHOD(small_button); #undef VOID_METHOD From 0d765d9fd1421103ce752856c4a51e2c7e7425e7 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 06:18:32 -0800 Subject: [PATCH 5/9] srb2::Draw: TextElement enhancements - Add default constructor - Add text method with no arguments: returns TextElement that inherits font and flags from drawer --- src/v_draw.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/v_draw.hpp b/src/v_draw.hpp index 5e4c93ae9..a3c0bf682 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -75,6 +75,8 @@ public: class TextElement { public: + explicit TextElement() {} + explicit TextElement(std::string string) : string_(string) {} template @@ -157,6 +159,8 @@ public: template void text(fmt::format_string format, Args&&... args) const { text(fmt::format(format, args...)); } + TextElement text() const { return TextElement().font(font_).flags(flags_); } + void patch(patch_t* patch) const; void patch(const char* name) const; @@ -238,7 +242,7 @@ public: #define VOID_METHOD(Name) \ template \ - void Name (Args&&... args) const { return chain_.Name(std::forward(args)...); } + auto Name (Args&&... args) const { return chain_.Name(std::forward(args)...); } VOID_METHOD(text); VOID_METHOD(patch); From bfa6e4f401a931acb270cee52a98d9bfa7feab59 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 06:21:13 -0800 Subject: [PATCH 6/9] srb2::Draw::TextElement: add parse method - Parse and translate special characters - Currently supported: - Button codes - - - - - - - - - - - - - - All button codes can be suffixed with '_pressed' or '_animated' - E.g. or --- src/v_draw.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/v_draw.hpp | 9 ++++++ 2 files changed, 84 insertions(+) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 0f869e653..cfdd26773 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -7,6 +7,8 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- +#include + #include "doomdef.h" // skincolornum_t #include "doomtype.h" #include "hu_stuff.h" @@ -27,6 +29,79 @@ int Draw::TextElement::width() const return font_ ? font_width(*font_, default_font_flags(*font_) | flags_.value_or(0), string_.c_str()) / FRACUNIT : 0; } +Draw::TextElement& Draw::TextElement::parse(std::string_view raw) +{ + static const std::unordered_map translation = { +#define BUTTON(str, lower_bits) \ + {str, 0xB0 | lower_bits},\ + {str "_animated", 0xA0 | lower_bits},\ + {str "_pressed", 0x90 | lower_bits} + + BUTTON("up", 0x00), + BUTTON("down", 0x01), + BUTTON("right", 0x02), + BUTTON("left", 0x03), + + BUTTON("r", 0x07), + BUTTON("l", 0x08), + BUTTON("start", 0x09), + + BUTTON("a", 0x0A), + BUTTON("b", 0x0B), + BUTTON("c", 0x0C), + + BUTTON("x", 0x0D), + BUTTON("y", 0x0E), + BUTTON("z", 0x0F), + +#undef BUTTON + }; + + string_.clear(); + string_.reserve(raw.size()); + + using std::size_t; + using std::string_view; + + for (;;) + { + size_t p = raw.find('<'); + + // Copy characters until the start tag + string_.append(raw.substr(0, p)); + + if (p == raw.npos) + { + break; // end of string + } + + raw.remove_prefix(p); + + // Find end tag + p = raw.find('>'); + + if (p == raw.npos) + { + break; // no end tag + } + + string_view code = raw.substr(1, p - 1); + + if (auto it = translation.find(code); it != translation.end()) + { + string_.push_back(it->second); // replace with character code + } + else + { + string_.append(raw.substr(0, p + 1)); // code not found, leave text verbatim + } + + raw.remove_prefix(p + 1); // past end of tag + } + + return *this; +} + void Chain::patch(patch_t* patch) const { const auto _ = Clipper(*this); diff --git a/src/v_draw.hpp b/src/v_draw.hpp index a3c0bf682..c21c3356b 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -11,6 +11,7 @@ #define __V_DRAW_HPP__ #include +#include #include #include @@ -97,6 +98,14 @@ public: return *this; } + TextElement& parse(std::string_view string); + + template + TextElement& parse(fmt::format_string format, Args&&... args) + { + return parse(fmt::format(format, args...)); + } + TextElement& font(Font font) { font_ = font; From cef3b6d8411a512ff7d439715fc44bf5d372d17c Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 06:31:56 -0800 Subject: [PATCH 7/9] srb2::Dialogue::NewText: free word-wrapped string --- src/k_dialogue.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/k_dialogue.cpp b/src/k_dialogue.cpp index d3fbe82dd..538e6d7d8 100644 --- a/src/k_dialogue.cpp +++ b/src/k_dialogue.cpp @@ -218,18 +218,20 @@ void Dialogue::SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfx typewriter.voiceSfx = voice; } -void Dialogue::NewText(std::string newText) +void Dialogue::NewText(std::string rawText) { Init(); - newText = V_ScaledWordWrap( + char* newText = V_ScaledWordWrap( 290 << FRACBITS, FRACUNIT, FRACUNIT, FRACUNIT, 0, HU_FONT, - newText.c_str() + rawText.c_str() ); typewriter.NewText(newText); + + Z_Free(newText); } bool Dialogue::Active(void) From ae04a9be2747509c33f0f3e2770a5493e0af47f3 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 06:34:48 -0800 Subject: [PATCH 8/9] srb2::Dialogue::NewText: use string parsing --- src/k_dialogue.cpp | 4 ++-- src/k_dialogue.hpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/k_dialogue.cpp b/src/k_dialogue.cpp index 538e6d7d8..f489088cc 100644 --- a/src/k_dialogue.cpp +++ b/src/k_dialogue.cpp @@ -218,7 +218,7 @@ void Dialogue::SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfx typewriter.voiceSfx = voice; } -void Dialogue::NewText(std::string rawText) +void Dialogue::NewText(std::string_view rawText) { Init(); @@ -226,7 +226,7 @@ void Dialogue::NewText(std::string rawText) 290 << FRACBITS, FRACUNIT, FRACUNIT, FRACUNIT, 0, HU_FONT, - rawText.c_str() + srb2::Draw::TextElement().parse(rawText).string().c_str() // parse special characters ); typewriter.NewText(newText); diff --git a/src/k_dialogue.hpp b/src/k_dialogue.hpp index bdea25626..eda14d67d 100644 --- a/src/k_dialogue.hpp +++ b/src/k_dialogue.hpp @@ -15,6 +15,7 @@ #define __K_DIALOGUE_HPP__ #include +#include #include "doomdef.h" #include "doomtype.h" @@ -34,7 +35,7 @@ public: void SetSpeaker(std::string skinName, int portraitID); void SetSpeaker(std::string name, patch_t *patch, UINT8 *colormap, sfxenum_t voice); - void NewText(std::string newText); + void NewText(std::string_view newText); bool Active(void); bool TextDone(void); From 3030f7c65bb3cc1cfe4ba336b623a094f2e735c2 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 16 Jan 2024 20:06:45 -0800 Subject: [PATCH 9/9] srb2::Draw::TextElement: add color codes to parsing - - - - - - - - - - - - - - - - --- src/v_draw.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/v_draw.cpp b/src/v_draw.cpp index cfdd26773..edff06380 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -55,6 +55,23 @@ Draw::TextElement& Draw::TextElement::parse(std::string_view raw) BUTTON("z", 0x0F), #undef BUTTON + + {"white", 0x80}, + {"purple", 0x81}, + {"yellow", 0x82}, + {"green", 0x83}, + {"blue", 0x84}, + {"red", 0x85}, + {"gray", 0x86}, + {"orange", 0x87}, + {"sky", 0x88}, + {"lavender", 0x89}, + {"gold", 0x8A}, + {"aqua", 0x8B}, + {"magenta", 0x8C}, + {"pink", 0x8D}, + {"brown", 0x8E}, + {"tan", 0x8F}, }; string_.clear();