rodecomp/Source/Render/DX7/DeviceOwnerDX7.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

588 lines
18 KiB
C++

#include "Render/DX7/DeviceOwnerDX7.h"
#include <cstring>
namespace {
// INLINED
HRESULT DeviceError(unsigned code) {
return static_cast<HRESULT>(0x82000000u | code);
}
// OFFSET: 0x00548C00
// FUNCTION: fn_01862
DDSURFACEDESC2 SurfaceDescription(DWORD flags, DWORD caps) {
DDSURFACEDESC2 result{};
result.dwSize = sizeof(result);
result.dwFlags = flags;
result.ddsCaps.dwCaps = caps;
result.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
return result;
}
// OFFSET: 0x0054AA50
// FUNCTION: fn_01900
RECT ClientRectangle(HWND window, const RECT& monitor) {
RECT result;
GetClientRect(window, &result);
POINT point{result.left, result.top};
ClientToScreen(window, &point);
result.left = point.x - monitor.left;
result.top = point.y - monitor.top;
point = {result.right, result.bottom};
ClientToScreen(window, &point);
result.right = point.x - monitor.left;
result.bottom = point.y - monitor.top;
return result;
}
// OFFSET: 0x0054A970
// FUNCTION: fn_01899
HRESULT CALLBACK SelectDepthFormat(DDPIXELFORMAT* candidate, void* context) {
auto* selected = static_cast<DDPIXELFORMAT*>(context);
if (!candidate || !selected) {
return D3DENUMRET_CANCEL;
}
if (candidate->dwFlags != selected->dwFlags || candidate->dwZBufferBitDepth <= selected->dwZBufferBitDepth) {
return D3DENUMRET_OK;
}
*selected = *candidate;
return candidate->dwZBufferBitDepth < 32 ? D3DENUMRET_OK : D3DENUMRET_CANCEL;
}
// INLINED
void ChannelMask(DeviceOwnerDX7::Channel& channel, DWORD mask) {
channel = {0, 8};
if (!mask) {
return;
}
while (!(mask & 1)) {
++channel.shift;
mask >>= 1;
}
do {
--channel.expansion;
mask >>= 1;
} while (mask);
}
// INLINED
HRESULT SurfaceError(HRESULT status, unsigned code) {
return status == DDERR_OUTOFVIDEOMEMORY ? status : DeviceError(code);
}
}
// OFFSET: 0x005493B0
// FUNCTION: fn_01888
DeviceOwnerDX7::DeviceOwnerDX7()
: window(nullptr), width(0), height(0), primary(nullptr), backBuffer(nullptr), renderTarget(nullptr), depthBuffer(nullptr), draw(nullptr),
direct3D(nullptr), device(nullptr), depthMemory(0), fullscreen(0), presentationOption(0), captureSurface(nullptr), red{0, 8}, green{0, 8}, blue{0, 8},
alpha{0, 8}, bitDepth(0), redMask(0), greenMask(0), blueMask(0), alphaMask(0), surfacesLost(false) {
}
// OFFSET: 0x005498A0
// FUNCTION: fn_01894
HRESULT DeviceOwnerDX7::CreateSurfaces(const DDSURFACEDESC2* mode, DWORD flags, const RECT& monitor) {
const bool buffered = (flags & 2) != 0;
DDSURFACEDESC2 description = SurfaceDescription(DDSD_CAPS, 0);
HRESULT status;
if (flags & 1) {
SetRect(&this->source, 0, 0, mode->dwWidth, mode->dwHeight);
this->width = this->source.right;
this->height = this->source.bottom;
this->destination = this->source;
const DWORD modeFlags = this->width == 320 && this->height == 200 && mode->ddpfPixelFormat.dwRGBBitCount == 8 ? DDSDM_STANDARDVGAMODE : 0;
if (FAILED(this->draw->SetDisplayMode(this->width, this->height, mode->ddpfPixelFormat.dwRGBBitCount, mode->dwRefreshRate, modeFlags))) {
return DeviceError(9);
}
description.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
if (buffered) {
description.dwFlags |= DDSD_BACKBUFFERCOUNT;
description.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;
description.dwBackBufferCount = 1;
}
status = this->draw->CreateSurface(&description, &this->primary, nullptr);
if (FAILED(status)) {
return SurfaceError(status, 7);
}
if (buffered) {
DDSCAPS2 caps{DDSCAPS_BACKBUFFER};
status = this->primary->GetAttachedSurface(&caps, &this->backBuffer);
if (FAILED(status)) {
return SurfaceError(status, 10);
}
}
} else {
GetClientRect(this->window, &this->source);
this->width = this->source.right;
this->height = this->source.bottom;
this->destination = ClientRectangle(this->window, monitor);
description.ddsCaps.dwCaps = buffered ? DDSCAPS_PRIMARYSURFACE : DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
status = this->draw->CreateSurface(&description, &this->primary, nullptr);
if (FAILED(status)) {
return SurfaceError(status, 7);
}
}
IDirectDrawClipper* clipper;
if (FAILED(this->draw->CreateClipper(0, &clipper, nullptr))) {
return DeviceError(8);
}
clipper->SetHWnd(0, this->window);
this->primary->SetClipper(clipper);
if (clipper) {
clipper->Release();
}
if (!(flags & 1)) {
if (buffered) {
description.dwWidth = this->width;
description.dwHeight = this->height;
description.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
description.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
status = this->draw->CreateSurface(&description, &this->backBuffer, nullptr);
if (FAILED(status)) {
return SurfaceError(status, 10);
}
} else {
POINT topLeft{this->source.left, this->source.top};
ClientToScreen(this->window, &topLeft);
this->source.left = topLeft.x;
this->source.top = topLeft.y;
POINT bottomRight{this->source.right, this->source.bottom};
ClientToScreen(this->window, &bottomRight);
this->source.right = bottomRight.x;
this->source.bottom = bottomRight.y;
}
}
this->primaryDescription = SurfaceDescription(DDSD_CAPS, 0);
this->primary->GetSurfaceDesc(&this->primaryDescription);
const auto& format = this->primaryDescription.ddpfPixelFormat;
this->bitDepth = format.dwRGBBitCount;
this->redMask = format.dwRBitMask;
this->greenMask = format.dwGBitMask;
this->blueMask = format.dwBBitMask;
this->alphaMask = format.dwRGBAlphaBitMask;
ChannelMask(this->red, this->redMask);
ChannelMask(this->green, this->greenMask);
ChannelMask(this->blue, this->blueMask);
ChannelMask(this->alpha, this->alphaMask);
this->renderTarget = buffered ? this->backBuffer : this->primary;
this->renderTarget->AddRef();
description = SurfaceDescription(DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT, DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY);
description.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
description.dwWidth = this->width;
description.dwHeight = this->height;
status = this->draw->CreateSurface(&description, &this->captureSurface, nullptr);
return FAILED(status) ? E_OUTOFMEMORY : S_OK;
}
// OFFSET: 0x0054A000
// FUNCTION: fn_01895
HRESULT DeviceOwnerDX7::CreateDevice(GUID* drawIdentity, const GUID* renderIdentity, const DDSURFACEDESC2* mode, DWORD flags, const RECT& monitor) {
this->depthMemory =
std::memcmp(renderIdentity, &IID_IDirect3DHALDevice, sizeof(GUID)) == 0 || std::memcmp(renderIdentity, &IID_IDirect3DTnLHalDevice, sizeof(GUID)) == 0
? DDSCAPS_VIDEOMEMORY
: DDSCAPS_SYSTEMMEMORY;
if (FAILED(DirectDrawCreateEx(drawIdentity, reinterpret_cast<void**>(&this->draw), IID_IDirectDraw7, nullptr))) {
return DeviceError(1);
}
auto description = SurfaceDescription(0, 0);
this->draw->GetDisplayMode(&description);
this->desktopBitDepth = description.ddpfPixelFormat.dwRGBBitCount;
DWORD cooperative = this->fullscreen ? DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE : DDSCL_NORMAL;
if (!(flags & 16)) {
cooperative |= DDSCL_FPUSETUP;
}
if (FAILED(this->draw->SetCooperativeLevel(this->window, cooperative | DDSCL_MULTITHREADED))) {
return DeviceError(2);
}
const HRESULT status = this->CreateSurfaces(mode, flags, monitor);
if (FAILED(status)) {
return status;
}
if (renderIdentity) {
if (FAILED(this->draw->QueryInterface(IID_IDirect3D7, reinterpret_cast<void**>(&this->direct3D)))) {
return DeviceError(3);
}
if (FAILED(this->direct3D->CreateDevice(*renderIdentity, this->renderTarget, &this->device))) {
return DeviceError(4);
}
D3DVIEWPORT7 viewport{0, 0, this->width, this->height, 0.0f, 1.0f};
if (FAILED(this->device->SetViewport(&viewport))) {
return DeviceError(6);
}
this->depthFormat = {};
this->depthFormat.dwFlags = DDPF_ZBUFFER | ((flags & 8) ? DDPF_STENCILBUFFER : 0);
this->direct3D->EnumZBufferFormats(*renderIdentity, SelectDepthFormat, &this->depthFormat);
if (this->depthFormat.dwSize != sizeof(this->depthFormat)) {
return DeviceError(5);
}
this->device->GetCaps(&this->caps);
if (!(this->caps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR)) {
description = SurfaceDescription(DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT, this->depthMemory | DDSCAPS_ZBUFFER);
description.dwWidth = this->width;
description.dwHeight = this->height;
description.ddpfPixelFormat = this->depthFormat;
const HRESULT depthStatus = this->draw->CreateSurface(&description, &this->depthBuffer, nullptr);
if (FAILED(depthStatus)) {
return SurfaceError(depthStatus, 5);
}
if (FAILED(this->renderTarget->AddAttachedSurface(this->depthBuffer)) || FAILED(this->device->SetRenderTarget(this->renderTarget, 0))) {
return DeviceError(5);
}
}
}
return S_OK;
}
// OFFSET: 0x0054A7D0
// FUNCTION: fn_01897
HRESULT DeviceOwnerDX7::Close() {
ULONG deviceReferences = 0;
if (this->device) {
deviceReferences = this->device->Release();
if (static_cast<std::int32_t>(deviceReferences) > 0) {
do {
deviceReferences = this->device->Release();
} while (deviceReferences);
}
}
this->device = nullptr;
if (!this->fullscreen && this->backBuffer) {
this->backBuffer->Release();
this->backBuffer = nullptr;
}
if (this->depthBuffer) {
this->depthBuffer->Release();
this->depthBuffer = nullptr;
}
if (this->renderTarget) {
this->renderTarget->Release();
this->renderTarget = nullptr;
}
if (this->primary) {
this->primary->Release();
this->primary = nullptr;
}
if (this->direct3D) {
this->direct3D->Release();
this->direct3D = nullptr;
}
if (this->captureSurface) {
this->captureSurface->Release();
this->captureSurface = nullptr;
}
ULONG drawReferences = 0;
if (this->draw) {
this->draw->SetCooperativeLevel(this->window, DDSCL_NORMAL);
drawReferences = this->draw->Release();
}
this->draw = nullptr;
return drawReferences || deviceReferences ? DeviceError(11) : S_OK;
}
// OFFSET: 0x0054AAD0
// FUNCTION: fn_01901
HRESULT DeviceOwnerDX7::Initialize(
HWND value, GUID* drawIdentity, const GUID* renderIdentity, const DDSURFACEDESC2* mode, DWORD flags, HWND applicationWindow, const RECT& monitor
) {
this->window = value;
if (!value || !renderIdentity || (!mode && (flags & 1))) {
return E_INVALIDARG;
}
this->fullscreen = flags & 1;
if (this->fullscreen) {
SetWindowLongA(applicationWindow, GWL_STYLE, static_cast<LONG>(WS_POPUP));
ShowWindow(applicationWindow, SW_MAXIMIZE);
}
const HRESULT status = this->CreateDevice(drawIdentity, renderIdentity, mode, flags, monitor);
if (FAILED(status)) {
this->Close();
if (status == E_FAIL) {
return DeviceError(0);
}
}
if (this->device) {
const struct {
D3DRENDERSTATETYPE state;
DWORD value;
} states[] = {
{D3DRENDERSTATE_CULLMODE, D3DCULL_NONE},
{D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL},
{D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE},
{D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATEREQUAL},
{D3DRENDERSTATE_ALPHAREF, 240},
{D3DRENDERSTATE_COLORKEYENABLE, TRUE},
{D3DRENDERSTATE_ZENABLE, D3DZB_TRUE},
{D3DRENDERSTATE_ZWRITEENABLE, TRUE},
{D3DRENDERSTATE_SRCBLEND, D3DBLEND_SRCALPHA},
{D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA}
};
for (const auto& state : states) {
this->device->SetRenderState(state.state, state.value);
}
const struct {
DWORD stage;
D3DTEXTURESTAGESTATETYPE state;
DWORD value;
} stages[] = {{0, D3DTSS_TEXCOORDINDEX, 0}, {0, D3DTSS_COLOROP, D3DTOP_MODULATE},
{0, D3DTSS_COLORARG1, D3DTA_TEXTURE}, {0, D3DTSS_COLORARG2, D3DTA_DIFFUSE},
{0, D3DTSS_ALPHAOP, D3DTOP_MODULATE}, {0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE},
{0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE}, {1, D3DTSS_TEXCOORDINDEX, 1},
{1, D3DTSS_COLORARG1, D3DTA_TEXTURE}, {1, D3DTSS_COLOROP, D3DTOP_MODULATEALPHA_ADDCOLOR},
{1, D3DTSS_COLORARG2, D3DTA_CURRENT}, {1, D3DTSS_ALPHAOP, D3DTOP_DISABLE},
{2, D3DTSS_COLOROP, D3DTOP_DISABLE}, {2, D3DTSS_ALPHAOP, D3DTOP_DISABLE},
{0, D3DTSS_MAGFILTER, D3DTFG_LINEAR}, {0, D3DTSS_MINFILTER, D3DTFN_LINEAR},
{1, D3DTSS_MAGFILTER, D3DTFG_LINEAR}, {1, D3DTSS_MINFILTER, D3DTFN_LINEAR},
{0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP}, {1, D3DTSS_ADDRESS, D3DTADDRESS_BORDER},
{1, D3DTSS_BORDERCOLOR, 0xFF000000}};
for (const auto& state : stages) {
this->device->SetTextureStageState(state.stage, state.state, state.value);
}
}
return status;
}
// OFFSET: 0x005496D0
// FUNCTION: fn_01892
HRESULT DeviceOwnerDX7::Clear(DWORD color) {
D3DRECT rectangle{0, 0, static_cast<LONG>(this->width), static_cast<LONG>(this->height)};
return this->device->Clear(1, &rectangle, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1.0f, 0);
}
// OFFSET: 0x00549730
// FUNCTION: fn_01893
HRESULT DeviceOwnerDX7::ClearDepth() {
D3DRECT rectangle{0, 0, static_cast<LONG>(this->width), static_cast<LONG>(this->height)};
return this->device->Clear(1, &rectangle, D3DCLEAR_ZBUFFER, 0, 1.0f, 0);
}
// OFFSET: 0x0054AF10
// FUNCTION: fn_01903
void DeviceOwnerDX7::MarkSurfacesLost() {
this->surfacesLost = true;
}
// OFFSET: 0x005495C0
// FUNCTION: fn_01891
bool DeviceOwnerDX7::RestoreLostSurfaces() {
if (!this->surfacesLost) {
return false;
}
const HRESULT primaryStatus = this->primary->IsLost();
const HRESULT depthStatus = this->depthBuffer ? this->depthBuffer->IsLost() : S_OK;
if (primaryStatus == DDERR_SURFACELOST && depthStatus == DDERR_SURFACELOST) {
if (this->depthBuffer) {
this->depthBuffer->Restore();
}
this->draw->RestoreAllSurfaces();
this->surfacesLost = false;
}
return true;
}
// OFFSET: 0x0054AF20
// FUNCTION: fn_01904
HRESULT DeviceOwnerDX7::Present(bool wait, const RECT& monitor) {
if (!this->primary) {
return DeviceError(14);
}
if (!this->backBuffer) {
return this->primary->IsLost();
}
if (wait && (!this->fullscreen || this->presentationOption)) {
this->destination = ClientRectangle(this->window, monitor);
this->draw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, nullptr);
return this->primary->Blt(&this->destination, this->backBuffer, &this->source, DDBLT_WAIT, nullptr);
}
GetClientRect(this->window, &this->destination);
POINT topLeft{this->destination.left, this->destination.top};
ClientToScreen(this->window, &topLeft);
this->destination.left = topLeft.x;
this->destination.top = topLeft.y;
POINT bottomRight{this->destination.right, this->destination.bottom};
ClientToScreen(this->window, &bottomRight);
this->destination.right = bottomRight.x;
this->destination.bottom = bottomRight.y;
if (wait) {
this->draw->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, nullptr);
return this->primary->Blt(nullptr, this->backBuffer, nullptr, DDBLT_WAIT, nullptr);
}
return this->primary->Blt(&this->destination, this->backBuffer, &this->source, DDBLT_WAIT, nullptr);
}
// OFFSET: 0x005494C0
// FUNCTION: fn_01890
void DeviceOwnerDX7::AdjustTextureDimensions(std::uint32_t& width, std::uint32_t& height) const {
std::uint32_t selectedWidth = 1;
while (selectedWidth < width) {
selectedWidth *= 2;
}
if (selectedWidth < this->minTextureWidth) {
selectedWidth = this->minTextureWidth;
}
if (selectedWidth > this->maxTextureWidth) {
selectedWidth = this->maxTextureWidth;
}
std::uint32_t selectedHeight = 1;
while (selectedHeight < height) {
selectedHeight *= 2;
}
if (selectedHeight < this->minTextureHeight) {
selectedHeight = this->minTextureHeight;
}
if (selectedHeight > this->maxTextureHeight) {
selectedHeight = this->maxTextureHeight;
}
const auto aspect = this->maxTextureAspectRatio;
if (aspect) {
if (selectedWidth / selectedHeight > aspect) {
selectedHeight = selectedWidth / aspect;
}
if (selectedHeight / selectedWidth > aspect) {
selectedWidth = selectedHeight / aspect;
}
}
width = selectedWidth;
height = selectedHeight;
}
// OFFSET: 0x0054AE50
// FUNCTION: fn_01902
bool DeviceOwnerDX7::SupportsTextureDimensions(std::uint32_t width, std::uint32_t height) const {
return this->minTextureWidth <= width && width <= this->maxTextureWidth && this->minTextureHeight <= height && height <= this->maxTextureHeight;
}
// OFFSET: 0x0056B890
// FUNCTION: fn_02324
void DeviceOwnerDX7::PrepareErrorDialog() {
if (this->direct3D) {
this->direct3D->EvictManagedTextures();
}
}
// OFFSET: 0x0056B8B0
// FUNCTION: fn_02325
void DeviceOwnerDX7::RestoreDisplayMode() {
if (this->draw) {
if (this->backBuffer) {
this->backBuffer->Unlock(nullptr);
}
if (this->primary) {
this->primary->Unlock(nullptr);
}
this->draw->FlipToGDISurface();
}
}
// OFFSET: 0x0056C4B0
// FUNCTION: fn_02336
HRESULT DeviceOwnerDX7::RestoreAllSurfaces() {
return this->draw->RestoreAllSurfaces();
}
// OFFSET: 0x0054A8D0
// FUNCTION: fn_45420
void DeviceOwnerDX7::SetDialogClipper(int enabled) {
if (!this->fullscreen) {
return;
}
IDirectDrawClipper* clipper = nullptr;
if (enabled == 1) {
this->draw->CreateClipper(0, &clipper, nullptr);
clipper->SetHWnd(0, this->window);
}
this->primary->SetClipper(clipper);
if (clipper) {
clipper->Release();
}
}