rodecomp/Source/Render/DX9/SurfaceDX9.cpp
ragnarok-clanker e168b4e4a6 Restore translation-unit ownership and publish verified source corrections
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.
2026-10-25 15:42:21 +00:00

244 lines
7.1 KiB
C++

#include "Render/DX9/SurfaceDX9.h"
#include <algorithm>
#include <cstring>
namespace {
// OFFSET: 0x00570970
// FUNCTION: fn_02430
RECT Clip(const RECT& rectangle, const D3DSURFACE_DESC& description) {
return {
std::clamp<LONG>(rectangle.left, 0, description.Width), std::clamp<LONG>(rectangle.top, 0, description.Height),
std::clamp<LONG>(rectangle.right, 0, description.Width), std::clamp<LONG>(rectangle.bottom, 0, description.Height)
};
}
// OFFSET: 0x00570C70
// FUNCTION: fn_02437
int BitsPerPixel(D3DFORMAT format) {
switch (format) {
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
return 32;
case D3DFMT_R5G6B5:
case D3DFMT_X1R5G5B5:
case D3DFMT_A1R5G5B5:
case D3DFMT_A4R4G4B4:
return 16;
default:
return 0;
}
}
// OFFSET: 0x00570D70
// FUNCTION: fn_02441
std::uint16_t Color1555(std::uint32_t color) {
return ((color >> 16) & 0x8000) | ((color & 255) >> 3) | ((color >> 6) & 0x3E0) | ((color >> 9) & 0x7C00);
}
// INLINED
UINT AlignDimension(int value) {
const std::uint32_t dimension = value;
return dimension + ((0u - dimension) & 3);
}
}
// OFFSET: 0x00570720
// FUNCTION: fn_02427
CSurfaceDX9::CSurfaceDX9(SurfaceDX9Context& context, int width, int height)
: m_context(&context), m_width(AlignDimension(width)), m_height(AlignDimension(height)), m_surface(nullptr) {
context.device->CreateOffscreenPlainSurface(this->m_width, this->m_height, context.backBufferDescription.Format, D3DPOOL_DEFAULT, &this->m_surface, nullptr);
}
// OFFSET: 0x005707D0
// FUNCTION: fn_02428
CSurfaceDX9::CSurfaceDX9(SurfaceDX9Context& context, IDirect3DSurface9* surface) : m_context(&context) {
D3DSURFACE_DESC description;
if (FAILED(surface->GetDesc(&description))) {
this->m_width = 0;
this->m_height = 0;
this->m_surface = nullptr;
} else {
this->m_width = description.Width;
this->m_height = description.Height;
this->m_surface = surface;
surface->AddRef();
}
}
// INLINED
CSurfaceDX9::~CSurfaceDX9() {
if (this->m_surface) {
this->m_surface->Release();
this->m_surface = nullptr;
}
}
// OFFSET: 0x00570CB0
// FUNCTION: fn_02438
std::uint32_t CSurfaceDX9::Width() {
return this->m_width;
}
// OFFSET: 0x00570C60
// FUNCTION: fn_02436
std::uint32_t CSurfaceDX9::Height() {
return this->m_height;
}
// OFFSET: 0x00570A20
// FUNCTION: fn_02432
bool CSurfaceDX9::Resize(int width, int height) {
if (this->m_surface) {
this->m_surface->Release();
this->m_surface = nullptr;
}
this->m_width = AlignDimension(width);
this->m_height = AlignDimension(height);
return SUCCEEDED(this->m_context->device->CreateOffscreenPlainSurface(
this->m_width, this->m_height, this->m_context->backBufferDescription.Format, D3DPOOL_DEFAULT, &this->m_surface, nullptr
)) &&
this->m_surface;
}
// OFFSET: 0x00570CC0
// FUNCTION: fn_02439
SurfaceLock CSurfaceDX9::Lock() {
SurfaceLock output{};
D3DSURFACE_DESC description;
D3DLOCKED_RECT locked;
if (this->m_surface && SUCCEEDED(this->m_surface->GetDesc(&description)) && SUCCEEDED(this->m_surface->LockRect(&locked, nullptr, 0))) {
output.success = true;
output.pixels = locked.pBits;
output.pitch = locked.Pitch;
output.width = description.Width;
output.height = description.Height;
output.bitsPerPixel = BitsPerPixel(description.Format);
}
return output;
}
// OFFSET: 0x00570DB0
// FUNCTION: fn_02442
void CSurfaceDX9::Unlock() {
if (this->m_surface) {
this->m_surface->UnlockRect();
}
}
// OFFSET: 0x00570C30
// FUNCTION: fn_02435
bool CSurfaceDX9::GetDC(HDC* output) {
return this->m_surface && SUCCEEDED(this->m_surface->GetDC(output));
}
// OFFSET: 0x00570D50
// FUNCTION: fn_02440
void CSurfaceDX9::ReleaseDC(HDC dc) {
if (this->m_surface) {
this->m_surface->ReleaseDC(dc);
}
}
// OFFSET: 0x00570DC0
// FUNCTION: fn_02443
void CSurfaceDX9::Upload(int x, int y, int width, int height, const std::uint32_t* pixels, int, int sourceWidth) {
if (!this->m_surface || !width || !height) {
return;
}
D3DSURFACE_DESC description;
if (FAILED(this->m_surface->GetDesc(&description))) {
return;
}
RECT rectangle{x, y, x + width, y + height};
D3DLOCKED_RECT locked;
if (FAILED(this->m_surface->LockRect(&locked, &rectangle, 0))) {
return;
}
const int stride = sourceWidth ? sourceWidth : width;
if (BitsPerPixel(description.Format) == 16) {
for (int row = 0; row < height; ++row) {
auto* output = static_cast<unsigned char*>(locked.pBits) + row * locked.Pitch;
for (int column = 0; column < width; ++column) {
const std::uint32_t color = pixels[row * stride + column];
std::uint16_t value = 0;
if ((color & 0xFFFFFF) != 0xFF00FF) {
switch (description.Format) {
case D3DFMT_R5G6B5:
value = ((color & 255) >> 3) | ((color >> 5) & 0x7E0) | ((color >> 8) & 0xF800);
break;
case D3DFMT_X1R5G5B5:
case D3DFMT_A1R5G5B5:
value = Color1555(color);
break;
case D3DFMT_A4R4G4B4:
value = ((color >> 16) & 0xF000) | ((color & 255) >> 4) | ((color >> 8) & 0xF0) | ((color >> 12) & 0xF00);
break;
default:
break;
}
}
std::memcpy(output + column * sizeof(value), &value, sizeof(value));
}
}
} else if (description.Format == D3DFMT_A8R8G8B8 || description.Format == D3DFMT_X8R8G8B8) {
for (int row = 0; row < height; ++row) {
auto* output = static_cast<unsigned char*>(locked.pBits) + row * locked.Pitch;
for (int column = 0; column < width; ++column) {
const std::uint32_t color = pixels[row * stride + column];
const std::uint32_t value = (color & 0xFFFFFF) == 0xFF00FF ? 0 : color;
std::memcpy(output + column * sizeof(value), &value, sizeof(value));
}
}
}
this->m_surface->UnlockRect();
}
// OFFSET: 0x005709F0
// FUNCTION: fn_02431
void CSurfaceDX9::Fill(const RECT* rectangle, std::uint32_t color) {
if (this->m_surface) {
this->m_context->device->ColorFill(this->m_surface, rectangle, color);
}
}
// OFFSET: 0x00570AA0
// FUNCTION: fn_02433
void CSurfaceDX9::Draw(int x, int y, int width, int height, std::uint32_t) {
if (!this->m_surface) {
return;
}
D3DSURFACE_DESC description;
if (FAILED(this->m_surface->GetDesc(&description))) {
return;
}
const RECT target{x, y, x + width, y + height};
const RECT destination = Clip(target, this->m_context->backBufferDescription);
const RECT original{0, 0, destination.right - destination.left, destination.bottom - destination.top};
const RECT source = Clip(original, description);
this->m_context->device->StretchRect(this->m_surface, &source, this->m_context->backBuffer, &destination, D3DTEXF_NONE);
}
// OFFSET: 0x00570BA0
// FUNCTION: fn_02434
void CSurfaceDX9::Stretch(int x, int y, int width, int height) {
if (!this->m_surface) {
return;
}
const RECT target{x, y, x + width, y + height};
const RECT destination = Clip(target, this->m_context->backBufferDescription);
this->m_context->device->StretchRect(this->m_surface, nullptr, this->m_context->backBuffer, &destination, D3DTEXF_LINEAR);
}