From b4e962ed1f3a60d77dea51f2a7a204b2f719a4f0 Mon Sep 17 00:00:00 2001 From: ragnarok-clanker Date: Wed, 28 Oct 2026 19:47:08 +0000 Subject: [PATCH] Decompile 5 functions in Source/Render/OpaqueQueuesDX7.cpp, Source/Render/AlphaQueuesDX7.cpp, ... Batch #1637 by eAthena: 0 byte-identical, 5 confirmed by peer review. - fn_02088 QueuedDrawingDX7::DrawDepthSortedQueue: logic confirmed by peer review - fn_02091 QueuedDrawingDX7::DrawOpaqueQueues: logic confirmed by peer review - fn_02092 QueuedDrawingDX7::DrawGroundBaseQueue: logic confirmed by peer review - fn_02089 QueuedDrawingDX7::DrawAlphaQueues: logic confirmed by peer review - fn_02093 QueuedDrawingDX7::DrawAuxiliaryQueue: logic confirmed by peer review Reviewed-by: ragnarok-clanker Adds to the build: Source/Render/OpaqueQueuesDX7.cpp, Source/Render/AlphaQueuesDX7.cpp, Source/Render/AuxiliaryQueuesDX7.cpp --- Source/Render/AlphaQueuesDX7.cpp | 111 +++++++++++++++++++++++++++ Source/Render/AuxiliaryQueuesDX7.cpp | 59 ++++++++++++++ Source/Render/DX7/QueuedDrawingDX7.h | 50 ++++++++++++ Source/Render/OpaqueQueuesDX7.cpp | 70 +++++++++++++++++ data/compile.json | 3 + 5 files changed, 293 insertions(+) create mode 100644 Source/Render/AlphaQueuesDX7.cpp create mode 100644 Source/Render/AuxiliaryQueuesDX7.cpp create mode 100644 Source/Render/DX7/QueuedDrawingDX7.h create mode 100644 Source/Render/OpaqueQueuesDX7.cpp diff --git a/Source/Render/AlphaQueuesDX7.cpp b/Source/Render/AlphaQueuesDX7.cpp new file mode 100644 index 0000000..ae58463 --- /dev/null +++ b/Source/Render/AlphaQueuesDX7.cpp @@ -0,0 +1,111 @@ +#include "Render/DX7/QueuedDrawingDX7.h" + +#include +#include + +namespace { + // INLINED + bool Before(const DepthPrimitive& left, const DepthPrimitive& right) { + if (left.depth < right.depth) { + return true; + } + + if (right.depth < left.depth) { + return false; + } + + return left.depth == right.depth && reinterpret_cast(left.primitive) < reinterpret_cast(right.primitive); + } + + // INLINED + bool WritesDepth(const RenderCommand& command) { + return (command.unknown_0014 & 0xFFu) != 0 && (command.unknown_0014 & 0xFF00u) != 0; + } +} + +// OFFSET: 0x0055B160 +// FUNCTION: fn_02089 +void QueuedDrawingDX7::DrawAlphaQueues() { + const auto before = [](const DepthPrimitive& left, const DepthPrimitive& right) { + return Before(left, right); + }; + + std::sort(this->queues.queue_018C.begin(), this->queues.queue_018C.end(), before); + std::sort(this->queues.queue_01BC.begin(), this->queues.queue_01BC.end(), before); + + DWORD zWrite = 0; + DWORD alphaTest = 0; + DWORD alphaReference = 0; + DWORD alphaFunction = 0; + DWORD alphaBlend = 0; + DWORD sourceBlend = 0; + DWORD destinationBlend = 0; + this->device->GetRenderState(D3DRENDERSTATE_ZWRITEENABLE, &zWrite); + this->device->GetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, &alphaTest); + this->device->GetRenderState(D3DRENDERSTATE_ALPHAREF, &alphaReference); + this->device->GetRenderState(D3DRENDERSTATE_ALPHAFUNC, &alphaFunction); + this->device->GetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, &alphaBlend); + this->device->GetRenderState(D3DRENDERSTATE_SRCBLEND, &sourceBlend); + this->device->GetRenderState(D3DRENDERSTATE_DESTBLEND, &destinationBlend); + + this->device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE); + this->device->SetRenderState(D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA); + this->device->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA); + this->device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, TRUE); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAREF, 1); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATEREQUAL); + + const auto drawAlphaTested = [this](const DepthPrimitive& entry) { + RenderCommand* command = entry.primitive; + this->device->SetRenderState(D3DRENDERSTATE_ALPHAREF, WritesDepth(*command) ? 1 : 240); + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + }; + + if (this->twoPass == 1) { + this->device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, TRUE); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATEREQUAL); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + std::for_each(this->queues.queue_018C.begin(), this->queues.queue_018C.end(), drawAlphaTested); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + std::for_each(this->queues.queue_01BC.begin(), this->queues.queue_01BC.end(), drawAlphaTested); + + this->device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, FALSE); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_LESS); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + std::for_each(this->queues.queue_018C.begin(), this->queues.queue_018C.end(), drawAlphaTested); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + std::for_each(this->queues.queue_01BC.begin(), this->queues.queue_01BC.end(), drawAlphaTested); + + this->device->SetRenderState(D3DRENDERSTATE_ALPHAREF, 1); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATEREQUAL); + std::sort(this->queues.queue_01A4.begin(), this->queues.queue_01A4.end(), before); + + for (auto it = this->queues.queue_01A4.begin(); it != this->queues.queue_01A4.end(); ++it) { + RenderCommand* command = it->primitive; + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + } + } else { + const auto drawDepthWriting = [this](const DepthPrimitive& entry) { + RenderCommand* command = entry.primitive; + this->device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, WritesDepth(*command)); + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + }; + + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + std::for_each(this->queues.queue_018C.begin(), this->queues.queue_018C.end(), drawDepthWriting); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + std::for_each(this->queues.queue_01BC.begin(), this->queues.queue_01BC.end(), drawDepthWriting); + } + + this->device->SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, zWrite); + this->device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, alphaTest); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAREF, alphaReference); + this->device->SetRenderState(D3DRENDERSTATE_ALPHAFUNC, alphaFunction); + this->device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, alphaBlend); + this->device->SetRenderState(D3DRENDERSTATE_SRCBLEND, sourceBlend); + this->device->SetRenderState(D3DRENDERSTATE_DESTBLEND, destinationBlend); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); +} diff --git a/Source/Render/AuxiliaryQueuesDX7.cpp b/Source/Render/AuxiliaryQueuesDX7.cpp new file mode 100644 index 0000000..457dd6c --- /dev/null +++ b/Source/Render/AuxiliaryQueuesDX7.cpp @@ -0,0 +1,59 @@ +#include "Render/DX7/QueuedDrawingDX7.h" + +#include +#include + +// OFFSET: 0x0055BE40 +// FUNCTION: fn_02093 +void QueuedDrawingDX7::DrawAuxiliaryQueue() { + auto& queue = this->queues.queue_0240; + + if (queue.empty()) { + return; + } + + std::sort(queue.begin(), queue.end(), [](const LightmappedPrimitive* left, const LightmappedPrimitive* right) { + const auto first = reinterpret_cast(left->texture); + const auto second = reinterpret_cast(right->texture); + + if (first != second) { + return first < second; + } + + return reinterpret_cast(left->lightmap) < reinterpret_cast(right->lightmap); + }); + this->device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + this->device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + this->device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + this->device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + this->device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + this->device->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + this->device->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + this->device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + this->device->SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + this->device->SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_CURRENT); + this->device->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); + this->device->SetTextureStageState(2, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + this->device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + + for (auto it = queue.begin(); it != queue.end(); ++it) { + LightmappedPrimitive* command = *it; + + if (command->vertexCount > 0) { + this->BindTexture(static_cast(command->texture)); + this->BindLightmap(static_cast(command->lightmap)); + command->DrawAuxiliary(reinterpret_cast(this->device)); + } + } + + this->device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + this->device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + this->device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + this->device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + this->device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + this->device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + this->device->SetTextureStageState(1, D3DTSS_ADDRESS, D3DTADDRESS_BORDER); + this->device->SetTexture(1, nullptr); +} diff --git a/Source/Render/DX7/QueuedDrawingDX7.h b/Source/Render/DX7/QueuedDrawingDX7.h new file mode 100644 index 0000000..8e8c087 --- /dev/null +++ b/Source/Render/DX7/QueuedDrawingDX7.h @@ -0,0 +1,50 @@ +#ifndef RAGNAROK_SOURCE_RENDER_DX7_QUEUEDDRAWINGDX7_H +#define RAGNAROK_SOURCE_RENDER_DX7_QUEUEDDRAWINGDX7_H + +#include "Render/DX7/TextureDX7.h" +#include "Render/Primitives/RenderQueues.h" + +#include +#include + +struct QueuedDrawingDX7 { + /* 0000 */ unsigned char unknown_0000[0x48]; + /* 0048 */ unsigned char twoPass; + /* 0049 */ unsigned char unknown_0049[0x113]; + /* 015C */ RenderQueues queues; + /* 024C */ unsigned char unknown_024C[0x1C]; + /* 0268 */ CTextureDX7* boundTexture; + /* 026C */ CTextureDX7* boundLightmap; + /* 0270 */ unsigned unknown_0270; + /* 0274 */ IDirect3DDevice7* device; + + void DrawDepthSortedQueue(); + void DrawAlphaQueues(); + void DrawOpaqueQueues(); + void DrawGroundBaseQueue(); + void DrawAuxiliaryQueue(); + // INLINED + void BindTexture(CTextureDX7* texture) { + if (this->boundTexture != texture) { + this->device->SetTexture(0, texture ? texture->NativeSurface() : nullptr); + this->boundTexture = texture; + } + } + // INLINED + void BindLightmap(CTextureDX7* lightmap) { + if (this->boundLightmap != lightmap) { + this->device->SetTexture(1, lightmap ? lightmap->NativeSurface() : nullptr); + this->boundLightmap = lightmap; + } + } +}; + +#if defined(_WIN32) && !defined(_WIN64) +static_assert(offsetof(QueuedDrawingDX7, twoPass) == 0x0048); +static_assert(offsetof(QueuedDrawingDX7, queues) == 0x015C); +static_assert(offsetof(QueuedDrawingDX7, boundTexture) == 0x0268); +static_assert(offsetof(QueuedDrawingDX7, boundLightmap) == 0x026C); +static_assert(offsetof(QueuedDrawingDX7, device) == 0x0274); +#endif + +#endif diff --git a/Source/Render/OpaqueQueuesDX7.cpp b/Source/Render/OpaqueQueuesDX7.cpp new file mode 100644 index 0000000..4651639 --- /dev/null +++ b/Source/Render/OpaqueQueuesDX7.cpp @@ -0,0 +1,70 @@ +#include "Render/DX7/QueuedDrawingDX7.h" + +#include +#include + +// OFFSET: 0x0055B0C0 +// FUNCTION: fn_02088 +void QueuedDrawingDX7::DrawDepthSortedQueue() { + std::sort(this->queues.queue_0180.begin(), this->queues.queue_0180.end(), [](const DepthPrimitive& left, const DepthPrimitive& right) { + if (left.depth < right.depth) { + return true; + } + + if (right.depth < left.depth) { + return false; + } + + return left.depth == right.depth && reinterpret_cast(left.primitive) < reinterpret_cast(right.primitive); + }); + + for (auto it = this->queues.queue_0180.begin(); it != this->queues.queue_0180.end(); ++it) { + RenderCommand* command = it->primitive; + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + } +} + +// OFFSET: 0x0055B9E0 +// FUNCTION: fn_02091 +void QueuedDrawingDX7::DrawOpaqueQueues() { + const auto before = [](const RenderCommand* left, const RenderCommand* right) { + return reinterpret_cast(left->texture) < reinterpret_cast(right->texture); + }; + + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); + std::sort(this->queues.queue_015C.begin(), this->queues.queue_015C.end(), before); + + for (auto it = this->queues.queue_015C.begin(); it != this->queues.queue_015C.end(); ++it) { + if (RenderCommand* command = *it) { + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + } + } + + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); + std::sort(this->queues.queue_01B0.begin(), this->queues.queue_01B0.end(), before); + + for (auto it = this->queues.queue_01B0.begin(); it != this->queues.queue_01B0.end(); ++it) { + if (RenderCommand* command = *it) { + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + } + } + + this->device->SetTextureStageState(0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); +} + +// OFFSET: 0x0055BC40 +// FUNCTION: fn_02092 +void QueuedDrawingDX7::DrawGroundBaseQueue() { + std::sort(this->queues.queue_0168.begin(), this->queues.queue_0168.end(), [](const RenderCommand* left, const RenderCommand* right) { + return reinterpret_cast(left->texture) < reinterpret_cast(right->texture); + }); + + for (auto it = this->queues.queue_0168.begin(); it != this->queues.queue_0168.end(); ++it) { + RenderCommand* command = *it; + this->BindTexture(static_cast(command->texture)); + command->Draw(reinterpret_cast(this->device)); + } +} diff --git a/data/compile.json b/data/compile.json index d98f387..2ad69b2 100644 --- a/data/compile.json +++ b/data/compile.json @@ -467,7 +467,9 @@ "Source/Network/Packets/PartyJoinRequest.cpp": 2, "Source/Network/Packets/SkillUpdatePacket.cpp": 4, "Source/Network/TextEncoding.cpp": 0, + "Source/Render/AlphaQueuesDX7.cpp": 0, "Source/Render/AlphaRectangle.cpp": 0, + "Source/Render/AuxiliaryQueuesDX7.cpp": 0, "Source/Render/BitmapDrawing.cpp": 0, "Source/Render/BlendColor.cpp": 0, "Source/Render/DX7/BackBufferDX7.cpp": 0, @@ -513,6 +515,7 @@ "Source/Render/DeviceSelection.cpp": 0, "Source/Render/Direct3DErrors.cpp": 0, "Source/Render/DisplayMode.cpp": 0, + "Source/Render/OpaqueQueuesDX7.cpp": 0, "Source/Render/Primitives/DepthAlpha.cpp": 0, "Source/Render/Primitives/LightmappedPrimitive.cpp": 0, "Source/Render/Primitives/RenderCommandPool.cpp": 0,