#include "Render/DX7/DeviceOwnerDX7.h" #include "Render/Primitives/RenderPrimitive.h" #include "Render/DX7/SurfaceDX7.h" #include "Render/DX7/TextureDX7.h" #include #include namespace { // INLINED unsigned Component(unsigned pixel, DWORD mask, const DeviceOwnerDX7::Channel& channel) { return ((pixel & mask) >> channel.shift) << channel.expansion; } } // OFFSET: 0x0054B040 // FUNCTION: fn_01905 bool DeviceOwnerDX7::CalibrateTextureCoordinates() { const std::uint32_t pattern[16] = {0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0}; CSurfaceDX7 readback(*this, this->width, this->height); CTextureDX7 texture(*this, 4, 4, TextureFormat::A1R5G5B5); texture.Upload(0, 0, 4, 4, pattern, 0, 0); this->device->SetRenderState(D3DRENDERSTATE_ALPHATESTENABLE, 0); this->device->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, 0); this->device->SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE); this->device->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); this->device->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); this->device->SetTexture(0, texture.NativeSurface()); unsigned first = 0; const unsigned columns = this->width >> 2; const unsigned capacity = columns * (this->height >> 2); int bestScore = -1024; int best = 32896; do { this->device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0, 1, 0); if (FAILED(this->device->BeginScene())) { return false; } for (unsigned index = 0; index < capacity; ++index) { const int candidate = first + index; if (candidate > 65535) { break; } const int left = 4 * (index % columns); const int top = 4 * (index / columns); const float offsetX = static_cast(candidate % 256) * (1.0f / 256.0f); const float offsetY = static_cast(candidate / 256) * (1.0f / 256.0f); const float u0 = (offsetX + 0.0f) / static_cast(texture.TextureWidth()); const float v0 = (offsetY + 0.0f) / static_cast(texture.TextureHeight()); const float u1 = (offsetX + 4.0f) / static_cast(texture.TextureWidth()); const float v1 = (offsetY + 4.0f) / static_cast(texture.TextureHeight()); constexpr float z = 0.00001f; constexpr float rhw = 0.99999f; RenderVertex vertices[4] = { {static_cast(left), static_cast(top), z, rhw, 0xFFFFFFFF, 0xFFFFFFFF, u0, v0}, {static_cast(left), static_cast(top + 4), z, rhw, 0xFFFFFFFF, 0xFFFFFFFF, u0, v1}, {static_cast(left + 4), static_cast(top), z, rhw, 0xFFFFFFFF, 0xFFFFFFFF, u1, v0}, {static_cast(left + 4), static_cast(top + 4), z, rhw, 0xFFFFFFFF, 0xFFFFFFFF, u1, v1} }; this->device->DrawPrimitive(D3DPT_TRIANGLESTRIP, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1, vertices, 4, 0); } this->device->EndScene(); readback.m_surface->Blt(nullptr, this->renderTarget, nullptr, DDBLT_WAIT, nullptr); DDSURFACEDESC2 locked = {sizeof(DDSURFACEDESC2)}; if (FAILED(readback.m_surface->Lock(nullptr, &locked, DDLOCK_WAIT, nullptr))) { return false; } const unsigned pixelBytes = locked.ddpfPixelFormat.dwRGBBitCount >> 3; for (unsigned index = 0; index < capacity; ++index) { const int candidate = first + index; if (candidate > 65535) { break; } const unsigned x = 4 * (index % columns); const unsigned y = 4 * (index / columns); int dark = 0; int bright = 0; for (int sample = 0; sample < 16; ++sample) { const auto* source = static_cast(locked.lpSurface) + (y + sample / 4) * locked.lPitch + (x + sample % 4) * pixelBytes; unsigned pixel; if (pixelBytes == 2) { std::uint16_t value; std::memcpy(&value, source, 2); pixel = value; } else { std::memcpy(&pixel, source, 4); } pixel = static_cast(pixel); const int value = Component(pixel, this->greenMask, this->green) + Component(pixel, this->blueMask, this->blue) + Component(pixel, this->redMask, this->red); if (pattern[sample] == 0) { dark += value; } else { bright += value; } } if (bright >= 5760 && dark <= 384 && bright - dark > bestScore) { bestScore = bright - dark; best = candidate; } } readback.m_surface->Unlock(nullptr); first += capacity; } while (first < 65536); g_textureOffsetX = static_cast(best % 256) * (1.0f / 256.0f); g_textureOffsetY = static_cast(best / 256) * (1.0f / 256.0f); this->device->SetTextureStageState(0, D3DTSS_MINFILTER, D3DTFN_LINEAR); this->device->SetTextureStageState(0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); return true; }