From 9fc5476ef7554773ab8aad5139de8f888ef5fc01 Mon Sep 17 00:00:00 2001 From: superp00t Date: Fri, 6 Sep 2024 12:32:50 -0400 Subject: [PATCH] feat(gx): add broken cursor drawing implementation --- src/gx/Buffer.cpp | 4 + src/gx/Buffer.hpp | 2 + src/gx/CGxCaps.hpp | 1 + src/gx/CGxDevice.cpp | 234 +++++++++++++++++++++++++++++- src/gx/CGxDevice.hpp | 19 +++ src/gx/CGxFormat.hpp | 2 + src/gx/Transform.cpp | 5 + src/gx/Transform.hpp | 2 + src/gx/Types.hpp | 15 +- src/gx/d3d/CGxDeviceD3d.cpp | 126 +++++++++++++++- src/gx/d3d/CGxDeviceD3d.hpp | 8 + src/gx/gll/CGxDeviceGLL.cpp | 2 + src/gx/glsdl/CGxDeviceGLSDL.cpp | 18 ++- src/gx/glsdl/CGxDeviceGLSDL.hpp | 1 + src/gx/glsdl/GLSDLWindow.cpp | 250 -------------------------------- src/gx/glsdl/GLSDLWindow.hpp | 7 - 16 files changed, 423 insertions(+), 273 deletions(-) diff --git a/src/gx/Buffer.cpp b/src/gx/Buffer.cpp index 94dd527..55a4950 100644 --- a/src/gx/Buffer.cpp +++ b/src/gx/Buffer.cpp @@ -188,6 +188,10 @@ uint32_t GxVertexAttribOffset(EGxVertexBufferFormat format, EGxVertexAttrib attr return Buffer::s_vertexBufOffset[format][attrib]; } +CGxBuf* GxBufStream(EGxPoolTarget target, uint32_t itemSize, uint32_t itemCount) { + return g_theGxDevicePtr->BufStream(target, itemSize, itemCount); +} + CGxBuf* GxBufCreate(CGxPool* pool, uint32_t itemSize, uint32_t itemCount, uint32_t index) { return g_theGxDevicePtr->BufCreate(pool, itemSize, itemCount, index); } diff --git a/src/gx/Buffer.hpp b/src/gx/Buffer.hpp index 529dfcd..55a0b9c 100644 --- a/src/gx/Buffer.hpp +++ b/src/gx/Buffer.hpp @@ -25,6 +25,8 @@ namespace Buffer { uint32_t GxVertexAttribOffset(EGxVertexBufferFormat, EGxVertexAttrib); +CGxBuf* GxBufStream(EGxPoolTarget target, uint32_t itemSize, uint32_t itemCount); + CGxBuf* GxBufCreate(CGxPool*, uint32_t, uint32_t, uint32_t); void GxBufData(CGxBuf* buf, const void* data, uint32_t size, uint32_t offset); diff --git a/src/gx/CGxCaps.hpp b/src/gx/CGxCaps.hpp index 6a9b0f4..0797ca8 100644 --- a/src/gx/CGxCaps.hpp +++ b/src/gx/CGxCaps.hpp @@ -22,6 +22,7 @@ class CGxCaps { int32_t m_texFilterAnisotropic = 0; uint32_t m_maxTexAnisotropy = 0; int32_t m_depthBias = 0; + int32_t m_hardwareCursor = 0; int32_t int130 = 1; int32_t int134 = 0; int32_t int138 = 0; diff --git a/src/gx/CGxDevice.cpp b/src/gx/CGxDevice.cpp index 9017624..594b884 100644 --- a/src/gx/CGxDevice.cpp +++ b/src/gx/CGxDevice.cpp @@ -2,10 +2,16 @@ #include "gx/Gx.hpp" #include "gx/Shader.hpp" #include "gx/texture/CGxTex.hpp" +#include "gx/Texture.hpp" +#include "gx/RenderState.hpp" +#include "gx/Transform.hpp" +#include "gx/Draw.hpp" #include "util/SFile.hpp" +#include "event/Input.hpp" #include #include #include +#include #include #include #include @@ -97,6 +103,9 @@ uint32_t CGxDevice::s_texFormatBytesPerBlock[] = { 4 // GxTex_D24X8 }; +CGxShader* CGxDevice::s_uiVertexShader = nullptr; +CGxShader* CGxDevice::s_uiPixelShader = nullptr; + void CGxDevice::Log(const char* format, ...) { // TODO } @@ -144,6 +153,16 @@ uint32_t CGxDevice::PrimCalcCount(EGxPrim primType, uint32_t count) { return count - CGxDevice::s_primVtxAdjust[primType]; } +void CGxDevice::ICursorUpdate(EGxTexCommand command, uint32_t width, uint32_t height, uint32_t face, uint32_t level, void* userArg, uint32_t& texelStrideInBytes, const void*& texels) { + // TODO + if (command == GxTex_Latch) { + auto device = static_cast(userArg); + + texelStrideInBytes = 0x80; + texels = device->m_cursor; + } +} + CGxDevice::CGxDevice() { // TODO // - implement rest of constructor @@ -264,7 +283,201 @@ const CRect& CGxDevice::DeviceDefWindow() { } void CGxDevice::ICursorCreate(const CGxFormat& format) { - // TODO + int32_t hardwareCursor = format.hwCursor && this->m_caps.m_hardwareCursor; + + this->m_hardwareCursor = hardwareCursor; + + // If hardware cursor is disabled, and there is no cursor texture yet, create one + if (!hardwareCursor && this->m_cursorTexture == nullptr) { + // default flags? + CGxTexFlags cursorTextureFlags; + + // Create a 32x32 cursor texture + GxTexCreate( + 32, + 32, + GxTex_Argb8888, + cursorTextureFlags, + reinterpret_cast(this), + CGxDevice::ICursorUpdate, + this->m_cursorTexture + ); + } +} + +void CGxDevice::ICursorDestroy() { + if (this->m_cursorTexture) { + GxTexDestroy(this->m_cursorTexture); + this->m_cursorTexture = nullptr; + } +} + +void CGxDevice::ICursorDraw() { + if (!this->m_cursorVisible) { + return; + } + + if (this->m_hardwareCursor) { + return; + } + + int32_t mouseX; + int32_t mouseY; + OsInputGetMousePosition(&mouseX, &mouseY); + + if (mouseX <= -1 || mouseY <= -1 || mouseX >= this->m_curWindowRect.maxX || mouseY >= this->m_curWindowRect.maxY) { + return; + } + + GxRsPush(); + // Turn off everything + GxRsSet(GxRs_PolygonOffset, 0); + GxRsSet(GxRs_NormalizeNormals, 0); + GxRsSet(GxRs_BlendingMode, 1); + GxRsSetAlphaRef(); + GxRsSet(GxRs_Lighting, 0); + GxRsSet(GxRs_Fog, 0); + GxRsSet(GxRs_DepthTest, 0); + GxRsSet(GxRs_DepthWrite, 0); + GxRsSet(GxRs_ColorWrite, 15); + GxRsSet(GxRs_Culling, 0); + GxRsSet(GxRs_ClipPlaneMask, 0); + GxRsSet(GxRs_Texture0, this->m_cursorTexture); + GxRsSet(GxRs_Texture1, static_cast(nullptr)); + GxRsSet(GxRs_ColorOp0, 0); + GxRsSet(GxRs_AlphaOp0, 0); + GxRsSet(GxRs_TexGen0, 0); + GxRsSet(GxRs_Unk61, 0); + + C44Matrix identity; + GxXformPush(GxXform_World, identity); + + float cursorDepth = 1.0f; + + C44Matrix projection; + + if (!this->StereoEnabled() || + (CGxDevice::s_uiVertexShader == 0 || !s_uiVertexShader->Valid()) || + (CGxDevice::s_uiPixelShader == 0 || !s_uiPixelShader->Valid())) { + // Disable shaders + GxRsSet(GxRs_VertexShader, static_cast(nullptr)); + GxRsSet(GxRs_PixelShader, static_cast(nullptr)); + } else { + cursorDepth = this->m_cursorDepth; + + float minX, maxX, minY, maxY, minZ, maxZ; + GxXformViewport(minX, maxX, minY, maxY, minZ, maxZ); + + GxXformProjection(projection); + + C44Matrix mProj; + mProj.a0 = 2.0f / (maxX - minX); + mProj.b0 = 0.0f; + mProj.c0 = 0.0f; + mProj.d0 = -((minX + maxX) / (maxX - minX)); + mProj.a1 = 0.0f; + mProj.b1 = 2.0f / (maxY - minY); + mProj.c1 = 0.0f; + mProj.d1 = -((minY + maxY) / (maxY - minY)); + mProj.a2 = 0.0f; + mProj.b2 = 0.0f; + mProj.c2 = 1.00008f; + mProj.d2 = -0.400016f; + mProj.a3 = 0.0f; + mProj.b3 = 0.0f; + mProj.c3 = 1.0f; + mProj.d3 = 0.0f; + GxXformSetProjection(mProj); + + GxRsSet(GxRs_VertexShader, CGxDevice::s_uiVertexShader); + GxRsSet(GxRs_PixelShader, CGxDevice::s_uiPixelShader); + + C44Matrix transposition; + GxXformProjNativeTranspose(transposition); + GxShaderConstantsSet(GxSh_Vertex, 0, reinterpret_cast(&transposition), 0); + } + + auto buffer = GxBufStream(GxPoolTarget_Vertex, sizeof(CGxVertexPCT), 4); + auto vertices = reinterpret_cast(GxBufLock(buffer)); + + if (!vertices) { + return; + } + + auto scaleX = this->m_curWindowRect.maxX > 0.0f ? 1.0f / this->m_curWindowRect.maxX : 0.0f; + auto scaleY = this->m_curWindowRect.maxY > 0.0f ? 1.0f / this->m_curWindowRect.maxY : 0.0f; + + mouseX -= this->m_cursorHotspotX; + mouseY -= this->m_cursorHotspotY; + + auto minX = std::fabsf(static_cast(mouseX)) * scaleX; + auto maxX = std::fabsf(static_cast(mouseX + 32)) * scaleX; + + auto minY = 1.0f - (std::fabsf(static_cast(mouseY)) * scaleY); + auto maxY = 1.0f - (std::fabsf(static_cast(mouseY + 32)) * scaleY); + + if (this->m_api == GxApi_D3d9 || this->m_api == GxApi_D3d9Ex) { + minX -= (scaleX * 0.5f); + maxX += (scaleX * 0.5f); + minY -= (scaleY * 0.5f); + maxY += (scaleY * 0.5f); + } + + // Vertex coordinates + vertices[0].p.x = minX; + vertices[0].p.y = minY; + vertices[0].p.z = cursorDepth; + + vertices[1].p.x = minX; + vertices[1].p.y = maxY; + vertices[1].p.z = cursorDepth; + + vertices[2].p.x = maxX; + vertices[2].p.y = minY; + vertices[2].p.z = cursorDepth; + + vertices[3].p.x = maxX; + vertices[3].p.y = maxY; + vertices[3].p.z = cursorDepth; + + // Color values + vertices[0].c = { 0xFF, 0xFF, 0xFF, 0xFF }; + vertices[1].c = { 0xFF, 0xFF, 0xFF, 0xFF }; + vertices[2].c = { 0xFF, 0xFF, 0xFF, 0xFF }; + vertices[3].c = { 0xFF, 0xFF, 0xFF, 0xFF }; + + // Texture coordinates + vertices[0].tc[0].x = 0.0f; + vertices[0].tc[0].y = 0.0f; + + vertices[1].tc[0].x = 0.0f; + vertices[1].tc[0].y = 1.0f; + + vertices[2].tc[0].x = 1.0f; + vertices[2].tc[0].y = 0.0f; + + vertices[3].tc[0].x = 1.0f; + vertices[3].tc[0].y = 1.0f; + + GxBufUnlock(buffer, 0); + GxPrimVertexPtr(buffer, GxVBF_PCT); + + CGxBatch batch; + batch.m_primType = GxPrim_TriangleStrip; + batch.m_count = 4; + batch.m_start = 0; + batch.m_minIndex = 0; + batch.m_maxIndex = 3; + + GxDraw(&batch, 0); + + GxXformPop(GxXform_World); + + if (this->StereoEnabled()) { + GxXformSetProjection(projection); + } + + GxRsPop(); } int32_t CGxDevice::IDevIsWindowed() { @@ -1030,6 +1243,12 @@ void CGxDevice::XformPush(EGxXform xf) { this->m_xforms[xf].Push(); } +// 1-liner for Push/Set +void CGxDevice::XformPush(EGxXform xf, const C44Matrix& matrix) { + this->m_xforms[xf].Push(); + this->m_xforms[xf].Top() = matrix; +} + void CGxDevice::XformSet(EGxXform xf, const C44Matrix& matrix) { this->m_xforms[xf].Top() = matrix; } @@ -1082,3 +1301,16 @@ void CGxDevice::XformViewport(float& minX, float& maxX, float& minY, float& maxY minZ = this->m_viewport.z.l; maxZ = this->m_viewport.z.h; } + +void CGxDevice::CursorSetVisible(int32_t visible) { + this->m_cursorVisible = visible; +} + +uint32_t* CGxDevice::CursorLock() { + return this->m_cursor; +} + +void CGxDevice::CursorUnlock(uint32_t x, uint32_t y) { + this->m_cursorHotspotX = x; + this->m_cursorHotspotY = y; +} diff --git a/src/gx/CGxDevice.hpp b/src/gx/CGxDevice.hpp index c59e3f2..be62c4b 100644 --- a/src/gx/CGxDevice.hpp +++ b/src/gx/CGxDevice.hpp @@ -8,6 +8,7 @@ #include "gx/CGxStateBom.hpp" #include "gx/Types.hpp" #include "gx/Shader.hpp" +#include "cursor/Cursor.hpp" #include #include #include @@ -46,6 +47,8 @@ class CGxDevice { static uint32_t s_streamPoolSize[]; static uint32_t s_texFormatBitDepth[]; static uint32_t s_texFormatBytesPerBlock[]; + static CGxShader* s_uiVertexShader; + static CGxShader* s_uiPixelShader; // Static functions static void Log(const char* format, ...); @@ -62,6 +65,7 @@ class CGxDevice { #endif static CGxDevice* NewOpenGl(); static uint32_t PrimCalcCount(EGxPrim primType, uint32_t count); + static void ICursorUpdate(EGxTexCommand, uint32_t, uint32_t, uint32_t, uint32_t, void*, uint32_t&, const void*&); // Member variables TSGrowableArray m_pushedStates; @@ -102,11 +106,20 @@ class CGxDevice { TSFixedArray m_appRenderStates; TSFixedArray m_hwRenderStates; uint32_t m_baseMipLevel = 0; // TODO placeholder + int32_t m_cursorVisible = 0; + int32_t m_hardwareCursor = 0; + uint32_t m_cursorHotspotX = 0; + uint32_t m_cursorHotspotY = 0; + uint32_t m_cursor[CURSOR_IMAGE_SIZE] = { 0 }; + CGxTex* m_cursorTexture = nullptr; + float m_cursorDepth = 0.0f; // Virtual member functions virtual void ITexMarkAsUpdated(CGxTex*) = 0; virtual void IRsSendToHw(EGxRenderState) = 0; virtual void ICursorCreate(const CGxFormat& format); + virtual void ICursorDestroy(); + virtual void ICursorDraw(); virtual int32_t DeviceCreate(int32_t (*windowProc)(void* window, uint32_t message, uintptr_t wparam, intptr_t lparam), const CGxFormat&); virtual int32_t DeviceSetFormat(const CGxFormat&); virtual void* DeviceWindow() = 0; @@ -130,6 +143,9 @@ class CGxDevice { virtual void ShaderConstantsSet(EGxShTarget, uint32_t, const float*, uint32_t); virtual void IShaderCreate(CGxShader*) = 0; virtual int32_t StereoEnabled(void) = 0; + virtual void CursorSetVisible(int32_t visible); + virtual uint32_t* CursorLock(); + virtual void CursorUnlock(uint32_t x, uint32_t y); // Member functions CGxDevice(); @@ -142,6 +158,7 @@ class CGxDevice { void DeviceSetCurWindow(const CRect&); void DeviceSetDefWindow(CRect const&); const CRect& DeviceDefWindow(void); + void ICursorUpdate(); int32_t IDevIsWindowed(); void IRsDirty(EGxRenderState); void IRsForceUpdate(void); @@ -173,10 +190,12 @@ class CGxDevice { void XformProjection(C44Matrix&); void XformProjNative(C44Matrix&); void XformPush(EGxXform xf); + void XformPush(EGxXform xf, const C44Matrix& matrix); void XformSet(EGxXform xf, const C44Matrix& matrix); void XformSetViewport(float, float, float, float, float, float); void XformView(C44Matrix&); void XformViewport(float&, float&, float&, float&, float&, float&); + }; #endif diff --git a/src/gx/CGxFormat.hpp b/src/gx/CGxFormat.hpp index cd64faa..8960d6b 100644 --- a/src/gx/CGxFormat.hpp +++ b/src/gx/CGxFormat.hpp @@ -21,6 +21,8 @@ class CGxFormat { // Member variables bool hwTnL; + bool hwCursor; + bool fixLag; int8_t window; int32_t maximize; Format depthFormat; diff --git a/src/gx/Transform.cpp b/src/gx/Transform.cpp index 6ee7b3e..f71680c 100644 --- a/src/gx/Transform.cpp +++ b/src/gx/Transform.cpp @@ -31,6 +31,11 @@ void GxXformPush(EGxXform xf) { g_theGxDevicePtr->XformPush(xf); } +// 1-liner for Push/Set +void GxXformPush(EGxXform xf, const C44Matrix& matrix) { + g_theGxDevicePtr->XformPush(xf, matrix); +} + void GxXformSet(EGxXform xf, const C44Matrix& matrix) { g_theGxDevicePtr->XformSet(xf, matrix); } diff --git a/src/gx/Transform.hpp b/src/gx/Transform.hpp index 66bfb13..ffdb060 100644 --- a/src/gx/Transform.hpp +++ b/src/gx/Transform.hpp @@ -16,6 +16,8 @@ void GxXformProjNativeTranspose(C44Matrix&); void GxXformPush(EGxXform xf); +void GxXformPush(EGxXform xf, const C44Matrix& matrix); + void GxXformSet(EGxXform xf, const C44Matrix& matrix); void GxXformSetProjection(const C44Matrix&); diff --git a/src/gx/Types.hpp b/src/gx/Types.hpp index ac1c11b..9e0acf6 100644 --- a/src/gx/Types.hpp +++ b/src/gx/Types.hpp @@ -339,10 +339,17 @@ enum PIXEL_FORMAT { }; struct C4Pixel { - char b; - char g; - char r; - char a; + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; +}; + +struct C4LargePixel { + uint64_t b; + uint64_t g; + uint64_t r; + uint64_t a; }; struct MipBits { diff --git a/src/gx/d3d/CGxDeviceD3d.cpp b/src/gx/d3d/CGxDeviceD3d.cpp index b0b8804..4ef458b 100644 --- a/src/gx/d3d/CGxDeviceD3d.cpp +++ b/src/gx/d3d/CGxDeviceD3d.cpp @@ -336,12 +336,7 @@ LRESULT CGxDeviceD3d::WindowProcD3d(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM if (device) { if (device->m_d3dDevice && lParam == 1) { SetCursor(nullptr); - BOOL show = TRUE; - // if (device->unk2904[0x13] == 0) || (device->.unk2904[0x14] == 0)) { - // show = FALSE; - // } else { - // show = TRUE; - // } + BOOL show = device->m_cursorVisible && device->m_hardwareCursor ? TRUE : FALSE; device->m_d3dDevice->ShowCursor(show); } } @@ -889,6 +884,8 @@ int32_t CGxDeviceD3d::ICreateD3dDevice(const CGxFormat& format) { this->IStateSetD3dDefaults(); + this->ICursorCreate(format); + // TODO return 1; @@ -1199,6 +1196,94 @@ void CGxDeviceD3d::IRsSendToHw(EGxRenderState which) { } } +void CGxDeviceD3d::ICursorCreate(const CGxFormat& format) { + CGxDevice::ICursorCreate(format); + + if (this->m_hardwareCursor && this->m_hwCursorTexture == nullptr) { + this->m_d3dDevice->CreateTexture( + 32, + 32, + 1, + 0, + D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, + &this->m_hwCursorTexture, + nullptr); + + if (this->m_hwCursorTexture) { + this->m_hwCursorTexture->GetSurfaceLevel(0, &this->m_hwCursorBitmap); + } + + this->m_hwCursorNeedsUpdate = 1; + this->ICursorDraw(); + } +} + +void CGxDeviceD3d::ICursorDestroy() { + CGxDevice::ICursorDestroy(); + + if (this->m_hwCursorBitmap) { + this->m_hwCursorBitmap->Release(); + this->m_hwCursorBitmap = nullptr; + } + + if (this->m_hwCursorTexture) { + this->m_hwCursorTexture->Release(); + this->m_hwCursorTexture = nullptr; + } +} + +void CGxDeviceD3d::CursorSetVisible(int32_t visible) { + CGxDevice::CursorSetVisible(visible); + + if (this->m_hardwareCursor && this->m_context) { + POINT point; + RECT rect; + GetCursorPos(&point); + ScreenToClient(this->m_hwnd, &point); + GetClientRect(this->m_hwnd, &rect); + + if (rect.left <= point.x && (point.x < rect.right && (rect.top <= point.y)) && point.y < rect.bottom) { + this->m_d3dDevice->ShowCursor(this->m_cursorVisible); + } + } +} + +void CGxDeviceD3d::ICursorDraw() { + if (!this->m_hardwareCursor) { + this->ISceneBegin(); + } + + CGxDevice::ICursorDraw(); + + if (!this->m_hardwareCursor) { + this->ISceneEnd(); + if (!this->m_hardwareCursor) { + return; + } + } + + if (this->m_hwCursorNeedsUpdate && this->m_hwCursorBitmap && this->m_context) { + D3DLOCKED_RECT lockedRect; + if SUCCEEDED(this->m_hwCursorBitmap->LockRect(&lockedRect, nullptr, 0)) { + // upload cursor texture data + auto src = reinterpret_cast(this->m_cursor); + + for (int32_t i = 0; i < 32; i++) { + auto dest = reinterpret_cast(lockedRect.pBits) + (lockedRect.Pitch * i); + memcpy(dest, src, 128); + src += 128; + } + + this->m_hwCursorBitmap->UnlockRect(); + + this->m_d3dDevice->SetCursorProperties(this->m_cursorHotspotX, this->m_cursorHotspotY, this->m_hwCursorBitmap); + } + + this->m_hwCursorNeedsUpdate = 0; + } +} + void CGxDeviceD3d::ISceneBegin() { if (this->m_context) { this->ShaderConstantsClear(); @@ -1303,6 +1388,10 @@ void CGxDeviceD3d::ISetCaps(const CGxFormat& format) { // TODO modify shader targets based on format + // Detect hardware cursor + + this->m_caps.m_hardwareCursor = this->m_d3dCaps.CursorCaps & D3DCURSORCAPS_COLOR; + // Texture formats for (int32_t i = 0; i < GxTexFormats_Last; i++) { @@ -1596,7 +1685,7 @@ void CGxDeviceD3d::IStateSync() { this->IShaderConstantsFlush(); this->IRsSync(0); - if (this->m_hwRenderStates[GxRs_VertexShader] == nullptr && this->m_appRenderStates[GxRs_VertexShader].m_value == nullptr) { + if (this->m_hwRenderStates[GxRs_VertexShader] == nullptr || this->m_appRenderStates[GxRs_VertexShader].m_value == nullptr) { this->IStateSyncLights(); this->IStateSyncMaterial(); this->IStateSyncXforms(); @@ -1734,7 +1823,9 @@ void CGxDeviceD3d::IStateSyncXforms() { this->m_xforms[GxXform_View].m_dirty = 0; } - // TODO world + if (this->m_xforms[GxXform_World].m_dirty) { + this->IXformSetWorld(); + } // TODO tex } @@ -1932,6 +2023,7 @@ UNLOCK: void CGxDeviceD3d::IXformSetProjection(const C44Matrix& matrix) { #if defined(_MSC_VER) + // This is the correct way DirectX::XMMATRIX projNative; memcpy(&projNative, &matrix, sizeof(projNative)); @@ -1966,6 +2058,8 @@ void CGxDeviceD3d::IXformSetProjection(const C44Matrix& matrix) { this->m_xforms[GxXform_Projection].m_dirty = 1; memcpy(&this->m_projNative, &projNative, sizeof(this->m_projNative)); #else + // Without the DirectX::XMMATRIX, we can soldier on + // with a Tempest matrix C44Matrix projNative; memcpy(&projNative, &matrix, sizeof(projNative)); @@ -2026,6 +2120,19 @@ void CGxDeviceD3d::IXformSetViewport() { this->intF6C = 0; } +void CGxDeviceD3d::IXformSetWorld() { + static int32_t isIdent = 0; + + auto& stack = this->m_xforms[GxXform_World]; + + if (!isIdent || !(stack.m_flags[stack.m_level] & CGxMatrixStack::F_Identity)) { + this->m_d3dDevice->SetTransform(D3DTS_WORLD, reinterpret_cast(&stack.TopConst())); + } + + isIdent = stack.m_flags[stack.m_level] & CGxMatrixStack::F_Identity; + stack.m_dirty = 0; +} + void CGxDeviceD3d::PoolSizeSet(CGxPool* pool, uint32_t size) { // TODO } @@ -2059,6 +2166,8 @@ void CGxDeviceD3d::ScenePresent() { CGxDevice::ScenePresent(); this->ISceneEnd(); + this->ICursorDraw(); + // TODO // TODO fixLag @@ -2092,3 +2201,4 @@ void CGxDeviceD3d::XformSetProjection(const C44Matrix& matrix) { CGxDevice::XformSetProjection(matrix); this->IXformSetProjection(matrix); } + diff --git a/src/gx/d3d/CGxDeviceD3d.hpp b/src/gx/d3d/CGxDeviceD3d.hpp index 9823083..16c9f3e 100644 --- a/src/gx/d3d/CGxDeviceD3d.hpp +++ b/src/gx/d3d/CGxDeviceD3d.hpp @@ -235,6 +235,9 @@ class CGxDeviceD3d : public CGxDevice { D3DFORMAT m_devAdapterFormat; LPDIRECT3DSURFACE9 m_defColorSurface = nullptr; LPDIRECT3DSURFACE9 m_defDepthSurface = nullptr; + int32_t m_hwCursorNeedsUpdate = 1; + LPDIRECT3DTEXTURE9 m_hwCursorTexture = nullptr; + LPDIRECT3DSURFACE9 m_hwCursorBitmap = nullptr; LPDIRECT3DVERTEXDECLARATION9 m_d3dCurrentVertexDecl; LPDIRECT3DINDEXBUFFER9 m_d3dCurrentIndexBuf; LPDIRECT3DVERTEXBUFFER9 m_d3dVertexStreamBuf[8]; @@ -245,6 +248,10 @@ class CGxDeviceD3d : public CGxDevice { // Virtual member functions virtual void ITexMarkAsUpdated(CGxTex* texId); virtual void IRsSendToHw(EGxRenderState which); + virtual void ICursorCreate(const CGxFormat& format); + virtual void ICursorDestroy(); + virtual void ICursorDraw(); + virtual void CursorSetVisible(int32_t visible); virtual int32_t DeviceCreate(int32_t (*windowProc)(void* window, uint32_t message, uintptr_t wparam, intptr_t lparam), const CGxFormat& format); virtual int32_t DeviceSetFormat(const CGxFormat& format); virtual void* DeviceWindow(); @@ -302,6 +309,7 @@ class CGxDeviceD3d : public CGxDevice { void ITexUpload(CGxTex* texId); void IXformSetProjection(const C44Matrix& matrix); void IXformSetViewport(); + void IXformSetWorld(); }; #endif diff --git a/src/gx/gll/CGxDeviceGLL.cpp b/src/gx/gll/CGxDeviceGLL.cpp index 888fac8..74cff07 100644 --- a/src/gx/gll/CGxDeviceGLL.cpp +++ b/src/gx/gll/CGxDeviceGLL.cpp @@ -703,6 +703,8 @@ void CGxDeviceGLL::ISetCaps(const CGxFormat& format) { this->m_caps.m_texMaxSize[GxTex_Rectangle] = 4096; this->m_caps.m_texMaxSize[GxTex_NonPow2] = 4096; + this->m_caps.m_hardwareCursor = 0; + // TODO } diff --git a/src/gx/glsdl/CGxDeviceGLSDL.cpp b/src/gx/glsdl/CGxDeviceGLSDL.cpp index 89f7444..d45780d 100644 --- a/src/gx/glsdl/CGxDeviceGLSDL.cpp +++ b/src/gx/glsdl/CGxDeviceGLSDL.cpp @@ -320,7 +320,7 @@ int32_t CGxDeviceGLSDL::DeviceSetFormat(const CGxFormat& format) { } void* CGxDeviceGLSDL::DeviceWindow() { - return &this->m_GLSDLWindow; + return this->m_GLSDLWindow.m_sdlWindow; } void CGxDeviceGLSDL::Draw(CGxBatch* batch, int32_t indexed) { @@ -681,6 +681,8 @@ void CGxDeviceGLSDL::ISetCaps(const CGxFormat& format) { this->m_caps.m_texMaxSize[GxTex_Rectangle] = 4096; this->m_caps.m_texMaxSize[GxTex_NonPow2] = 4096; + this->m_caps.m_hardwareCursor = 0; + // TODO } @@ -926,7 +928,17 @@ void CGxDeviceGLSDL::IStateSyncVertexPtrs() { ); } +void CGxDeviceGLSDL::IXformSetWorld() { + auto& stack = this->m_xforms[GxXform_World]; + this->m_GLSDLDevice.SetTransform('WRLD', reinterpret_cast(&stack.TopConst())); + stack.m_dirty = 0; +} + void CGxDeviceGLSDL::IStateSyncXforms() { + if (this->m_xforms[GxXform_World].m_dirty) { + this->IXformSetWorld(); + } + // TODO this->IXformSetWorld(); // TODO this->IXformSetTex(); @@ -1268,13 +1280,13 @@ void CGxDeviceGLSDL::SceneClear(uint32_t mask, CImVector color) { } void CGxDeviceGLSDL::ScenePresent() { - this->m_GLSDLWindow.DispatchEvents(); - if (this->m_context) { // TODO CGxDevice::ScenePresent(); + this->ICursorDraw(); + // TODO this->m_GLSDLDevice.Swap(); diff --git a/src/gx/glsdl/CGxDeviceGLSDL.hpp b/src/gx/glsdl/CGxDeviceGLSDL.hpp index 316317c..9e7cefb 100644 --- a/src/gx/glsdl/CGxDeviceGLSDL.hpp +++ b/src/gx/glsdl/CGxDeviceGLSDL.hpp @@ -74,6 +74,7 @@ class CGxDeviceGLSDL : public CGxDevice { void IXformSetProjection(const C44Matrix&); void IXformSetView(const C44Matrix&); void IXformSetViewport(); + void IXformSetWorld(); void PatchPixelShader(CGxShader*); void PatchVertexShader(CGxShader*); void Resize(uint32_t width, uint32_t height); diff --git a/src/gx/glsdl/GLSDLWindow.cpp b/src/gx/glsdl/GLSDLWindow.cpp index 791a1d8..757e89b 100644 --- a/src/gx/glsdl/GLSDLWindow.cpp +++ b/src/gx/glsdl/GLSDLWindow.cpp @@ -12,136 +12,6 @@ static bool s_GLSDL_Initialized = false; -static const std::map s_keyConversion = { - {SDL_SCANCODE_LSHIFT, KEY_LSHIFT}, - {SDL_SCANCODE_RSHIFT, KEY_RSHIFT}, - {SDL_SCANCODE_LCTRL, KEY_LCONTROL}, - {SDL_SCANCODE_RCTRL, KEY_RCONTROL}, - {SDL_SCANCODE_LALT, KEY_LALT}, - {SDL_SCANCODE_RALT, KEY_RALT}, - {SDL_SCANCODE_SPACE, KEY_SPACE}, - {SDL_SCANCODE_0, KEY_0}, - {SDL_SCANCODE_1, KEY_1}, - {SDL_SCANCODE_2, KEY_2}, - {SDL_SCANCODE_3, KEY_3}, - {SDL_SCANCODE_4, KEY_4}, - {SDL_SCANCODE_5, KEY_5}, - {SDL_SCANCODE_6, KEY_6}, - {SDL_SCANCODE_7, KEY_7}, - {SDL_SCANCODE_8, KEY_8}, - {SDL_SCANCODE_9, KEY_9}, - {SDL_SCANCODE_A, KEY_A}, - {SDL_SCANCODE_B, KEY_B}, - {SDL_SCANCODE_C, KEY_C}, - {SDL_SCANCODE_D, KEY_D}, - {SDL_SCANCODE_E, KEY_E}, - {SDL_SCANCODE_F, KEY_F}, - {SDL_SCANCODE_G, KEY_G}, - {SDL_SCANCODE_H, KEY_H}, - {SDL_SCANCODE_I, KEY_I}, - {SDL_SCANCODE_J, KEY_J}, - {SDL_SCANCODE_K, KEY_K}, - {SDL_SCANCODE_L, KEY_L}, - {SDL_SCANCODE_M, KEY_M}, - {SDL_SCANCODE_N, KEY_N}, - {SDL_SCANCODE_O, KEY_O}, - {SDL_SCANCODE_P, KEY_P}, - {SDL_SCANCODE_Q, KEY_Q}, - {SDL_SCANCODE_R, KEY_R}, - {SDL_SCANCODE_S, KEY_S}, - {SDL_SCANCODE_T, KEY_T}, - {SDL_SCANCODE_U, KEY_U}, - {SDL_SCANCODE_V, KEY_V}, - {SDL_SCANCODE_W, KEY_W}, - {SDL_SCANCODE_X, KEY_X}, - {SDL_SCANCODE_Y, KEY_Y}, - {SDL_SCANCODE_Z, KEY_Z}, - {SDL_SCANCODE_GRAVE, KEY_TILDE}, - {SDL_SCANCODE_KP_0, KEY_NUMPAD0}, - {SDL_SCANCODE_KP_1, KEY_NUMPAD1}, - {SDL_SCANCODE_KP_2, KEY_NUMPAD2}, - {SDL_SCANCODE_KP_3, KEY_NUMPAD3}, - {SDL_SCANCODE_KP_4, KEY_NUMPAD4}, - {SDL_SCANCODE_KP_5, KEY_NUMPAD5}, - {SDL_SCANCODE_KP_6, KEY_NUMPAD6}, - {SDL_SCANCODE_KP_7, KEY_NUMPAD7}, - {SDL_SCANCODE_KP_8, KEY_NUMPAD8}, - {SDL_SCANCODE_KP_9, KEY_NUMPAD9}, - {SDL_SCANCODE_KP_PLUS, KEY_NUMPAD_PLUS}, - {SDL_SCANCODE_KP_MINUS, KEY_NUMPAD_MINUS}, - {SDL_SCANCODE_KP_MULTIPLY, KEY_NUMPAD_MULTIPLY}, - {SDL_SCANCODE_KP_DIVIDE, KEY_NUMPAD_DIVIDE}, - {SDL_SCANCODE_KP_DECIMAL, KEY_NUMPAD_DECIMAL}, - {SDL_SCANCODE_KP_EQUALS, KEY_NUMPAD_EQUALS}, - {SDL_SCANCODE_EQUALS, KEY_PLUS}, - {SDL_SCANCODE_MINUS, KEY_MINUS}, - {SDL_SCANCODE_LEFTBRACKET, KEY_BRACKET_OPEN}, - {SDL_SCANCODE_RIGHTBRACKET, KEY_BRACKET_CLOSE}, - {SDL_SCANCODE_SLASH, KEY_SLASH}, - {SDL_SCANCODE_BACKSLASH, KEY_BACKSLASH}, - {SDL_SCANCODE_SEMICOLON, KEY_SEMICOLON}, - {SDL_SCANCODE_APOSTROPHE, KEY_APOSTROPHE}, - {SDL_SCANCODE_COMMA, KEY_COMMA}, - {SDL_SCANCODE_PERIOD, KEY_PERIOD}, - {SDL_SCANCODE_ESCAPE, KEY_ESCAPE}, - {SDL_SCANCODE_RETURN, KEY_ENTER}, - {SDL_SCANCODE_BACKSPACE, KEY_BACKSPACE}, - {SDL_SCANCODE_TAB, KEY_TAB}, - {SDL_SCANCODE_LEFT, KEY_LEFT}, - {SDL_SCANCODE_UP, KEY_UP}, - {SDL_SCANCODE_RIGHT, KEY_RIGHT}, - {SDL_SCANCODE_DOWN, KEY_DOWN}, - {SDL_SCANCODE_INSERT, KEY_INSERT}, - {SDL_SCANCODE_DELETE, KEY_DELETE}, - {SDL_SCANCODE_HOME, KEY_HOME}, - {SDL_SCANCODE_END, KEY_END}, - {SDL_SCANCODE_PAGEUP, KEY_PAGEUP}, - {SDL_SCANCODE_PAGEDOWN, KEY_PAGEDOWN}, - {SDL_SCANCODE_CAPSLOCK, KEY_CAPSLOCK}, - {SDL_SCANCODE_NUMLOCKCLEAR, KEY_NUMLOCK}, - {SDL_SCANCODE_SCROLLLOCK, KEY_SCROLLLOCK}, - {SDL_SCANCODE_PAUSE, KEY_PAUSE}, - {SDL_SCANCODE_PRINTSCREEN, KEY_PRINTSCREEN}, - {SDL_SCANCODE_F1, KEY_F1}, - {SDL_SCANCODE_F2, KEY_F2}, - {SDL_SCANCODE_F3, KEY_F3}, - {SDL_SCANCODE_F4, KEY_F4}, - {SDL_SCANCODE_F5, KEY_F5}, - {SDL_SCANCODE_F6, KEY_F6}, - {SDL_SCANCODE_F7, KEY_F7}, - {SDL_SCANCODE_F8, KEY_F8}, - {SDL_SCANCODE_F9, KEY_F9}, - {SDL_SCANCODE_F10, KEY_F10}, - {SDL_SCANCODE_F11, KEY_F11}, - {SDL_SCANCODE_F12, KEY_F12}, - {SDL_SCANCODE_F13, KEY_F13}, - {SDL_SCANCODE_F14, KEY_F14}, - {SDL_SCANCODE_F15, KEY_F15}, - {SDL_SCANCODE_F16, KEY_F16}, - {SDL_SCANCODE_F17, KEY_F17}, - {SDL_SCANCODE_F18, KEY_F18}, - {SDL_SCANCODE_F19, KEY_F19} -}; - -static MOUSEBUTTON s_buttonConversion[16] = { - MOUSE_BUTTON_NONE, - MOUSE_BUTTON_LEFT, - MOUSE_BUTTON_MIDDLE, - MOUSE_BUTTON_RIGHT, - MOUSE_BUTTON_XBUTTON1, - MOUSE_BUTTON_XBUTTON2, - MOUSE_BUTTON_XBUTTON3, - MOUSE_BUTTON_XBUTTON4, - MOUSE_BUTTON_XBUTTON5, - MOUSE_BUTTON_XBUTTON6, - MOUSE_BUTTON_XBUTTON7, - MOUSE_BUTTON_XBUTTON8, - MOUSE_BUTTON_XBUTTON9, - MOUSE_BUTTON_XBUTTON10, - MOUSE_BUTTON_XBUTTON11, - MOUSE_BUTTON_XBUTTON12 -}; - void GLSDLWindow::Create(const char* title, const GLSDLWindowRect& rect, GLTextureFormat depthFormat, uint32_t sampleCount) { BLIZZARD_ASSERT(this->m_sdlWindow == nullptr); @@ -213,13 +83,6 @@ void GLSDLWindow::Swap() { SDL_GL_SwapWindow(this->m_sdlWindow); } -void GLSDLWindow::DispatchEvents() { - SDL_Event event; - while (SDL_PollEvent(&event)) { - this->DispatchSDLEvent(event); - } -} - void GLSDLWindow::Destroy() { SDL_DestroyWindow(this->m_sdlWindow); this->m_sdlWindow = nullptr; @@ -275,116 +138,3 @@ int32_t GLSDLWindow::GetHeight() { return this->GetBackingRect().size.height; } -void GLSDLWindow::DispatchSDLEvent(const SDL_Event& event) { - switch (event.type) { - case SDL_KEYDOWN: - case SDL_KEYUP: - this->DispatchSDLKeyboardEvent(event); - break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - this->DispatchSDLMouseButtonEvent(event); - break; - case SDL_MOUSEMOTION: - this->DispatchSDLMouseMotionEvent(event); - break; - case SDL_TEXTINPUT: - this->DispatchSDLTextInputEvent(event); - break; - case SDL_WINDOWEVENT_RESIZED: - this->DispatchSDLWindowResizedEvent(event); - break; - case SDL_QUIT: - EventPostClose(); - break; - default: - break; - } -} - -void GLSDLWindow::DispatchSDLKeyboardEvent(const SDL_Event& event) { - // Is this an up or down keypress? - OSINPUT inputclass = event.type == SDL_KEYUP ? OS_INPUT_KEY_UP : OS_INPUT_KEY_DOWN; - - // What key does this SDL scancode correspond to? - auto lookup = s_keyConversion.find(event.key.keysym.scancode); - if (lookup != s_keyConversion.end()) { - // Scancode was found - KEY key = lookup->second; - - // Push key event into input queue - OsQueuePut(inputclass, key, 0, 0, 0); - return; - } - -} - -void GLSDLWindow::DispatchSDLMouseMotionEvent(const SDL_Event& event) { - auto x = static_cast(event.motion.x); - auto y = static_cast(event.motion.y); - - OsQueuePut(OS_INPUT_MOUSE_MOVE, 0, x, y, 0); -} - -void GLSDLWindow::DispatchSDLMouseButtonEvent(const SDL_Event& event) { - // Is this an up or down mouse click? - OSINPUT inputclass = event.type == SDL_MOUSEBUTTONUP ? OS_INPUT_MOUSE_UP : OS_INPUT_MOUSE_DOWN; - - // XY click coordinates - auto x = static_cast(event.button.x); - auto y = static_cast(event.button.y); - - // Convert SDL button index into internal MOUSEBUTTON ID - auto buttonIndex = event.button.button; - if (buttonIndex > 15) { - return; - } - auto button = s_buttonConversion[buttonIndex]; - - // Push mousebutton event into input queue - OsQueuePut(inputclass, button, x, y, 0); -} - -void GLSDLWindow::DispatchSDLTextInputEvent(const SDL_Event& event) { - // text input string holding one or more UTF-8 characters - auto text = reinterpret_cast(event.text.text); - - // Because SDL_TextInputEvent can hold multiple UTF-8 characters - // explode variable number of these characters into - // individual OS_INPUT_CHAR events - while (*text != '\0') { - // byte size of current UTF-8 character - int32_t charactersize = 0; - - // Read UTF-8 character - auto character = static_cast(SUniSGetUTF8(text, &charactersize)); - if (character < 0) { - // Cancel in case of invalid input - break; - } - - // Push character to input queue - OsQueuePut(OS_INPUT_CHAR, character, 1, 0, 0); - - // Advance text pointer - text += charactersize; - } -} - -void GLSDLWindow::DispatchSDLWindowResizedEvent(const SDL_Event& event) { - auto width = static_cast(event.window.data1); - auto height = static_cast(event.window.data2); - - static_cast(g_theGxDevicePtr)->Resize(width, height); - - OsQueuePut(OS_INPUT_SIZE, width, height, 0, 0); - - auto bounds = GetSavedWindowBounds(); - Rect newBounds = { - bounds->top, - bounds->left, - static_cast(bounds->top + height), - static_cast(bounds->left + width) - }; - SetSavedWindowBounds(newBounds); -} diff --git a/src/gx/glsdl/GLSDLWindow.hpp b/src/gx/glsdl/GLSDLWindow.hpp index d1303ca..70cd765 100644 --- a/src/gx/glsdl/GLSDLWindow.hpp +++ b/src/gx/glsdl/GLSDLWindow.hpp @@ -30,13 +30,6 @@ class GLSDLWindow { void Create(const char* title, const GLSDLWindowRect& rect, GLTextureFormat depthFormat, uint32_t sampleCount); void Destroy(); void Swap(); - void DispatchEvents(); - void DispatchSDLEvent(const SDL_Event& event); - void DispatchSDLKeyboardEvent(const SDL_Event& event); - void DispatchSDLMouseMotionEvent(const SDL_Event& event); - void DispatchSDLMouseButtonEvent(const SDL_Event& event); - void DispatchSDLTextInputEvent(const SDL_Event& event); - void DispatchSDLWindowResizedEvent(const SDL_Event& event); void Resize(const GLSDLWindowRect& rect); GLSDLWindowRect GetRect();