#include "Render/DX7/DeviceOwnerDX7.h" #include "Render/DX7/SurfaceDX7.h" #include #include namespace { // INLINED std::uint32_t AlignDimension(int value) { const std::uint32_t dimension = value; return dimension + ((0u - dimension) & 3); } // INLINED DDSURFACEDESC2 Description(DeviceOwnerDX7& owner, DWORD width, DWORD height) { DDSURFACEDESC2 description{}; description.dwSize = sizeof(description); description.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT; description.dwWidth = width; description.dwHeight = height; description.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; description.ddpfPixelFormat = owner.primaryDescription.ddpfPixelFormat; description.ddckCKSrcBlt.dwColorSpaceLowValue = description.ddpfPixelFormat.dwRBitMask | description.ddpfPixelFormat.dwBBitMask; description.ddckCKSrcBlt.dwColorSpaceHighValue = description.ddckCKSrcBlt.dwColorSpaceLowValue; return description; } // INLINED std::uint16_t Channel(unsigned value, const DeviceOwnerDX7::Channel& channel) { return static_cast((value >> (channel.expansion & 31)) << (channel.shift & 31)); } // FUNCTION: fn_01787 std::uint16_t Color(DeviceOwnerDX7& owner, unsigned red, unsigned green, unsigned blue) { return static_cast(Channel(red, owner.red) + Channel(green, owner.green) + Channel(blue, owner.blue)); } } // OFFSET: 0x00542B50 // FUNCTION: fn_01776 CSurfaceDX7::CSurfaceDX7(DeviceOwnerDX7& owner, int width, int height) : m_owner(&owner), m_surface(nullptr), m_width(AlignDimension(width)), m_height(AlignDimension(height)) { auto description = Description(owner, this->m_width, this->m_height); owner.draw->CreateSurface(&description, &this->m_surface, nullptr); } // OFFSET: 0x00542C80 // FUNCTION: fn_01777 CSurfaceDX7::CSurfaceDX7(DeviceOwnerDX7& owner, IDirectDrawSurface7* surface) : m_owner(&owner), m_surface(nullptr), m_width(0), m_height(0) { if (surface) { DDSURFACEDESC2 description{}; description.dwSize = sizeof(description); if (SUCCEEDED(surface->GetSurfaceDesc(&description))) { this->m_width = description.dwWidth; this->m_height = description.dwHeight; this->m_surface = surface; surface->AddRef(); } } } // OFFSET: 0x00542DC0 // OFFSET: 0x00542E60 // FUNCTION: fn_01779 CSurfaceDX7::~CSurfaceDX7() { if (this->m_surface) { this->m_surface->Release(); this->m_surface = nullptr; } } // OFFSET: 0x00543360 // FUNCTION: fn_01801 std::uint32_t CSurfaceDX7::Width() { return this->m_width; } // OFFSET: 0x00543310 // FUNCTION: fn_01796 std::uint32_t CSurfaceDX7::Height() { return this->m_height; } // OFFSET: 0x00543000 // FUNCTION: fn_01784 bool CSurfaceDX7::Resize(int width, int height) { this->m_width = AlignDimension(width); this->m_height = AlignDimension(height); if (this->m_surface) { this->m_surface->Release(); this->m_surface = nullptr; } auto description = Description(*this->m_owner, this->m_width, this->m_height); return SUCCEEDED(this->m_owner->draw->CreateSurface(&description, &this->m_surface, nullptr)); } // OFFSET: 0x00543370 // FUNCTION: fn_01802 SurfaceLock CSurfaceDX7::Lock() { SurfaceLock output{}; if (this->m_surface) { DDSURFACEDESC2 description{}; if (SUCCEEDED(this->m_surface->Lock(nullptr, &description, DDLOCK_WAIT, nullptr))) { output.success = true; output.pixels = description.lpSurface; output.pitch = description.lPitch; output.width = description.dwWidth; output.height = description.dwHeight; output.bitsPerPixel = description.ddpfPixelFormat.dwRGBBitCount; } } return output; } // OFFSET: 0x00543710 // FUNCTION: fn_01804 void CSurfaceDX7::Unlock() { if (this->m_surface) { this->m_surface->Unlock(nullptr); } } // OFFSET: 0x005432A0 // FUNCTION: fn_01791 bool CSurfaceDX7::GetDC(HDC* output) { return this->m_surface && SUCCEEDED(this->m_surface->GetDC(output)); } // OFFSET: 0x00543400 // FUNCTION: fn_01803 void CSurfaceDX7::ReleaseDC(HDC dc) { if (this->m_surface) { this->m_surface->ReleaseDC(dc); } } // OFFSET: 0x00543730 // FUNCTION: fn_01805 void CSurfaceDX7::Upload(int x, int y, int width, int height, const std::uint32_t* pixels, int, int sourceWidth) { if (!this->m_surface || !width || !height) { return; } const unsigned stride = sourceWidth ? sourceWidth : width; RECT rectangle{x, y, x + width, y + height}; DDSURFACEDESC2 description{}; description.dwSize = sizeof(description); if (FAILED(this->m_surface->Lock(&rectangle, &description, DDLOCK_WAIT | DDLOCK_WRITEONLY, nullptr))) { return; } const auto transparent = Color(*this->m_owner, 255, 0, 255); auto* output = static_cast(description.lpSurface); for (int row = 0; row < height; ++row) { if (description.ddpfPixelFormat.dwRGBBitCount == 16) { for (int column = 0; column < width; ++column) { const auto pixel = pixels[column]; const auto value = Color(*this->m_owner, (pixel >> 16) & 255, (pixel >> 8) & 255, pixel & 255); if (value != transparent) { std::memcpy(output + column * sizeof(value), &value, sizeof(value)); } } } else { for (int column = 0; column < width; ++column) { if ((pixels[column] & 0xFFFFFF) != 0xFF00FF) { const std::uint32_t value = pixels[column]; std::memcpy(output + column * sizeof(value), &value, sizeof(value)); } } } output += description.lPitch; pixels += stride; } this->m_surface->Unlock(nullptr); } // OFFSET: 0x00542F70 // FUNCTION: fn_01783 void CSurfaceDX7::Fill(const RECT* rectangle, std::uint32_t color) { if (this->m_surface) { DDBLTFX effects; effects.dwSize = sizeof(effects); effects.dwFillColor = Color(*this->m_owner, color & 255, (color >> 8) & 255, (color >> 16) & 255); this->m_surface->Blt(const_cast(rectangle), nullptr, nullptr, DDBLT_COLORFILL | DDBLT_WAIT, &effects); } } // OFFSET: 0x005430F0 // FUNCTION: fn_01785 void CSurfaceDX7::Draw(int x, int y, int width, int height, std::uint32_t) { RECT source{0, 0, width, height}; const int right = x + width; const int bottom = y + height; if (right > static_cast(this->m_owner->width)) { source.right = this->m_owner->width - x; } if (bottom > static_cast(this->m_owner->height)) { source.bottom = this->m_owner->height - y; } source.left = x < 0 ? -x : 0; source.top = y < 0 ? -y : 0; if (source.right > source.left && source.bottom > source.top) { this->m_owner->renderTarget->BltFast(std::max(x, 0), std::max(y, 0), this->m_surface, &source, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); } } // OFFSET: 0x005431C0 // FUNCTION: fn_01786 void CSurfaceDX7::Stretch(int, int, int width, int height) { RECT destination{0, 0, width, height}; this->m_owner->renderTarget->Blt(&destination, this->m_surface, nullptr, DDBLT_WAIT, nullptr); } // FUNCTION: fn_01788 DWORD DeviceOwnerDX7::BlueMask() { return this->blueMask; } // FUNCTION: fn_01789 DWORD DeviceOwnerDX7::BlueExpansion() { return this->blue.expansion; } // FUNCTION: fn_01790 DWORD DeviceOwnerDX7::BlueShift() { return this->blue.shift; } // FUNCTION: fn_01792 IDirectDraw7* DeviceOwnerDX7::DirectDraw() { return this->draw; } // FUNCTION: fn_01793 DWORD DeviceOwnerDX7::GreenMask() { return this->greenMask; } // FUNCTION: fn_01794 DWORD DeviceOwnerDX7::GreenExpansion() { return this->green.expansion; } // FUNCTION: fn_01795 DWORD DeviceOwnerDX7::GreenShift() { return this->green.shift; } // FUNCTION: fn_01797 DWORD DeviceOwnerDX7::RedMask() { return this->redMask; } // FUNCTION: fn_01798 DWORD DeviceOwnerDX7::RedExpansion() { return this->red.expansion; } // FUNCTION: fn_01799 DWORD DeviceOwnerDX7::RedShift() { return this->red.shift; } // FUNCTION: fn_01800 IDirectDrawSurface7* DeviceOwnerDX7::RenderTarget() { return this->renderTarget; } // OFFSET: 0x00542D60 // FUNCTION: fn_01778 CSurfaceWallpaperDX7::CSurfaceWallpaperDX7(DeviceOwnerDX7& owner, int width, int height) : CSurfaceDX7(owner, width, height) { } // OFFSET: 0x00543990 // FUNCTION: fn_01806 void CSurfaceWallpaperDX7::Upload(int, int, int width, int height, const std::uint32_t* pixels, int, int) { CSurfaceDX7 temporary(*this->m_owner, width, height); temporary.Upload(0, 0, width, height, pixels, 0, 0); this->m_surface->Blt(nullptr, temporary.m_surface, nullptr, DDBLT_WAIT, nullptr); }