From a2b94b680c60498d06d7174c8c6098ea79fffb70 Mon Sep 17 00:00:00 2001 From: korenkonder Date: Sun, 2 Jun 2024 16:05:38 +0300 Subject: [PATCH] Added more funcs to `PrintWork` --- src/DivaGL/color.cpp | 16 ++ src/DivaGL/color.hpp | 38 +++- src/DivaGL/print_work.cpp | 466 ++++++++++++++++++++++++++++++++++++-- src/DivaGL/print_work.hpp | 98 +++++++- src/DivaGL/sprite.cpp | 230 ++++++++++++++++++- src/DivaGL/sprite.hpp | 79 ++++++- 6 files changed, 895 insertions(+), 32 deletions(-) diff --git a/src/DivaGL/color.cpp b/src/DivaGL/color.cpp index c36948a..84c7317 100644 --- a/src/DivaGL/color.cpp +++ b/src/DivaGL/color.cpp @@ -4,3 +4,19 @@ */ #include "color.hpp" + +const color4u8 color_black = 0xFF000000; +const color4u8 color_grey = 0xFF7F7F7F; +const color4u8 color_white = 0xFFFFFFFF; +const color4u8 color_red = 0xFF0000FF; +const color4u8 color_green = 0xFF00FF00; +const color4u8 color_blue = 0xFFFF0000; +const color4u8 color_cyan = 0xFFFFFF00; +const color4u8 color_magenta = 0xFFFF00FF; +const color4u8 color_yellow = 0xFF00FFFF; +const color4u8 color_dark_red = 0xFF00007F; +const color4u8 color_dark_green = 0xFF007F00; +const color4u8 color_dark_blue = 0xFF7F0000; +const color4u8 color_dark_cyan = 0xFF7F7F00; +const color4u8 color_dark_magenta = 0xFF7F007F; +const color4u8 color_dark_yellow = 0xFF007F7F; diff --git a/src/DivaGL/color.hpp b/src/DivaGL/color.hpp index 8d8bb19..68b1817 100644 --- a/src/DivaGL/color.hpp +++ b/src/DivaGL/color.hpp @@ -29,7 +29,7 @@ struct color4u8 { a = (uint8_t)((value >> 24) & 0xFF); } - inline color4u8(vec4 value) { + inline color4u8(const vec4& value) { vec4i _value = vec4i::store_xmm(_mm_cvtps_epi32(vec4::load_xmm(vec4::clamp(value, 0.0f, 1.0f) * 255.0f))); r = (uint8_t)_value.x; g = (uint8_t)_value.y; @@ -40,6 +40,8 @@ struct color4u8 { inline operator vec4() const { return vec4::store_xmm(_mm_cvtepi32_ps(vec4i::load_xmm(vec4i(r, g, b, a)))) * (1.0f / 255.0f); } + + inline color4u8(const struct color4u8_bgra& value); }; struct color4u8_bgra { @@ -63,7 +65,7 @@ struct color4u8_bgra { a = (uint8_t)((value >> 24) & 0xFF); } - inline color4u8_bgra(vec4 value) { + inline color4u8_bgra(const vec4& value) { vec4i _value = vec4i::store_xmm(_mm_cvtps_epi32(vec4::load_xmm(vec4::clamp(value, 0.0f, 1.0f) * 255.0f))); r = (uint8_t)_value.x; g = (uint8_t)_value.y; @@ -74,4 +76,36 @@ struct color4u8_bgra { inline operator vec4() const { return vec4::store_xmm(_mm_cvtepi32_ps(vec4i::load_xmm(vec4i(r, g, b, a)))) * (1.0f / 255.0f); } + + color4u8_bgra(const struct color4u8& value); }; + +inline color4u8::color4u8(const color4u8_bgra& value) { + r = value.r; + g = value.g; + b = value.b; + a = value.a; +} + +inline color4u8_bgra::color4u8_bgra(const color4u8& value) { + r = value.r; + g = value.g; + b = value.b; + a = value.a; +} + +extern const color4u8 color_black; +extern const color4u8 color_grey; +extern const color4u8 color_white; +extern const color4u8 color_red; +extern const color4u8 color_green; +extern const color4u8 color_blue; +extern const color4u8 color_cyan; +extern const color4u8 color_magenta; +extern const color4u8 color_yellow; +extern const color4u8 color_dark_red; +extern const color4u8 color_dark_green; +extern const color4u8 color_dark_blue; +extern const color4u8 color_dark_cyan; +extern const color4u8 color_dark_magenta; +extern const color4u8 color_dark_yellow; diff --git a/src/DivaGL/print_work.cpp b/src/DivaGL/print_work.cpp index b0e5c99..ed0c6c6 100644 --- a/src/DivaGL/print_work.cpp +++ b/src/DivaGL/print_work.cpp @@ -4,6 +4,19 @@ */ #include "print_work.hpp" +#include "shader_ft.hpp" + +static const font_character font_character_null = {}; + +const font_character* font::get_character(wchar_t c) const { + if (c >= 0 && c < characters.size()) + return &characters[c]; + return &font_character_null; +} + +font_char::font_char() : glyph_offset(), glyph_width(), field_18() { + +} font_info::font_info() : font_ptr(), type() { font_handler_index = -1; @@ -19,6 +32,30 @@ font_info::font_info(int32_t font_handler_index) : font_ptr(), type() { font_info__font_info(this, font_handler_index); } +font_char* font_info::get_char_data(wchar_t c, font_char* font_c) const { + const font_character* fc = font_ptr->get_character(c); + if (!fc->init) + return 0; + + vec2 glyph_size = font_glyph; + if (fc->halfwidth) + glyph_size.x *= 0.5f; + + float_t glyph_offset = 0.0f; + float_t glyph_width = glyph_size.x; + if (type == 2) { + glyph_offset = (float_t)fc->glyph_offset; + glyph_width = (float_t)fc->glyph_width; + } + + font_c->tex.pos = vec2((float_t)fc->tex_column, (float_t)fc->tex_row) * font_glyph_box; + font_c->tex.size = glyph_size; + font_c->glyph_offset = glyph_offset; + font_c->glyph_width = glyph_width; + font_c->field_18 = 0; + return font_c; +} + void font_info::set_glyph_size(float_t glyph_width, float_t glyph_height) { glyph.x = glyph_width; glyph.y = glyph_height; @@ -26,6 +63,70 @@ void font_info::set_glyph_size(float_t glyph_width, float_t glyph_height) { glyph_ratio.y = glyph_height / font_glyph.y; } +bool font_info::sub_140199170() const { + return font_glyph != glyph && font_glyph == font_glyph_box; +} + +sprite_text_mesh::sprite_text_mesh() { + sprite_id = -1; +} + +sprite_text_mesh::~sprite_text_mesh() { + +} + +spr::SpriteVertex* sprite_text_mesh::add_char() { + size_t size = vertices.size(); + vertices.resize(size + 4); + return &vertices.data()[size]; +} + +void sprite_text_mesh::add_set_char(app::text_flags flags, rectangle pos, rectangle uv, color4u8 color) { + sprite_text_mesh::set_char(add_char(), flags, pos, uv, color); +} + +void sprite_text_mesh::apply_scale_offset(vec2 scale, vec2 offset) { + for (spr::SpriteVertex& i : vertices) + *(vec2*)&i.pos.x = *(vec2*)&i.pos.x * scale + offset; +} + +void sprite_text_mesh::set_char(spr::SpriteVertex* vtx, app::text_flags flags, rectangle pos, rectangle uv, color4u8 color) { + vec2 uv_size = uv.size; + vec2 uv_pos = uv.pos; + if (flags & app::TEXT_FLAG_11) { + uv_pos += 0.5f; + uv_size += -1.0f; + } + + vtx[0].pos.x = pos.pos.x; + vtx[0].pos.y = pos.pos.y; + vtx[0].pos.z = 0.0f; + vtx[0].uv.x = uv_pos.x; + vtx[0].uv.y = uv_pos.y; + vtx[0].color = color; + + vtx[1].pos.x = pos.pos.x + pos.size.x; + vtx[1].pos.y = pos.pos.y; + vtx[1].pos.z = 0.0; + vtx[1].uv.x = uv_pos.x + uv_size.x; + vtx[1].uv.y = uv_pos.y; + vtx[1].color = color; + + vtx[2].pos.x = pos.pos.x + pos.size.x; + vtx[2].pos.y = pos.pos.y + pos.size.y; + vtx[2].pos.z = 0.0f; + vtx[2].uv.x = uv_pos.x + uv_size.x; + vtx[2].uv.y = uv_pos.y + uv_size.y; + vtx[2].color = color; + + vtx[3].pos.x = pos.pos.x; + vtx[3].pos.y = pos.pos.y + pos.size.y; + vtx[3].pos.z = 0.0f; + vtx[3].uv.x = uv_pos.x; + vtx[3].uv.y = uv_pos.y + uv_size.y; + vtx[3].color = color; +} + PrintWork::PrintWork() : clip(), layer(), field_28(), line_length() { color = 0xFFFFFFFF; fill_color = 0xFF808080; @@ -35,56 +136,377 @@ PrintWork::PrintWork() : clip(), layer(), field_28(), line_length() { empty_char = L'\x25A1'; } +void PrintWork::DrawLine(vec2 pos[2]) { + spr::put_sprite_line(pos[0], pos[1], resolution_mode, prio, color, layer); +} + +void PrintWork::DrawPolyLine(vec2* points, size_t count) { + spr::put_sprite_line_list(points, count, resolution_mode, prio, color, layer); +} + +void PrintWork::DrawRectangle(rectangle rect) { + spr::put_sprite_multi(rect, resolution_mode, prio, color, layer); +} + +void PrintWork::DrawTextMesh(app::text_flags flags, sprite_text_mesh& mesh) { + if (!mesh.vertices.size()) + return; + + spr::SprArgs args; + args.blend = (field_28 >> 3) & 0x02; + args.resolution_mode_screen = resolution_mode; + args.resolution_mode_sprite = args.resolution_mode_screen; + args.prio = prio; + args.color = color; + args.layer = layer; + + if (field_28 & 0x02) { + for (spr::SpriteVertex& i : mesh.vertices) { + i.color.r = 0x40; + i.color.g = 0x40; + i.color.b = 0x40; + i.pos += 2.0f; + } + args.SetVertexArray(mesh.vertices.data(), mesh.vertices.size()); + args.id.index = mesh.sprite_id; + spr::put_sprite(&args); + + for (spr::SpriteVertex& i : mesh.vertices) { + i.color.r = color.r; + i.color.g = color.g; + i.color.b = color.b; + i.pos.x -= 2.0f; + i.pos.y -= 2.0f; + } + } + + args.SetVertexArray(mesh.vertices.data(), mesh.vertices.size()); + if (flags & app::TEXT_FLAG_FONT) + args.shader = SHADER_FT_FONT; + args.id.index = mesh.sprite_id; + spr::put_sprite(&args); +} + +void PrintWork::FillRectangle(rectangle rect) { + if (clip) { + float_t clip_max_pos_x; + PrintWork::ClampPosToClipBox(rect.pos.x, rect.pos.x + rect.size.x, + clip_data.pos.x, clip_data.pos.x + clip_data.size.x, rect.pos.x, clip_max_pos_x); + rect.size.x = clip_max_pos_x - rect.pos.x; + + float_t clip_max_pos_y; + PrintWork::ClampPosToClipBox(rect.pos.y, rect.pos.y + rect.size.y, + clip_data.pos.y, clip_data.pos.y + clip_data.size.y, rect.pos.y, clip_max_pos_y); + rect.size.y = clip_max_pos_y - rect.pos.y; + } + + spr::put_sprite_rect(rect, resolution_mode, prio, fill_color, layer); +} + +font_char PrintWork::GetCharData(wchar_t c) { + font_char font_c = {}; + if (!font->get_char_data(c, &font_c)) + font->get_char_data(empty_char, &font_c); + return font_c; +} + +rectangle PrintWork::GetClipBox(app::text_flags flags, vec2 glyph_size, vec2 glyph_ratio) { + glyph_ratio = 1.0f / glyph_ratio; + rectangle clip_box; + clip_box.pos = (clip_data.pos - text_current_loc) * glyph_ratio; + clip_box.size = clip_data.size * glyph_ratio; + + if (flags & app::TEXT_FLAG_ALIGN_FLAG_RIGHT) + clip_box.pos.x += glyph_size.x; + else if (flags & app::TEXT_FLAG_ALIGN_FLAG_H_CENTER) + clip_box.pos.x = (glyph_size.x - clip_data.size.x) * 0.5f * glyph_ratio.x; + else if (flags & app::TEXT_FLAG_ALIGN_FLAG_LOCATE_H_CENTER) + clip_box.pos.x += glyph_size.x * 0.5f; + + if (flags & app::TEXT_FLAG_ALIGN_FLAG_V_CENTER) + clip_box.pos.y = (glyph_size.y - clip_data.size.y) * 0.5f * glyph_ratio.y; + else if (flags & app::TEXT_FLAG_ALIGN_FLAG_LOCATE_V_CENTER) + clip_box.pos.y += glyph_size.y * 0.5f; + return clip_box; +} + +std::vector PrintWork::GetStringData(const wchar_t* str_begin, const wchar_t* str_end) { + std::vector vec(str_end - str_begin); + font_char* fc = vec.data(); + for (const wchar_t* i = str_begin; i != str_end; i++) + *fc++ = PrintWork::GetCharData(*i); + return vec; +} + +vec2 PrintWork::GetStringSize(const wchar_t* str_begin, const wchar_t* str_end) { + std::vector vec = GetStringData(str_begin, str_end); + float_t spacing = font->spacing.x / font->glyph_ratio.x; + vec2 size; + for (font_char& i : vec) { + if (&i - vec.data()) + size.x += spacing; + size.x += i.glyph_width; + } + + size.x *= font->glyph_ratio.x; + size.y = font->glyph.y; + return size; +} + +vec2 PrintWork::GetTextSize(const wchar_t* str, size_t length) { + vec2* (FASTCALL * PrintWork__GetTextSize)(PrintWork * _this, vec2 * size, const prj::wstring_range& str) + = (vec2 * (FASTCALL*)(PrintWork * _this, vec2 * size, const prj::wstring_range & str))0x000000014019A0A0; + + vec2 size; + return *PrintWork__GetTextSize(this, &size, prj::wstring_range(str, length)); +} + +vec2 PrintWork::GetTextSize(const wchar_t* str_begin, const wchar_t* str_end) { + return GetTextSize(str_begin, str_end - str_begin); +} + +vec2 PrintWork::GetTextSize(const char* str, size_t length) { + return GetTextSize(str, str + length); +} + +vec2 PrintWork::GetTextSize(const char* str_begin, const char* str_end) { + wchar_t* wstr = utf8_to_utf16(str_begin, str_end - str_begin); + vec2 size = GetTextSize(wstr, wstr + utf16_length(wstr)); + free_def(wstr); + return size; +} + +vec2 PrintWork::GetTextSize(const std::wstring& str) { + return GetTextSize(str.c_str(), str.c_str() + str.size()); +} + +void PrintWork::NewLine() { + text_current_loc.x = line_origin_loc.x; + float_t loc_y = text_current_loc.y + font->spacing.y + font->glyph.y; + text_current_loc.y = loc_y; + line_origin_loc.y = loc_y; +} + +void PrintWork::PrintText(app::text_flags flags, const char* str) { + wchar_t* wstr = utf8_to_utf16(str); + PrintText(flags, wstr, wstr + utf16_length(wstr)); + free_def(wstr); +} + +void PrintWork::PrintText(app::text_flags flags, const char* str, size_t length) { + wchar_t* wstr = utf8_to_utf16(str, length); + PrintText(flags, wstr, wstr + utf16_length(wstr)); + free_def(wstr); +} + +void PrintWork::PrintText(app::text_flags flags, const wchar_t* str_begin, const wchar_t* str_end) { + void (FASTCALL * PrintWork__PrintText)(PrintWork * _this, + app::text_flags flags, const prj::wstring_range& str) + = (void (FASTCALL*)(PrintWork * _this, + app::text_flags flags, const prj::wstring_range & str))0x0000000140198380; + PrintWork__PrintText(this, flags, prj::wstring_range(str_begin, str_end)); +} + +// It was intended to be DrawText but there's WinAPI macro for that +void PrintWork::PutText(app::text_flags flags, const wchar_t* str_begin, const wchar_t* str_end) { + if (str_begin == str_end) + return; + + app::text_flags v5 = (app::text_flags)(flags + & (app::TEXT_FLAG_ALIGN_FLAG_LOCATE_V_CENTER | app::TEXT_FLAG_ALIGN_FLAG_V_CENTER + | app::TEXT_FLAG_ALIGN_FLAG_LOCATE_H_CENTER | app::TEXT_FLAG_ALIGN_FLAG_H_CENTER + | app::TEXT_FLAG_ALIGN_FLAG_RIGHT | app::TEXT_FLAG_ALIGN_FLAG_LEFT)); + app::text_flags v6 = (app::text_flags)(flags & (app::TEXT_FLAG_11 | app::TEXT_FLAG_CLIP)); + bool clip = !!(flags & app::TEXT_FLAG_CLIP); + if (clip && font->glyph.y + text_current_loc.y <= clip_data.pos.y + && clip_data.pos.y + clip_data.size.y < text_current_loc.y) + return; + + std::vector v43 = PrintWork::GetStringData(str_begin, str_end); + float_t spacing = font->spacing.x / font->glyph_ratio.x; + + vec2 glyph_ratio = font->glyph_ratio; + rectangle clip_box; + if (clip) { + float_t glyph_size_x = 0.0f; + for (font_char& i : v43) + glyph_size_x += i.glyph_width + spacing; + + vec2 glyph_size; + glyph_size.x = glyph_size_x - spacing; + glyph_size.y = font->glyph.y; + clip_box = GetClipBox(v5, glyph_size, glyph_ratio); + } + else + clip_box = {}; + + std::vector v44; + sprite_text_mesh v45; + v45.sprite_id = font->font_ptr->sprite_id; + v44.push_back(v45); + v44.back().vertices.reserve(str_end - str_begin); + + float_t glyph_x = 0.0f; + if (str_end - str_begin) { + for (size_t i = 0; i != str_end - str_begin; i++) { + font_char* fc = &v43.data()[i]; + rectangle v37; + v37.pos.x = glyph_x; + v37.pos.y = 0.0f; + v37.size.x = fc->glyph_width; + v37.size.y = fc->tex.size.y; + rectangle v42; + v42.pos.x = fc->tex.pos.x + fc->glyph_offset; + v42.pos.y = fc->tex.pos.y; + v42.size.x = fc->glyph_width; + v42.size.y = fc->tex.size.y; + if (!clip || PrintWork::sub_140197D60(clip_box, v37, v42)) + v44.data()[fc->field_18].add_set_char(v6, v37, v42, color); + glyph_x += fc->glyph_width + spacing; + } + } + else + glyph_x -= spacing; + + vec2 v35; + v35.x = glyph_x * glyph_ratio.x; + v35.y = font->glyph.y; + + vec2 v41 = PrintWork::sub_140197B80((app::text_flags)(v5 | v6), v35); + if (v5 & app::TEXT_FLAG_ALIGN_FLAG_LEFT) + text_current_loc.x += font->spacing.x + v35.x; + + for (sprite_text_mesh& i : v44) { + i.apply_scale_offset(glyph_ratio, v41); + DrawTextMesh(flags, i); + } +} + void PrintWork::SetFont(const font_info* value) { font = value; } -void PrintWork::printf(app::text_flags flags, const char* fmt, ...) { +void PrintWork::SetResolutionMode(::resolution_mode value) { + resolution_mode = value; +} + +void PrintWork::set_text_position(float_t column, float_t line) { + line_origin_loc.x = (font->spacing.x + font->glyph.x * font->font_ptr->column_scale) * column; + line_origin_loc.y = (font->spacing.y + font->glyph.y) * line; + text_current_loc = line_origin_loc; +} + +void PrintWork::printf(app::text_flags flags, + _In_z_ _Printf_format_string_ const char* const fmt, ...) { va_list args; va_start(args, fmt); vprintf(flags, fmt, args); va_end(args); } -void PrintWork::printf_align_left(const char* fmt, ...) { +void PrintWork::printf_align_left(_In_z_ _Printf_format_string_ const char* const fmt, ...) { va_list args; va_start(args, fmt); vprintf(app::TEXT_FLAG_ALIGN_FLAG_LEFT, fmt, args); va_end(args); } -void PrintWork::wprintf(app::text_flags flags, const wchar_t* fmt, ...) { +void PrintWork::wprintf(app::text_flags flags, + _In_z_ _Printf_format_string_ const wchar_t* const fmt, ...) { va_list args; va_start(args, fmt); vwprintf(flags, fmt, args); va_end(args); } -void PrintWork::wprintf_align_left(const wchar_t* fmt, ...) { +void PrintWork::wprintf_align_left(_In_z_ _Printf_format_string_ const wchar_t* const fmt, ...) { va_list args; va_start(args, fmt); vwprintf(app::TEXT_FLAG_ALIGN_FLAG_LEFT, fmt, args); va_end(args); } -void PrintWork::vprintf(app::text_flags flags, const char* fmt, va_list args) { - static void(FASTCALL * sub_1400CA8E0)(prj::string * buf, const char* fmt, va_list args) - = (void (FASTCALL*)(prj::string * buf, const char* fmt, va_list args))0x00000001400CA8E0; - static void(FASTCALL * PrintWork__PrintText)(PrintWork * _this, app::text_flags flags, const char* str, size_t length) - = (void (FASTCALL*)(PrintWork * _this, app::text_flags flags, const char* str, size_t length))0x0000000140198500; - - prj::string buf; - sub_1400CA8E0(&buf, fmt, args); - PrintWork__PrintText(this, flags, buf.c_str(), buf.size()); +void PrintWork::vprintf(app::text_flags flags, + _In_z_ _Printf_format_string_ const char* const fmt, va_list args) { + std::string buf = vsprintf_s_string(fmt, args); + PrintText(flags, buf.data(), buf.size()); } -void PrintWork::vwprintf(app::text_flags flags, const wchar_t* fmt, va_list args) { - static void(FASTCALL * sub_1400DDC30)(prj::wstring * buf, const wchar_t* fmt, va_list args) - = (void (FASTCALL*)(prj::wstring * buf, const wchar_t* fmt, va_list args))0x00000001400DDC30; - static void(FASTCALL * PrintWork__PrintText)(PrintWork * _this, app::text_flags flags, const wchar_t* str, size_t length) - = (void (FASTCALL*)(PrintWork * _this, app::text_flags flags, const wchar_t* str, size_t length))0x0000000140198380; - - prj::wstring buf; - sub_1400DDC30(&buf, fmt, args); - PrintWork__PrintText(this, flags, buf.c_str(), buf.size()); +void PrintWork::vwprintf(app::text_flags flags, + _In_z_ _Printf_format_string_ const wchar_t* const fmt, va_list args) { + std::wstring buf = vswprintf_s_string(fmt, args); + PrintText(flags, buf.data(), buf.data() + buf.size()); +} + +void PrintWork::ClampPosToClipBox(float_t pos_min, float_t pos_max, + float_t clip_box_min, float_t clip_box_max, float_t& clip_pos_min, float_t& clip_pos_max) { + float_t v8 = max_def(pos_min, clip_box_min); + float_t v10 = min_def(pos_max, clip_box_max); + + if (v8 < v10) { + clip_pos_min = v8; + clip_pos_max = v10; + } + else { + clip_pos_min = pos_min; + clip_pos_max = pos_min; + } +} + +vec2 PrintWork::sub_140197B80(app::text_flags flags, vec2 size) { + vec2 pos = text_current_loc; + if (flags & app::TEXT_FLAG_ALIGN_FLAG_RIGHT) + pos.x -= size.x; + else if (flags & app::TEXT_FLAG_ALIGN_FLAG_H_CENTER) { + if (flags & app::TEXT_FLAG_CLIP) + pos.x = clip_data.pos.x + clip_data.size.x * 0.5f; + else { + resolution_struct v10(resolution_mode); + pos.x = (float_t)v10.width * 0.5f; + } + pos.x -= size.x * 0.5f; + } + else if (flags & app::TEXT_FLAG_ALIGN_FLAG_LOCATE_H_CENTER) + pos.x -= size.x * 0.5f; + + if (flags & app::TEXT_FLAG_ALIGN_FLAG_V_CENTER) { + if (flags & app::TEXT_FLAG_CLIP) + pos.y = clip_data.pos.y + clip_data.size.y * 0.5f; + else { + resolution_struct v10(resolution_mode); + pos.y = (float_t)v10.height * 0.5f; + } + pos.y -= size.y * 0.5f; + } + else if (flags & app::TEXT_FLAG_ALIGN_FLAG_LOCATE_V_CENTER) + pos.y -= size.y * 0.5f; + return pos; +} + +int32_t PrintWork::sub_140197D60(rectangle clip_box, rectangle& pos, rectangle& uv) { + vec2 pos_pos = pos.pos; + vec2 pos_size = pos.size; + vec2 uv_pos = uv.pos; + vec2 uv_size = uv.size; + + vec2 clip_max_pos; + vec2 clip_min_pos; + PrintWork::ClampPosToClipBox(pos_pos.x, pos_pos.x + pos_size.x, + clip_box.pos.x, clip_box.pos.x + clip_box.size.x, clip_min_pos.x, clip_max_pos.x); + PrintWork::ClampPosToClipBox(pos_pos.y, pos_pos.y + pos_size.y, + clip_box.pos.y, clip_box.pos.y + clip_box.size.y, clip_min_pos.y, clip_max_pos.y); + + vec2 clip_size = clip_max_pos - clip_min_pos; + + if (clip_size.x == pos_size.x && clip_size.y == pos_size.y) + return 2; + else if (clip_size.x <= 0.0f || clip_size.y <= 0.0f) + return 0; + + vec2 uv_scale = uv_size / pos_size; + pos.pos = clip_min_pos; + pos.size = clip_size; + uv.pos = (clip_min_pos - pos_pos) * uv_scale + uv_pos; + uv.size = clip_size * uv_scale; + return 1; } diff --git a/src/DivaGL/print_work.hpp b/src/DivaGL/print_work.hpp index 892f0d0..e2c5cba 100644 --- a/src/DivaGL/print_work.hpp +++ b/src/DivaGL/print_work.hpp @@ -31,6 +31,41 @@ namespace app { }; } +struct font_char { + rectangle tex; + float_t glyph_offset; + float_t glyph_width; + uint8_t field_18; + + font_char(); +}; + +struct font_character { + bool init; + bool halfwidth; + uint8_t tex_column; + uint8_t tex_row; + uint8_t glyph_offset; + uint8_t glyph_width; +}; + +struct font { + int32_t sprite_id; + uint8_t glyph_width; + uint8_t glyph_height; + uint8_t glyph_box_width; + uint8_t glyph_box_height; + uint8_t column_scale_num; + uint8_t column_scale_denom; + int32_t map_id; + float_t column_scale; + size_t characters_count_per_row; + prj::vector characters; + bool disable_glyph_spacing; + + const font_character* get_character(wchar_t c) const; +}; + struct font_info { int32_t font_handler_index; const struct font* font_ptr; @@ -44,11 +79,30 @@ struct font_info { font_info(); font_info(int32_t font_handler_index); + font_char* get_char_data(wchar_t c, font_char* font_c) const; void set_glyph_size(float_t glyph_width, float_t glyph_height); + + bool sub_140199170() const; }; static_assert(sizeof(font_info) == 0x40, "\"font_info\" struct should have a size of 0x40"); +struct sprite_text_mesh { + int32_t sprite_id; + std::vector vertices; + + sprite_text_mesh(); + ~sprite_text_mesh(); + + spr::SpriteVertex* add_char(); + void add_set_char(app::text_flags flags, + rectangle pos, rectangle uv, color4u8 color); + void apply_scale_offset(vec2 scale, vec2 offset); + + static void set_char(spr::SpriteVertex* vtx, app::text_flags flags, + rectangle pos, rectangle uv, color4u8 color); +}; + struct PrintWork { color4u8 color; color4u8 fill_color; @@ -66,14 +120,46 @@ struct PrintWork { PrintWork(); + void DrawLine(vec2 pos[2]); + void DrawPolyLine(vec2* points, size_t count); + void DrawRectangle(rectangle rect); + void DrawTextMesh(app::text_flags flags, sprite_text_mesh& mesh); + void FillRectangle(rectangle rect); + font_char GetCharData(wchar_t c); + rectangle GetClipBox(app::text_flags flags, vec2 glyph_size, vec2 glyph_ratio); + std::vector GetStringData(const wchar_t* str_begin, const wchar_t* str_end); + vec2 GetStringSize(const wchar_t* str_begin, const wchar_t* str_end); + vec2 GetTextSize(const wchar_t* str, size_t length); + vec2 GetTextSize(const wchar_t* str_begin, const wchar_t* str_end); + vec2 GetTextSize(const char* str, size_t length); + vec2 GetTextSize(const char* str_begin, const char* str_end); + vec2 GetTextSize(const std::wstring& str); + void NewLine(); + void PrintText(app::text_flags flags, const char* str); + void PrintText(app::text_flags flags, const char* str, size_t length); + void PrintText(app::text_flags flags, const wchar_t* str_begin, const wchar_t* str_end); + void PutText(app::text_flags flags, const wchar_t* str_begin, const wchar_t* str_end); void SetFont(const font_info* value); + void SetResolutionMode(::resolution_mode value); + void set_text_position(float_t column, float_t line); - void printf(app::text_flags flags, const char* fmt, ...); - void printf_align_left(const char* fmt, ...); - void wprintf(app::text_flags flags, const wchar_t* fmt, ...); - void wprintf_align_left(const wchar_t* fmt, ...); - void vprintf(app::text_flags flags, const char* fmt, va_list args); - void vwprintf(app::text_flags flags, const wchar_t* fmt, va_list args); + void printf(app::text_flags flags, + _In_z_ _Printf_format_string_ const char* const fmt, ...); + void printf_align_left(_In_z_ _Printf_format_string_ const char* const fmt, ...); + void wprintf(app::text_flags flags, + _In_z_ _Printf_format_string_ const wchar_t* const fmt, ...); + void wprintf_align_left(_In_z_ _Printf_format_string_ const wchar_t* const fmt, ...); + void vprintf(app::text_flags flags, + _In_z_ _Printf_format_string_ const char* const fmt, va_list args); + void vwprintf(app::text_flags flags, + _In_z_ _Printf_format_string_ const wchar_t* const fmt, va_list args); + + static void ClampPosToClipBox(float_t pos_min, float_t pos_max, + float_t clip_box_min, float_t clip_box_max, float_t& clip_pos_min, float_t& clip_pos_max); + + vec2 sub_140197B80(app::text_flags flags, vec2 size); + + static int32_t sub_140197D60(rectangle clip_box, rectangle& pos, rectangle& uv); }; static_assert(sizeof(PrintWork) == 0x58, "\"PrintWork\" struct should have a size of 0x58"); diff --git a/src/DivaGL/sprite.cpp b/src/DivaGL/sprite.cpp index 470118a..5414d5a 100644 --- a/src/DivaGL/sprite.cpp +++ b/src/DivaGL/sprite.cpp @@ -120,6 +120,17 @@ bool (FASTCALL* sprite_manager_load_file)(int32_t set_id) spr::SpriteManager* sprite_manager = (spr::SpriteManager*)0x000000014CC611C0; +#if BREAK_SPRITE_VERTEX_LIMIT +size_t sprite_vertex_array_max_count = 0x2000; + +spr::SpriteVertex* sprite_vertex_array; +#else +const size_t sprite_vertex_array_max_count = 0x2000; + +spr::SpriteVertex* sprite_vertex_array = (spr::SpriteVertex*)0x000000014CC62480; +#endif +size_t& sprite_vertex_array_count = *(size_t*)0x000000014CC611B0; + static mat4 view_projection_aet; static spr::SpriteManager::RenderData* sprite_manager_render_data; @@ -134,10 +145,220 @@ static const GLenum spr_blend_param[6][4] = { }; namespace spr { - void(FASTCALL* put_rgb_cross)(mat4* mat) = (void(FASTCALL*)(mat4 * mat))0x00000001404BC8F0; + void(FASTCALL* put_cross)(const mat4* mat, color4u8 color_x, color4u8 color_y, color4u8 color_z) + = (void(FASTCALL*)(const mat4 * mat, color4u8 color_x, color4u8 color_y, color4u8 color_z))0x00000001404BC920; + void(FASTCALL* put_rgb_cross)(const mat4* mat) = (void(FASTCALL*)(const mat4 * mat))0x00000001404BC8F0; spr::SprArgs* (FASTCALL* put_sprite)(const spr::SprArgs* args) = (spr::SprArgs * (FASTCALL*)(const spr::SprArgs * args))0x0000000140640740; + SprArgs::SprArgs() : kind(), attr(), blend(), index(), layer(), + prio(), resolution_mode_screen(), resolution_mode_sprite(), texture(), + shader(), vertex_array(), num_vertex(), flags(), field_CC(), next() { + Reset(); + } + + void SprArgs::Reset() { + kind = SPR_KIND_NORMAL; + id = {}; + color = 0xFFFFFFFF; + attr = (SprAttr)0; + blend = 0; + index = -1; + layer = 0; + prio = SPR_PRIO_DEFAULT; + resolution_mode_screen = RESOLUTION_MODE_HD; + resolution_mode_sprite = RESOLUTION_MODE_HD; + center = 0.0f; + trans = 0.0f; + scale = 1.0f; + rot = 0.0f; + skew_angle = 0.0f; + mat = mat4_identity; + texture = 0; + shader = SHADER_FT_FFP; +#if BREAK_SPRITE_VERTEX_LIMIT + vertex_array = -1; +#else + vertex_array = 0; +#endif + num_vertex = 0; + flags = (SprArgs::Flags)0; + sprite_size = 0.0f; + field_CC = 0; + texture_pos = 0.0f; + texture_size = 1.0f; + next = 0; + } + + void SprArgs::SetSpriteSize(vec2 size) { + if (flags & SPRITE_SIZE) + return; + + enum_or(flags, SPRITE_SIZE); + sprite_size = size; + field_CC = 0; + } + + void SprArgs::SetTexturePosSize(float_t x, float_t y, float_t width, float_t height) { + if (flags & TEXTURE_POS_SIZE) + return; + + enum_or(flags, TEXTURE_POS_SIZE); + texture_pos.x = x; + texture_pos.y = y; + texture_size.x = width; + texture_size.y = height; + } + + void SprArgs::SetVertexArray(SpriteVertex* vertex_array, size_t num_vertex) { +#if BREAK_SPRITE_VERTEX_LIMIT + if (sprite_vertex_array_count + num_vertex >= sprite_vertex_array_max_count) { + while (sprite_vertex_array_count + num_vertex >= sprite_vertex_array_max_count) + sprite_vertex_array_max_count *= 2; + + spr::SpriteVertex* _sprite_vertex_array = new spr::SpriteVertex[sprite_vertex_array_max_count * 2]; + memmove(_sprite_vertex_array, sprite_vertex_array, sizeof(SpriteVertex) * sprite_vertex_array_count); + delete[] sprite_vertex_array; + sprite_vertex_array = _sprite_vertex_array; + } +#else + if (sprite_vertex_array_count + num_vertex >= sprite_vertex_array_max_count) + return; +#endif + + this->num_vertex = num_vertex; +#if BREAK_SPRITE_VERTEX_LIMIT + this->vertex_array = sprite_vertex_array_count; + memmove(sprite_vertex_array + this->vertex_array, vertex_array, sizeof(SpriteVertex) * num_vertex); +#else + this->vertex_array = &sprite_vertex_array[sprite_vertex_array_count]; + memmove(this->vertex_array, vertex_array, sizeof(SpriteVertex) * num_vertex); +#endif + sprite_vertex_array_count += num_vertex; + } + + void SprArgs::SetNext(SprArgs* args, SprArgs* next) { + while (args->next) + args = args->next; + args->next = next; + next->kind = SPR_KIND_LINE; + } + + vec2 proj_sprite_3d_line(vec3 vec, bool offset) { + mat4 view; + mat4_transpose(&camera_data->view, &view); + + mat4_transform_point(&view, &vec, &vec); + if (fabsf(vec.z) < 1.0e-10f) + return 0.0f; + + vec2 sc_vec = camera_data->depth * *(vec2*)&vec.x * (1.0f / vec.z); + + resolution_struct* res_wind_int = res_window_internal_get(); + sc_vec.x = (float_t)res_wind_int->width * 0.5f - sc_vec.x; + sc_vec.y = (float_t)res_wind_int->height * 0.5f + sc_vec.y; + if (offset) { + resolution_struct* res_wind = res_window_get(); + sc_vec.x = (float_t)res_wind_int->x_offset + sc_vec.x; + sc_vec.y = (float_t)(res_wind->height + - res_wind_int->y_offset - res_wind_int->height) + sc_vec.y; + } + return sc_vec; + } + + void put_sprite_3d_line(vec3 p1, vec3 p2, color4u8 color) { + vec2 sc_p1 = proj_sprite_3d_line(p1, true); + vec2 sc_p2 = proj_sprite_3d_line(p2, true); + spr::put_sprite_line(sc_p1, sc_p2, RESOLUTION_MODE_MAX, SPR_PRIO_DEBUG, color, 0); + } + + void put_sprite_line(vec2 p1, vec2 p2, resolution_mode mode, spr::SprPrio prio, color4u8 color, int32_t layer) { + spr::SprArgs args; + args.trans.x = p1.x; + args.trans.y = p1.y; + args.trans.z = 0.0f; + args.layer = layer; + args.kind = SPR_KIND_LINES; + args.resolution_mode_screen = mode; + args.resolution_mode_sprite = mode; + args.prio = prio; + args.color = color; + args.SetSpriteSize({ p2.x - p1.x, p2.y - p1.y }); + enum_or(args.attr, SPR_ATTR_MATRIX); + spr::put_sprite(&args); + } + + void put_sprite_line_list(vec2* points, size_t count, resolution_mode mode, + spr::SprPrio prio, color4u8 color, int32_t layer) { + spr::SprArgs args; + args.kind = SPR_KIND_ARROW_AB; + args.layer = layer; + args.resolution_mode_screen = mode; + args.resolution_mode_sprite = mode; + args.prio = prio; + args.color = color; + + std::vector vertex_array; + vertex_array.reserve(count); + + for (size_t i = 0; i < count; i++, points++) { + spr::SpriteVertex vert = {}; + *(vec2*)&vert.pos = *points; + vertex_array.push_back(vert); + } + + args.SetVertexArray(vertex_array.data(), vertex_array.size()); + spr::put_sprite(&args); + } + + void put_sprite_multi(rectangle rect, resolution_mode mode, spr::SprPrio prio, color4u8 color, int32_t layer) { + spr::SprArgs args; + args.trans.x = rect.pos.x; + args.trans.y = rect.pos.y; + args.trans.z = 0.0f; + args.layer = layer; + args.kind = SPR_KIND_MULTI; + args.resolution_mode_screen = mode; + args.resolution_mode_sprite = mode; + args.prio = prio; + args.color = color; + args.SetSpriteSize(rect.size); + enum_or(args.attr, SPR_ATTR_MATRIX); + spr::put_sprite(&args); + } + + void put_sprite_rect(rectangle rect, resolution_mode mode, spr::SprPrio prio, color4u8 color, int32_t layer) { + spr::SprArgs args; + args.trans.x = rect.pos.x; + args.trans.y = rect.pos.y; + args.trans.z = 0.0f; + args.layer = layer; + args.kind = SPR_KIND_RECT; + args.resolution_mode_screen = mode; + args.resolution_mode_sprite = mode; + args.prio = prio; + args.color = color; + args.SetSpriteSize(rect.size); + enum_or(args.attr, SPR_ATTR_MATRIX); + spr::put_sprite(&args); + } + + void put_sprite_triangles(SpriteVertex* vert, size_t num, resolution_mode mode, + SprPrio prio, int32_t spr_id, int32_t layer) { + spr::SprArgs args; + args.layer = layer; + args.kind = SPR_KIND_TRIANGLE; + args.resolution_mode_screen = mode; + args.resolution_mode_sprite = mode; + args.prio = prio; + args.color = vert[0].color; + if (spr_id != -1) + args.id.info = sprite_database_get_spr_by_id(spr_id)->info; + enum_or(args.attr, SPR_ATTR_MATRIX); + args.SetVertexArray(vert, num); + spr::put_sprite(&args); + } + SpriteManager::RenderData::RenderData() { glGenVertexArrays(1, &vao); gl_state_bind_vertex_array(vao, true); @@ -1195,6 +1416,13 @@ namespace spr { } } +const spr_db_spr* sprite_database_get_spr_by_id(int32_t id) { + const spr_db_spr* (FASTCALL* sprite_database_struct__get_spr_by_id) + (size_t _this, int32_t id) + = (const spr_db_spr * (FASTCALL*)(size_t _this, int32_t id))0x000000014063C800; + return sprite_database_struct__get_spr_by_id(0x000000014CC62290, id); +} + int32_t sprite_database_get_spr_set_id_by_name(const prj::string& name) { int32_t(FASTCALL * sprite_database_struct__get_spr_set_id_by_name) (size_t _this, const prj::string & name) diff --git a/src/DivaGL/sprite.hpp b/src/DivaGL/sprite.hpp index ee0213b..cdb2cb8 100644 --- a/src/DivaGL/sprite.hpp +++ b/src/DivaGL/sprite.hpp @@ -7,6 +7,7 @@ #include "../KKdLib/default.hpp" #include "../KKdLib/mat.hpp" +#include "../KKdLib/rectangle.hpp" #include "../KKdLib/vec.hpp" #include "gl_state.hpp" #include "render_context.hpp" @@ -14,10 +15,59 @@ #include "texture.hpp" #include "types.hpp" +#define BREAK_SPRITE_VERTEX_LIMIT (0) struct spr_info { uint16_t index; uint16_t set_index; + + inline spr_info() { + this->index = (uint16_t)-1; + this->set_index = (uint16_t)-1; + } + + inline spr_info(uint16_t index, uint16_t set_index) { + this->index = index; + this->set_index = set_index; + } + + inline bool is_null() const { + return index == (uint16_t)-1 && set_index == (uint16_t)-1; + } + + inline bool not_null() const { + return index != (uint16_t)-1 || set_index != (uint16_t)-1; + } +}; + +constexpr bool operator==(const spr_info& left, const spr_info& right) { + return *(uint32_t*)&left == *(uint32_t*)&right; +} + +constexpr bool operator!=(const spr_info& left, const spr_info& right) { + return !(left == right); +} + +constexpr bool operator<(const spr_info& left, const spr_info& right) { + return *(uint32_t*)&left < *(uint32_t*)&right; +} + +constexpr bool operator>(const spr_info& left, const spr_info& right) { + return right < left; +} + +constexpr bool operator<=(const spr_info& left, const spr_info& right) { + return !(right < left); +} + +constexpr bool operator>=(const spr_info& left, const spr_info& right) { + return !(left < right); +} + +struct spr_db_spr { + uint32_t id; + prj::string name; + spr_info info; }; struct SpriteHeaderFile { @@ -191,7 +241,11 @@ namespace spr { mat4 mat; texture* texture; int32_t shader; +#if BREAK_SPRITE_VERTEX_LIMIT + size_t vertex_array; +#else SpriteVertex* vertex_array; +#endif size_t num_vertex; Flags flags; vec2 sprite_size; @@ -199,11 +253,33 @@ namespace spr { vec2 texture_pos; vec2 texture_size; spr::SprArgs* next; + + SprArgs(); + + void Reset(); + void SetSpriteSize(vec2 size); + void SetTexturePosSize(float_t x, float_t y, float_t width, float_t height); + void SetVertexArray(SpriteVertex* vertex_array, size_t num_vertex); + + static void SetNext(SprArgs* args, SprArgs* next); }; + static_assert(sizeof(spr::SprArgs) == 0xE8, "\"spr::SprArgs\" struct should have a size of 0xE8"); - extern void(FASTCALL* put_rgb_cross)(mat4* mat); + extern void(FASTCALL* put_cross)(const mat4* mat, color4u8 color_x, color4u8 color_y, color4u8 color_z); + extern void(FASTCALL* put_rgb_cross)(const mat4* mat); extern spr::SprArgs* (FASTCALL* put_sprite)(const spr::SprArgs* args); + + vec2 proj_sprite_3d_line(vec3 vec, bool offset); + + void put_sprite_3d_line(vec3 p1, vec3 p2, color4u8 color); + void put_sprite_line(vec2 p1, vec2 p2, resolution_mode mode, spr::SprPrio prio, color4u8 color, int32_t layer); + void put_sprite_line_list(vec2* points, size_t count, resolution_mode mode, + spr::SprPrio prio, color4u8 color, int32_t layer); + void put_sprite_multi(rectangle rect, resolution_mode mode, spr::SprPrio prio, color4u8 color, int32_t layer); + void put_sprite_rect(rectangle rect, resolution_mode mode, spr::SprPrio prio, color4u8 color, int32_t layer); + void put_sprite_triangles(SpriteVertex* vert, size_t num, resolution_mode mode, + SprPrio prio, int32_t spr_id, int32_t layer); } extern vec4& spr_color; @@ -213,6 +289,7 @@ extern size_t(FASTCALL* sprite_manager_get_reqlist_count)(int32_t index); extern void (FASTCALL* sprite_manager_read_file)(int32_t set_id, const prj::string mdata_dir); extern bool (FASTCALL* sprite_manager_load_file)(int32_t set_id); +extern const spr_db_spr* sprite_database_get_spr_by_id(int32_t id); extern int32_t sprite_database_get_spr_set_id_by_name(const prj::string& name); extern void sprite_manager_init();