isle-portable/miniwin/src/internal/d3drmrenderer_gxm.h
2025-07-07 15:09:27 +02:00

204 lines
5.9 KiB
C++

#pragma once
#include "d3drmrenderer.h"
#include "d3drmtexture_impl.h"
#include "ddpalette_impl.h"
#include "ddraw_impl.h"
#include "gxm_context.h"
#include <SDL3/SDL.h>
#include <psp2/gxm.h>
#include <psp2/kernel/clib.h>
#include <psp2/types.h>
#include <vector>
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<GXMTextureCacheEntry> m_textures;
std::vector<GXMMeshCacheEntry> m_meshes;
D3DRMMATRIX4D m_projection;
std::vector<SceneLight> 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);
}