Owner-authorized source migration: 31 helper-only translation units were merged into their callers or existing inline headers; both build manifests updated. Includes the preserved source payload, Lua configuration matching wowdecomp, and exact malloca expansion without diagnostic pragmas. 449 native units compiled locally and 449 staged units compiled by the pinned server toolchain. No previously byte-matched function regressed. Compiler mapping diagnostics remain recorded as needs_cleanup, not accepted or peer-confirmed. Existing independent review records are preserved. README.md is intentionally unchanged.
728 lines
17 KiB
C++
728 lines
17 KiB
C++
#include "Client/Mode/ModeCursor.h"
|
|
#include "Client/Mode/ModeEvents.h"
|
|
#include "Render/DeviceContext/DCBitmap.h"
|
|
#include "Render/Primitives/RenderPrimitivePool.h"
|
|
#include "Render/Primitives/RenderQueues.h"
|
|
#include "Render/Renderer.h"
|
|
#include "Render/Text/TextContext.h"
|
|
#include "Render/Textures/Texture.h"
|
|
#include "Resource/Bitmap/BitmapImage.h"
|
|
#include "UI/Window/UIWindow.h"
|
|
#include "UI/Window/WindowRegistration.h"
|
|
|
|
#include <bit>
|
|
#include <cstring>
|
|
#include <windows.h>
|
|
#include <timeapi.h>
|
|
|
|
// INLINED
|
|
inline WindowGeometry::WindowGeometry()
|
|
: width(0), height(0), x(0), y(0), surface(nullptr), visible(1), id(600), unknown_0030(0), unknown_0034(0), targetAlpha(255), alphaStart(timeGetTime()),
|
|
currentAlpha(255) {
|
|
}
|
|
|
|
// INLINED
|
|
inline void WindowGeometry::Show(int state) {
|
|
this->visible = state;
|
|
}
|
|
|
|
// INLINED
|
|
inline void WindowGeometry::SetId(int value) {
|
|
this->id = value;
|
|
}
|
|
|
|
// INLINED
|
|
inline std::uint32_t WindowGeometry::Color() {
|
|
std::uint32_t value = this->currentAlpha;
|
|
if (value != this->targetAlpha) {
|
|
const std::uint32_t step = (timeGetTime() - this->alphaStart) >> 4;
|
|
const std::uint32_t candidate = value < this->targetAlpha ? value + step : value - step;
|
|
const bool keepCandidate = value < this->targetAlpha ? candidate < this->targetAlpha : this->targetAlpha < candidate;
|
|
|
|
value = keepCandidate ? candidate : this->targetAlpha;
|
|
this->currentAlpha = value;
|
|
}
|
|
|
|
if (value > 255) {
|
|
value = this->targetAlpha;
|
|
this->currentAlpha = value;
|
|
}
|
|
|
|
return (value << 24) + 0xFFFFFF;
|
|
}
|
|
|
|
// STATIC: 0x0145723C
|
|
// GLOBAL: gl_24364
|
|
std::uint32_t g_windowUid = 0xFFFFFFFFu;
|
|
|
|
// INLINED
|
|
void UIWindowContext::DestroyDeferredChildren() {
|
|
for (UIWindow* window : this->deferredDeletion) {
|
|
delete window;
|
|
}
|
|
|
|
this->deferredDeletion.clear();
|
|
}
|
|
|
|
// OFFSET: 0x00A79A90
|
|
// FUNCTION: fn_16914
|
|
UIWindow::UIWindow(UIWindowContext& context, unsigned char cached)
|
|
: unknown_0044(0), unknown_0048(0), unknown_004C(4), m_dirty(1), m_uid(++g_windowUid), m_cached(cached), m_clip(0), m_context(&context) {
|
|
}
|
|
|
|
// OFFSET: 0x00A79E90
|
|
// OFFSET: 0x00A7A050
|
|
// FUNCTION: fn_16917
|
|
UIWindow::~UIWindow() {
|
|
delete this->geometry.surface;
|
|
this->geometry.surface = nullptr;
|
|
this->DeleteChildren();
|
|
this->m_context->registration.Remove(this);
|
|
ForgetWindowReferences(
|
|
this, this->m_context->reference_019C, this->m_context->reference_01A0, this->m_context->reference_01B8, this->m_context->reference_0A30,
|
|
this->m_context->reference_4F1D4
|
|
);
|
|
}
|
|
|
|
// INLINED
|
|
UIWindow* UIWindow::Parent() const {
|
|
return static_cast<UIWindow*>(this->parent);
|
|
}
|
|
|
|
// OFFSET: 0x00A82EB0
|
|
// FUNCTION: fn_16998
|
|
void UIWindow::Resize(int width, int height) {
|
|
delete this->geometry.surface;
|
|
this->geometry.surface = CreateBitmapDC(width, height, true);
|
|
this->geometry.width = width;
|
|
this->geometry.height = height;
|
|
this->Invalidate();
|
|
}
|
|
|
|
// OFFSET: 0x005C4650
|
|
// FUNCTION: fn_03571
|
|
bool UIWindow::Slot02() {
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x005C4670
|
|
// FUNCTION: fn_03573
|
|
bool UIWindow::Slot03() {
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00A81D40
|
|
// FUNCTION: fn_16987
|
|
void UIWindow::Move(int x, int y) {
|
|
this->geometry.Move(x, y);
|
|
}
|
|
|
|
// OFFSET: 0x005C3220
|
|
// FUNCTION: fn_03553
|
|
bool UIWindow::Slot05() {
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x005C4510
|
|
// FUNCTION: fn_03564
|
|
UIWindow* UIWindow::Slot06() {
|
|
return this;
|
|
}
|
|
|
|
// OFFSET: 0x005C45C0
|
|
// FUNCTION: fn_03567
|
|
bool UIWindow::Slot07(void*) {
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x005C4660
|
|
// FUNCTION: fn_03572
|
|
bool UIWindow::Slot08() {
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x005CA050
|
|
// FUNCTION: fn_03638
|
|
bool UIWindow::CanHitTest() {
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x00A7BB00
|
|
// FUNCTION: fn_16933
|
|
void UIWindow::Slot10(int, int, std::intptr_t) {
|
|
this->m_context->mode->SendModeMessage(18, 0, 0, 0, 0);
|
|
}
|
|
|
|
// OFFSET: 0x005CA0F0
|
|
// FUNCTION: fn_03640
|
|
void UIWindow::Slot11() {
|
|
}
|
|
|
|
// OFFSET: 0x005C7B40
|
|
// FUNCTION: fn_03623
|
|
void UIWindow::Slot12() {
|
|
}
|
|
|
|
// OFFSET: 0x005C4680
|
|
// FUNCTION: fn_03574
|
|
void UIWindow::Slot13(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C9630
|
|
// FUNCTION: fn_03632
|
|
void UIWindow::Show(int visible) {
|
|
this->geometry.Show(visible);
|
|
}
|
|
|
|
// OFFSET: 0x005C6070
|
|
// FUNCTION: fn_03584
|
|
void UIWindow::Slot15(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C6F10
|
|
// FUNCTION: fn_03592
|
|
void UIWindow::Slot16() {
|
|
}
|
|
|
|
// OFFSET: 0x005C7340
|
|
// FUNCTION: fn_03613
|
|
void UIWindow::Grow(int width, int height) {
|
|
this->Resize((this->geometry.width + width), (this->geometry.height + height));
|
|
}
|
|
|
|
// OFFSET: 0x005C6080
|
|
// FUNCTION: fn_03585
|
|
void UIWindow::Slot18() {
|
|
}
|
|
|
|
// OFFSET: 0x005C72D0
|
|
// FUNCTION: fn_03606
|
|
void UIWindow::Slot19() {
|
|
}
|
|
|
|
// OFFSET: 0x006006C0
|
|
// FUNCTION: fn_04159
|
|
void UIWindow::Paint() {
|
|
}
|
|
|
|
// OFFSET: 0x005C7320
|
|
// FUNCTION: fn_03611
|
|
void UIWindow::Slot21() {
|
|
}
|
|
|
|
// OFFSET: 0x005C7330
|
|
// FUNCTION: fn_03612
|
|
void UIWindow::Slot22(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C4C70
|
|
// FUNCTION: fn_03578
|
|
void UIWindow::Slot23() {
|
|
}
|
|
|
|
// OFFSET: 0x005C6F00
|
|
// FUNCTION: fn_03591
|
|
void UIWindow::Slot24(int) {
|
|
}
|
|
|
|
// OFFSET: 0x005FDA50
|
|
// FUNCTION: fn_04116
|
|
void UIWindow::Slot25(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C6F30
|
|
// FUNCTION: fn_03594
|
|
void UIWindow::Slot26(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C7280
|
|
// FUNCTION: fn_03602
|
|
void UIWindow::Slot27(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C7260
|
|
// FUNCTION: fn_03600
|
|
void UIWindow::Slot28(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C7290
|
|
// FUNCTION: fn_03603
|
|
void UIWindow::Slot29(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x00A81D60
|
|
// FUNCTION: fn_16988
|
|
void UIWindow::ResetCursor(int, int) {
|
|
this->m_context->cursor.Set(0, this->m_context->cursorTick);
|
|
}
|
|
|
|
// OFFSET: 0x005C7240
|
|
// FUNCTION: fn_03598
|
|
void UIWindow::Slot31(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C7300
|
|
// FUNCTION: fn_03609
|
|
void UIWindow::Slot32(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C7310
|
|
// FUNCTION: fn_03610
|
|
void UIWindow::Slot33(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C72E0
|
|
// FUNCTION: fn_03607
|
|
void UIWindow::Slot34(int, int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C73A0
|
|
// FUNCTION: fn_03615
|
|
void UIWindow::Slot35(int) {
|
|
}
|
|
|
|
// OFFSET: 0x005C7AB0
|
|
// FUNCTION: fn_03620
|
|
void UIWindow::Slot36() {
|
|
}
|
|
|
|
// OFFSET: 0x00A83660
|
|
// FUNCTION: fn_17005
|
|
int UIWindow::SendMsg(UIWindow*, int message, std::intptr_t, std::intptr_t, std::intptr_t, std::intptr_t) {
|
|
if ((message == 0 || message == 1) && this->parent) {
|
|
this->Parent()->SendMsg(this, message, 0, 0, 0, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// OFFSET: 0x00A81C30
|
|
// FUNCTION: fn_16983
|
|
void UIWindow::Invalidate() {
|
|
this->m_dirty = 1;
|
|
if (this->parent && this->Parent()->m_cached == 1) {
|
|
this->Parent()->Invalidate();
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00A81C50
|
|
// FUNCTION: fn_16984
|
|
void UIWindow::InvalidateChildren() {
|
|
this->m_dirty = 1;
|
|
this->Slot39();
|
|
|
|
for (UIWindow* child : this->m_children) {
|
|
if (child->geometry.visible != 0) {
|
|
child->InvalidateChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x005C4630
|
|
// FUNCTION: fn_03569
|
|
void UIWindow::Slot39() {
|
|
}
|
|
|
|
// OFFSET: 0x00A7D6F0
|
|
// FUNCTION: fn_16954
|
|
std::uint32_t UIWindow::Color() {
|
|
return this->geometry.Color();
|
|
}
|
|
|
|
// OFFSET: 0x00A7B710
|
|
// FUNCTION: fn_16931
|
|
bool UIWindow::Update(int redraw) {
|
|
if (this->m_dirty == 1) {
|
|
this->Paint();
|
|
this->m_dirty = 0;
|
|
redraw = 1;
|
|
}
|
|
|
|
bool changed = false;
|
|
|
|
for (UIWindow* child : this->m_children) {
|
|
if (child->geometry.visible == 1) {
|
|
changed = child->Update(redraw) || changed;
|
|
}
|
|
}
|
|
|
|
if (this->m_cached == 1) {
|
|
if (redraw != 1 && !changed) {
|
|
return false;
|
|
}
|
|
|
|
std::list<RenderPrimitive*> primitives(this->m_primitives);
|
|
|
|
for (UIWindow* child : this->m_children) {
|
|
if (child->geometry.visible == 1) {
|
|
primitives.push_back(child->DrawPrimitive());
|
|
}
|
|
}
|
|
|
|
this->m_context->renderer.RenderToTexture(this->geometry.width, this->geometry.height, primitives, this->m_texture);
|
|
return this->parent != nullptr;
|
|
}
|
|
|
|
if (!this->parent || (redraw != 1 && !changed)) {
|
|
return false;
|
|
}
|
|
|
|
UIWindow* parentWindow = this->Parent();
|
|
if (parentWindow->m_cached != 0) {
|
|
return true;
|
|
}
|
|
|
|
CDCBitmap& source = *static_cast<CDCBitmap*>(this->geometry.surface);
|
|
if (this->m_clip == 0) {
|
|
parentWindow->geometry.surface->BlendFrom(this->geometry.x, this->geometry.y, this->geometry.width, this->geometry.height, source);
|
|
return true;
|
|
}
|
|
|
|
int x = this->geometry.x >= 0 ? this->geometry.x : 0;
|
|
int y = this->geometry.y >= 0 ? this->geometry.y : 0;
|
|
int sourceX = this->geometry.x >= 0 ? 0 : (0 - this->geometry.x);
|
|
int sourceY = this->geometry.y >= 0 ? 0 : (0 - this->geometry.y);
|
|
int width = this->geometry.x >= 0 ? this->geometry.width : (this->geometry.width + this->geometry.x);
|
|
int height = this->geometry.y >= 0 ? this->geometry.height : (this->geometry.height + this->geometry.y);
|
|
|
|
if (parentWindow->geometry.width < (x + width)) {
|
|
width = (parentWindow->geometry.width - x);
|
|
}
|
|
|
|
if (parentWindow->geometry.height < (y + height)) {
|
|
height = (parentWindow->geometry.height - y);
|
|
}
|
|
|
|
if (width > 0 && height > 0) {
|
|
parentWindow->geometry.surface->CopyFrom(x, y, sourceX, sourceY, width, height, source);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// OFFSET: 0x005C45B0
|
|
// FUNCTION: fn_03566
|
|
bool UIWindow::Slot42(void*) {
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x005C33D0
|
|
// FUNCTION: fn_03556
|
|
void UIWindow::Slot43() {
|
|
}
|
|
|
|
// OFFSET: 0x005C4480
|
|
// FUNCTION: fn_03560
|
|
std::vector<std::uint32_t> UIWindow::Slot44() {
|
|
return {};
|
|
}
|
|
|
|
// OFFSET: 0x005C8F60
|
|
// FUNCTION: fn_03629
|
|
void UIWindow::SetId(int value) {
|
|
this->geometry.SetId(value);
|
|
}
|
|
|
|
// OFFSET: 0x005C4500
|
|
// FUNCTION: fn_03563
|
|
int UIWindow::Slot46() {
|
|
return 0;
|
|
}
|
|
|
|
// OFFSET: 0x005C7250
|
|
// FUNCTION: fn_03599
|
|
void UIWindow::Slot47() {
|
|
}
|
|
|
|
// OFFSET: 0x005C7270
|
|
// FUNCTION: fn_03601
|
|
void UIWindow::Slot48() {
|
|
}
|
|
|
|
// OFFSET: 0x00A7FFB0
|
|
// FUNCTION: fn_16970
|
|
RenderPrimitive* UIWindow::DrawPrimitive() {
|
|
if (this->m_cached == 0) {
|
|
static_cast<CDCBitmap*>(this->geometry.surface)->UploadTexture(this->m_context->renderSystem, this->m_texture);
|
|
}
|
|
|
|
RenderPrimitive* primitive = this->m_context->primitives.Acquire();
|
|
primitive->texture = this->m_texture;
|
|
const float width = static_cast<float>(std::bit_cast<std::int32_t>(this->m_texture->TextureWidth()));
|
|
const float height = static_cast<float>(std::bit_cast<std::int32_t>(this->m_texture->TextureHeight()));
|
|
const float x = static_cast<float>(this->geometry.x);
|
|
const float y = static_cast<float>(this->geometry.y);
|
|
const float right = static_cast<float>((this->geometry.x + this->geometry.width));
|
|
const float bottom = static_cast<float>((this->geometry.y + this->geometry.height));
|
|
const float u0 = g_textureOffsetX / width;
|
|
const float v0 = g_textureOffsetY / height;
|
|
const float u1 = (static_cast<float>(this->geometry.width) + g_textureOffsetX) / width;
|
|
const float v1 = (static_cast<float>(this->geometry.height) + g_textureOffsetY) / height;
|
|
|
|
primitive->quad[0].x = x;
|
|
primitive->quad[0].y = y;
|
|
primitive->quad[0].u = u0;
|
|
primitive->quad[0].v = v0;
|
|
primitive->quad[1].x = right;
|
|
primitive->quad[1].y = y;
|
|
primitive->quad[1].u = u1;
|
|
primitive->quad[1].v = v0;
|
|
primitive->quad[2].x = x;
|
|
primitive->quad[2].y = bottom;
|
|
primitive->quad[2].u = u0;
|
|
primitive->quad[2].v = v1;
|
|
primitive->quad[3].x = right;
|
|
primitive->quad[3].y = bottom;
|
|
primitive->quad[3].u = u1;
|
|
primitive->quad[3].v = v1;
|
|
|
|
for (RenderVertex& vertex : primitive->quad) {
|
|
vertex.z = 0.000001f;
|
|
vertex.rhw = 0.999999f;
|
|
vertex.diffuse = this->Color();
|
|
}
|
|
|
|
return primitive;
|
|
}
|
|
|
|
// OFFSET: 0x00A81B10
|
|
// FUNCTION: fn_16981
|
|
UIWindow* UIWindow::HitTest(int x, int y) {
|
|
if (!this->CanHitTest() || this->geometry.visible == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (x < this->geometry.x || x >= (this->geometry.x + this->geometry.width) || y < this->geometry.y || y >= (this->geometry.y + this->geometry.height)) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (auto child = this->m_children.rbegin(); child != this->m_children.rend(); ++child) {
|
|
UIWindow* hit = (*child)->HitTest((x - this->geometry.x), (y - this->geometry.y));
|
|
if (hit) {
|
|
return hit;
|
|
}
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
// OFFSET: 0x00A7C4B0
|
|
// FUNCTION: fn_16945
|
|
void UIWindow::VisitChildren() {
|
|
for (UIWindow* child : this->m_children) {
|
|
if (child) {
|
|
child->VisitChildren();
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x005C7AC0
|
|
// FUNCTION: fn_03621
|
|
void UIWindow::Slot52(int) {
|
|
}
|
|
|
|
// OFFSET: 0x00A7A080
|
|
// FUNCTION: fn_16920
|
|
void UIWindow::AddChild(UIWindow* child) {
|
|
child->parent = this;
|
|
this->m_children.push_back(child);
|
|
}
|
|
|
|
// OFFSET: 0x00A7A0A0
|
|
// FUNCTION: fn_16921
|
|
void UIWindow::AddChildFront(UIWindow* child) {
|
|
child->parent = this;
|
|
this->m_children.push_front(child);
|
|
}
|
|
|
|
// OFFSET: 0x00A81A30
|
|
// FUNCTION: fn_16979
|
|
UIWindow* UIWindow::FindUid(std::uint32_t uid) {
|
|
if (this->m_uid == uid) {
|
|
return this;
|
|
}
|
|
|
|
for (UIWindow* child : this->m_children) {
|
|
if (UIWindow* found = child->FindUid(uid)) {
|
|
return found;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// OFFSET: 0x00A7D6D0
|
|
// FUNCTION: fn_16953
|
|
UIWindow* UIWindow::Root() {
|
|
UIWindow* root = this;
|
|
|
|
while (root->parent) {
|
|
root = static_cast<UIWindow*>(root->parent);
|
|
}
|
|
|
|
return root;
|
|
}
|
|
|
|
// OFFSET: 0x00A82DD0
|
|
// FUNCTION: fn_16995
|
|
void UIWindow::DeleteChildren() {
|
|
for (UIWindow* child : this->m_children) {
|
|
delete child;
|
|
}
|
|
|
|
this->m_children.clear();
|
|
}
|
|
|
|
// OFFSET: 0x00A82E30
|
|
// FUNCTION: fn_16996
|
|
void UIWindow::ClearChildren(bool destroy) {
|
|
if (destroy) {
|
|
this->DeleteChildren();
|
|
} else {
|
|
this->m_children.clear();
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00AA5E90
|
|
// FUNCTION: fn_17226
|
|
void UIWindow::DeferDeletion(UIWindow* window) {
|
|
if (!window) {
|
|
return;
|
|
}
|
|
|
|
ForgetWindowReferences(
|
|
window, this->m_context->reference_019C, this->m_context->reference_01A0, this->m_context->reference_01B8, this->m_context->reference_0A30,
|
|
this->m_context->reference_4F1D4
|
|
);
|
|
this->m_context->deferredDeletion.insert(window);
|
|
window->Show(0);
|
|
}
|
|
|
|
// OFFSET: 0x00A82E50
|
|
// FUNCTION: fn_16997
|
|
void UIWindow::RemoveChild(UIWindow* child, unsigned char destroy) {
|
|
if (!child) {
|
|
return;
|
|
}
|
|
|
|
for (auto entry = this->m_children.begin(); entry != this->m_children.end(); ++entry) {
|
|
if (*entry == child) {
|
|
if (destroy == 1) {
|
|
this->DeferDeletion(child);
|
|
}
|
|
|
|
this->m_children.erase(entry);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00A81CC0
|
|
// FUNCTION: fn_16986
|
|
bool UIWindow::Contains(const UIWindow* window) const {
|
|
if (!window) {
|
|
return false;
|
|
}
|
|
|
|
if (window == this) {
|
|
return true;
|
|
}
|
|
|
|
for (UIWindow* child : this->m_children) {
|
|
if (child->Contains(window)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// OFFSET: 0x00A7B430
|
|
// FUNCTION: fn_16927
|
|
void UIWindow::ClearSurface(std::uint32_t color) {
|
|
if (this->geometry.surface) {
|
|
this->geometry.surface->Fill(nullptr, color);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00A7B470
|
|
// FUNCTION: fn_16929
|
|
void UIWindow::SetSize(int width, int height) {
|
|
delete this->geometry.surface;
|
|
this->geometry.surface = CreateBitmapDC(width, height, true);
|
|
this->geometry.width = width;
|
|
this->geometry.height = height;
|
|
this->Invalidate();
|
|
this->Slot15(width, height);
|
|
this->Slot22(width, height);
|
|
this->Slot16();
|
|
}
|
|
|
|
// OFFSET: 0x00A7BB60
|
|
// FUNCTION: fn_16935
|
|
void UIWindow::DrawBitmap(int x, int y, const BitmapImage* image, bool transparent) {
|
|
if (!this->geometry.surface || !image) {
|
|
return;
|
|
}
|
|
|
|
static_cast<CDCBitmap*>(this->geometry.surface)->SetAlpha(image->alpha != 0);
|
|
this->geometry.surface->Copy(x, y, image->width, image->height, image->pixels, transparent);
|
|
}
|
|
|
|
// OFFSET: 0x00A7BD60
|
|
// FUNCTION: fn_16938
|
|
void UIWindow::FillRegion(int x, int y, int width, int height, std::uint32_t color) {
|
|
const int right = (x + width);
|
|
const int bottom = (y + height);
|
|
RECT rectangle = {
|
|
x < 0 ? 0 : x, y < 0 ? 0 : y, this->geometry.width < right ? this->geometry.width : right, this->geometry.height < bottom ? this->geometry.height : bottom
|
|
};
|
|
this->geometry.surface->Fill(&rectangle, color);
|
|
}
|
|
|
|
// OFFSET: 0x00A80580
|
|
// FUNCTION: fn_16975
|
|
int UIWindow::TextWidth(
|
|
FontCache& fonts, const TextLocale& locale, const char* text, unsigned bytes, int family, int height, unsigned char bold, unsigned char italic
|
|
) {
|
|
if (!text) {
|
|
return 0;
|
|
}
|
|
|
|
if (!bytes) {
|
|
bytes = static_cast<unsigned>(std::strlen(text));
|
|
if (!bytes) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
TextContext context(*this->geometry.surface, fonts, locale);
|
|
context.SetFont(family, height, bold, italic);
|
|
return context.Measure(text, bytes).cx;
|
|
}
|
|
|
|
// OFFSET: 0x00A84360
|
|
// FUNCTION: fn_17009
|
|
void UIWindow::DrawTextAt(
|
|
FontCache& fonts, const TextLocale& locale, int x, int y, const char* text, int bytes, int family, int height, std::uint32_t color, unsigned char bold,
|
|
unsigned char italic
|
|
) {
|
|
if (!bytes) {
|
|
bytes = static_cast<int>(std::strlen(text));
|
|
}
|
|
|
|
TextContext context(*this->geometry.surface, fonts, locale);
|
|
context.SetFont(family, height, bold, italic);
|
|
context.SetColor(color);
|
|
context.Draw(x, y, text, bytes);
|
|
}
|
|
|
|
// OFFSET: 0x00A7C470
|
|
// FUNCTION: fn_16944
|
|
void UIWindow::FlushPrimitives(RenderQueues& queues, bool depthAlpha, float depthStart, float depthEnd) {
|
|
for (RenderPrimitive* primitive : this->m_overlayPrimitives) {
|
|
queues.Submit(primitive, 513, depthAlpha, depthStart, depthEnd);
|
|
}
|
|
|
|
this->m_overlayPrimitives.clear();
|
|
}
|