#pragma once #include "d3drmrenderer.h" #include "d3drmtexture_impl.h" #include "ddpalette_impl.h" #include "ddraw_impl.h" #include "gxm_context.h" #include #include #include #include #include DEFINE_GUID(GXM_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x58, 0x4D); #define GXM_VERTEX_BUFFER_COUNT 2 #define GXM_FRAGMENT_BUFFER_COUNT 3 #define GXM_TEXTURE_BUFFER_COUNT 2 // #define GXM_PRECOMPUTE struct GXMTextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; int bufferCount; int currentIndex; SceGxmTexture gxmTexture[GXM_TEXTURE_BUFFER_COUNT]; SceGxmNotification* notifications[GXM_TEXTURE_BUFFER_COUNT]; }; struct GXMMeshCacheEntry { const MeshGroup* meshGroup; int version; bool flat; void* meshData; void* vertexBuffer; void* indexBuffer; uint16_t indexCount; #ifdef GXM_PRECOMPUTE void* precomputeData; void* uniformBuffers; SceGxmPrecomputedVertexState vertexState[GXM_VERTEX_BUFFER_COUNT]; SceGxmPrecomputedFragmentState fragmentState[GXM_FRAGMENT_BUFFER_COUNT]; SceGxmPrecomputedDraw drawState; #endif }; typedef struct GXMDisplayData { void* address; } GXMDisplayData; struct SceneLightGXM { float color[4]; float vec[4]; float isDirectional; float _align; }; struct GXMSceneLightUniform { SceneLightGXM lights[2]; float ambientLight[3]; }; typedef struct Vertex { float position[3]; float normal[3]; float texCoord[2]; } Vertex; class GXMRenderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); GXMRenderer(DWORD width, DWORD height); ~GXMRenderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUi, float scaleX, float scaleY) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; HRESULT BeginFrame() override; void EnableTransparency() override; void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, const D3DRMMATRIX4D& worldMatrix, const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; void Resize(int width, int height, const ViewportTransform& viewportTransform) override; void Clear(float r, float g, float b) override; void Flip() override; void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); GXMMeshCacheEntry GXMUploadMesh(const MeshGroup& meshGroup); void StartScene(); inline const SceGxmTexture* UseTexture(GXMTextureCacheEntry& texture) { texture.notifications[texture.currentIndex] = &this->fragmentNotifications[this->currentFragmentBufferIndex]; const SceGxmTexture* gxmTexture = &texture.gxmTexture[texture.currentIndex]; sceGxmSetFragmentTexture(gxm->context, 0, gxmTexture); return gxmTexture; } inline Vertex2D* QuadVerticesBuffer() { Vertex2D* verts = &this->quadVertices[this->currentVertexBufferIndex][this->quadsUsed * 4]; this->quadsUsed += 1; if (this->quadsUsed >= 50) { SDL_Log("QuadVerticesBuffer overflow"); this->quadsUsed = 0; // declare bankruptcy } return verts; } inline GXMSceneLightUniform* LightsBuffer() { return this->lights[this->currentFragmentBufferIndex]; } std::vector m_textures; std::vector m_meshes; D3DRMMATRIX4D m_projection; std::vector m_lights; bool transparencyEnabled = false; // shader SceGxmShaderPatcherId mainVertexProgramId; SceGxmShaderPatcherId mainColorFragmentProgramId; SceGxmShaderPatcherId mainTextureFragmentProgramId; SceGxmVertexProgram* mainVertexProgram; SceGxmFragmentProgram* opaqueColorFragmentProgram; SceGxmFragmentProgram* blendedColorFragmentProgram; SceGxmFragmentProgram* opaqueTextureFragmentProgram; SceGxmFragmentProgram* blendedTextureFragmentProgram; // main shader vertex uniforms const SceGxmProgramParameter* uModelViewMatrix; const SceGxmProgramParameter* uNormalMatrix; const SceGxmProgramParameter* uProjectionMatrix; // main shader fragment uniforms const SceGxmProgramParameter* uShininess; const SceGxmProgramParameter* uColor; const SceGxmProgramParameter* uLights; const SceGxmProgramParameter* uAmbientLight; // uniforms / quad meshes GXMSceneLightUniform* lights[GXM_FRAGMENT_BUFFER_COUNT]; Vertex2D* quadVertices[GXM_VERTEX_BUFFER_COUNT]; uint16_t* quadIndices; int quadsUsed = 0; bool cleared = false; SceGxmNotification vertexNotifications[GXM_VERTEX_BUFFER_COUNT]; SceGxmNotification fragmentNotifications[GXM_FRAGMENT_BUFFER_COUNT]; int currentFragmentBufferIndex = 0; int currentVertexBufferIndex = 0; SDL_Gamepad* gamepad; bool button_dpad_up; bool button_dpad_down; bool button_dpad_left; bool button_dpad_right; bool m_initialized = false; }; int gxm_library_init(); inline static void GXMRenderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) { D3DDEVICEDESC halDesc = {}; halDesc.dcmColorModel = D3DCOLORMODEL::RGB; halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; halDesc.dwDeviceZBufferBitDepth = DDBD_16; halDesc.dwDeviceZBufferBitDepth |= DDBD_32; halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; D3DDEVICEDESC helDesc = {}; helDesc.dwDeviceRenderBitDepth = DDBD_32; int ret = gxm_library_init(); if (ret < 0) { SDL_Log("gxm_library_init failed: %08x", ret); return; } EnumDevice(cb, ctx, "GXM HAL", &halDesc, &helDesc, GXM_GUID); }