Refactor renderers (#237)

This commit is contained in:
Anders Jenbo 2025-06-05 04:07:42 +02:00 committed by GitHub
parent 8e55368615
commit 12d01ae311
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1801 additions and 1746 deletions

View File

@ -1,5 +1,6 @@
#include "d3drmrenderer_opengl15.h"
#include "ddraw_impl.h"
#include "mathutils.h"
#include <GL/glew.h>
#include <cstring>
@ -92,19 +93,14 @@ OpenGL15Renderer::~OpenGL15Renderer()
}
}
void OpenGL15Renderer::PushVertices(const PositionColorVertex* verts, size_t count)
{
m_vertices.assign(verts, verts + count);
}
void OpenGL15Renderer::PushLights(const SceneLight* lightsArray, size_t count)
{
m_lights.assign(lightsArray, lightsArray + count);
}
void OpenGL15Renderer::SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back)
void OpenGL15Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{
memcpy(&m_projection, perspective, sizeof(D3DRMMATRIX4D));
memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D));
m_projection[1][1] *= -1.0f; // OpenGL is upside down
}
@ -141,11 +137,14 @@ const char* OpenGL15Renderer::GetName()
return "OpenGL 1.5 HAL";
}
HRESULT OpenGL15Renderer::Render()
HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
if (!DDBackBuffer) {
return DDERR_GENERIC;
}
memcpy(m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D));
SDL_GL_MakeCurrent(DDWindow, m_context);
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
glViewport(0, 0, m_width, m_height);
@ -220,21 +219,41 @@ HRESULT OpenGL15Renderer::Render()
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Render geometry
return DD_OK;
}
void OpenGL15Renderer::SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
D3DRMMATRIX4D mvMatrix;
MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix);
glLoadMatrixf(&mvMatrix[0][0]);
glEnable(GL_NORMALIZE);
glBegin(GL_TRIANGLES);
for (const auto& v : m_vertices) {
glColor4ub(v.colors.r, v.colors.g, v.colors.b, v.colors.a);
for (size_t i = 0; i < count; i++) {
const GeometryVertex& v = vertices[i];
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
glNormal3f(v.normals.x, v.normals.y, v.normals.z);
glTexCoord2f(v.texCoord.u, v.texCoord.v);
// Set per-vertex specular material
glMaterialf(GL_FRONT, GL_SHININESS, v.shininess);
if (v.shininess != 0.0f) {
GLfloat whiteSpec[] = {v.shininess, v.shininess, v.shininess, v.shininess};
float shininess = appearance.shininess;
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
if (shininess != 0.0f) {
GLfloat whiteSpec[] = {shininess, shininess, shininess, shininess};
glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec);
}
else {
GLfloat noSpec[] = {0.f, 0.f, 0.f, 1.f};
GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 1.0f};
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
}
@ -242,6 +261,11 @@ HRESULT OpenGL15Renderer::Render()
}
glEnd();
glPopMatrix();
}
HRESULT OpenGL15Renderer::FinalizeFrame()
{
glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

View File

@ -2,12 +2,13 @@
#include "d3drmrenderer.h"
#include "d3drmrenderer_sdl3gpu.h"
#include "ddraw_impl.h"
#include "mathutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
#include <cstddef>
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device)
static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device, bool depthWrite)
{
const SDL_GPUShaderCreateInfo* vertexCreateInfo =
GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device));
@ -31,40 +32,25 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
SDL_GPUVertexBufferDescription vertexBufferDescs[1] = {};
vertexBufferDescs[0].slot = 0;
vertexBufferDescs[0].pitch = sizeof(PositionColorVertex);
vertexBufferDescs[0].pitch = sizeof(GeometryVertex);
vertexBufferDescs[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
vertexBufferDescs[0].instance_step_rate = 0;
SDL_GPUVertexAttribute vertexAttrs[6] = {};
SDL_GPUVertexAttribute vertexAttrs[3] = {};
vertexAttrs[0].location = 0;
vertexAttrs[0].buffer_slot = 0;
vertexAttrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
vertexAttrs[0].offset = offsetof(PositionColorVertex, position);
vertexAttrs[0].offset = offsetof(GeometryVertex, position);
vertexAttrs[1].location = 1;
vertexAttrs[1].buffer_slot = 0;
vertexAttrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
vertexAttrs[1].offset = offsetof(PositionColorVertex, normals);
vertexAttrs[1].offset = offsetof(GeometryVertex, normals);
vertexAttrs[2].location = 2;
vertexAttrs[2].buffer_slot = 0;
vertexAttrs[2].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM;
vertexAttrs[2].offset = offsetof(PositionColorVertex, colors);
vertexAttrs[3].location = 3;
vertexAttrs[3].buffer_slot = 0;
vertexAttrs[3].format = SDL_GPU_VERTEXELEMENTFORMAT_UINT;
vertexAttrs[3].offset = offsetof(PositionColorVertex, texId);
vertexAttrs[4].location = 4;
vertexAttrs[4].buffer_slot = 0;
vertexAttrs[4].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
vertexAttrs[4].offset = offsetof(PositionColorVertex, texCoord);
vertexAttrs[5].location = 5;
vertexAttrs[5].buffer_slot = 0;
vertexAttrs[5].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
vertexAttrs[5].offset = offsetof(PositionColorVertex, shininess);
vertexAttrs[2].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
vertexAttrs[2].offset = offsetof(GeometryVertex, texCoord);
SDL_GPUVertexInputState vertexInputState = {};
vertexInputState.vertex_buffer_descriptions = vertexBufferDescs;
@ -74,6 +60,19 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
SDL_GPUColorTargetDescription colorTargets = {};
colorTargets.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
if (depthWrite) {
colorTargets.blend_state.enable_blend = false;
}
else {
colorTargets.blend_state.enable_blend = true;
colorTargets.blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
colorTargets.blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
colorTargets.blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD;
colorTargets.blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
colorTargets.blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ZERO;
colorTargets.blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD;
colorTargets.blend_state.enable_color_write_mask = false;
}
SDL_GPURasterizerState rasterizerState = {};
rasterizerState.fill_mode = SDL_GPU_FILLMODE_FILL;
@ -92,7 +91,7 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device
pipelineCreateInfo.target_info.has_depth_stencil_target = true;
pipelineCreateInfo.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
pipelineCreateInfo.depth_stencil_state.enable_depth_test = true;
pipelineCreateInfo.depth_stencil_state.enable_depth_write = true;
pipelineCreateInfo.depth_stencil_state.enable_depth_write = depthWrite;
pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false;
pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_GREATER;
pipelineCreateInfo.depth_stencil_state.write_mask = 0xff;
@ -116,8 +115,13 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUDevice failed (%s)", SDL_GetError());
return nullptr;
}
SDL_GPUGraphicsPipeline* pipeline = InitializeGraphicsPipeline(device);
if (!pipeline) {
SDL_GPUGraphicsPipeline* opaquePipeline = InitializeGraphicsPipeline(device, true);
if (!opaquePipeline) {
return nullptr;
}
SDL_GPUGraphicsPipeline* transparentPipeline = InitializeGraphicsPipeline(device, false);
if (!transparentPipeline) {
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
return nullptr;
}
@ -131,7 +135,8 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
SDL_GPUTexture* transferTexture = SDL_CreateGPUTexture(device, &textureInfo);
if (!transferTexture) {
SDL_ReleaseGPUGraphicsPipeline(device, pipeline);
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(device, transparentPipeline);
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError());
return nullptr;
}
@ -146,7 +151,8 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
depthTextureInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET;
SDL_GPUTexture* depthTexture = SDL_CreateGPUTexture(device, &depthTextureInfo);
if (!depthTexture) {
SDL_ReleaseGPUGraphicsPipeline(device, pipeline);
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(device, transparentPipeline);
SDL_ReleaseGPUTexture(device, transferTexture);
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError());
return nullptr;
@ -158,7 +164,8 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
downloadTransferInfo.size = static_cast<Uint32>(width * height * 4);
SDL_GPUTransferBuffer* downloadTransferBuffer = SDL_CreateGPUTransferBuffer(device, &downloadTransferInfo);
if (!downloadTransferBuffer) {
SDL_ReleaseGPUGraphicsPipeline(device, pipeline);
SDL_ReleaseGPUGraphicsPipeline(device, opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(device, transparentPipeline);
SDL_ReleaseGPUTexture(device, depthTexture);
SDL_ReleaseGPUTexture(device, transferTexture);
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer failed (%s)", SDL_GetError());
@ -169,7 +176,8 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height)
width,
height,
device,
pipeline,
opaquePipeline,
transparentPipeline,
transferTexture,
depthTexture,
downloadTransferBuffer
@ -180,13 +188,15 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer(
DWORD width,
DWORD height,
SDL_GPUDevice* device,
SDL_GPUGraphicsPipeline* pipeline,
SDL_GPUGraphicsPipeline* opaquePipeline,
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUTransferBuffer* downloadTransferBuffer
)
: m_width(width), m_height(height), m_device(device), m_pipeline(pipeline), m_transferTexture(transferTexture),
m_depthTexture(depthTexture), m_downloadTransferBuffer(downloadTransferBuffer)
: m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline),
m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture),
m_downloadTransferBuffer(downloadTransferBuffer)
{
}
@ -196,7 +206,8 @@ Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer()
SDL_ReleaseGPUTransferBuffer(m_device, m_downloadTransferBuffer);
SDL_ReleaseGPUTexture(m_device, m_depthTexture);
SDL_ReleaseGPUTexture(m_device, m_transferTexture);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_pipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_opaquePipeline);
SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline);
SDL_DestroyGPUDevice(m_device);
}
@ -206,79 +217,15 @@ void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* vertices, size_t co
SDL_LogError(LOG_CATEGORY_MINIWIN, "Unsupported number of lights (%d)", static_cast<int>(count));
count = 3;
}
memcpy(&m_lights.lights, vertices, sizeof(SceneLight) * count);
m_lights.count = count;
memcpy(&m_fragmentShadingData.lights, vertices, sizeof(SceneLight) * count);
m_fragmentShadingData.lightCount = count;
}
void Direct3DRMSDL3GPURenderer::PushVertices(const PositionColorVertex* vertices, size_t count)
{
if (count > m_vertexBufferCount) {
if (m_vertexBuffer) {
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
}
SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
bufferCreateInfo.size = static_cast<Uint32>(sizeof(PositionColorVertex) * count);
m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!m_vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer returned NULL buffer (%s)", SDL_GetError());
}
m_vertexBufferCount = count;
}
m_vertexCount = count;
if (!count) {
return;
}
SDL_GPUTransferBufferCreateInfo transferCreateInfo = {};
transferCreateInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
transferCreateInfo.size = static_cast<Uint32>(sizeof(PositionColorVertex) * m_vertexCount);
SDL_GPUTransferBuffer* transferBuffer = SDL_CreateGPUTransferBuffer(m_device, &transferCreateInfo);
if (!transferBuffer) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer returned NULL transfer buffer (%s)",
SDL_GetError()
);
}
PositionColorVertex* transferData =
(PositionColorVertex*) SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer returned NULL buffer (%s)", SDL_GetError());
}
memcpy(transferData, vertices, m_vertexCount * sizeof(PositionColorVertex));
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* uploadCmdBuf = SDL_AcquireGPUCommandBuffer(m_device);
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(uploadCmdBuf);
SDL_GPUTransferBufferLocation transferLocation = {};
transferLocation.transfer_buffer = transferBuffer;
transferLocation.offset = 0;
SDL_GPUBufferRegion bufferRegion = {};
bufferRegion.buffer = m_vertexBuffer;
bufferRegion.offset = 0;
bufferRegion.size = static_cast<Uint32>(sizeof(PositionColorVertex) * m_vertexCount);
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
if (!SDL_SubmitGPUCommandBuffer(uploadCmdBuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer failes (%s)", SDL_GetError());
}
SDL_ReleaseGPUTransferBuffer(m_device, transferBuffer);
}
void Direct3DRMSDL3GPURenderer::SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back)
void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{
m_front = front;
m_back = back;
memcpy(&m_uniforms.perspective, perspective, sizeof(D3DRMMATRIX4D));
memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D));
}
Uint32 Direct3DRMSDL3GPURenderer::GetTextureId(IDirect3DRMTexture* texture)
@ -314,35 +261,133 @@ const char* Direct3DRMSDL3GPURenderer::GetName()
return "SDL3 GPU HAL";
}
HRESULT Direct3DRMSDL3GPURenderer::Render()
HRESULT Direct3DRMSDL3GPURenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (cmdbuf == NULL) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
if (!DDBackBuffer) {
return DDERR_GENERIC;
}
// Render the graphics
memcpy(&m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D));
// Clear color and depth targets
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
// Make the render target transparent so we can combine it with the back buffer
colorTargetInfo.clear_color = {0, 0, 0, 0};
colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.clear_depth = 0.f;
depthStencilTargetInfo.clear_stencil = 0;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
depthStencilTargetInfo.stencil_load_op = SDL_GPU_LOADOP_CLEAR;
depthStencilTargetInfo.stencil_store_op = SDL_GPU_STOREOP_STORE;
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_BindGPUGraphicsPipeline(renderPass, m_pipeline);
SDL_EndGPURenderPass(renderPass);
if (!SDL_SubmitGPUCommandBuffer(cmdbuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
return DD_OK;
}
void Direct3DRMSDL3GPURenderer::SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
{
D3DRMMATRIX4D worldViewMatrix;
MultiplyMatrix(worldViewMatrix, worldMatrix, m_viewMatrix);
memcpy(&m_uniforms.worldViewMatrix, worldViewMatrix, sizeof(D3DRMMATRIX4D));
m_fragmentShadingData.color = appearance.color;
m_fragmentShadingData.shininess = appearance.shininess;
if (count > m_vertexBufferCount) {
if (m_vertexBuffer) {
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
}
SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
bufferCreateInfo.size = static_cast<Uint32>(sizeof(GeometryVertex) * count);
m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!m_vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer returned NULL buffer (%s)", SDL_GetError());
}
m_vertexBufferCount = count;
}
m_vertexCount = count;
if (!count) {
return;
}
SDL_GPUTransferBufferCreateInfo transferCreateInfo = {};
transferCreateInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
transferCreateInfo.size = static_cast<Uint32>(sizeof(GeometryVertex) * m_vertexCount);
SDL_GPUTransferBuffer* transferBuffer = SDL_CreateGPUTransferBuffer(m_device, &transferCreateInfo);
if (!transferBuffer) {
SDL_LogError(
LOG_CATEGORY_MINIWIN,
"SDL_CreateGPUTransferBuffer returned NULL transfer buffer (%s)",
SDL_GetError()
);
}
GeometryVertex* transferData = (GeometryVertex*) SDL_MapGPUTransferBuffer(m_device, transferBuffer, false);
if (!transferData) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_MapGPUTransferBuffer returned NULL buffer (%s)", SDL_GetError());
}
memcpy(transferData, vertices, m_vertexCount * sizeof(GeometryVertex));
SDL_UnmapGPUTransferBuffer(m_device, transferBuffer);
// Upload the transfer data to the vertex buffer
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (!cmdbuf) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
return;
}
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTransferBufferLocation transferLocation = {};
transferLocation.transfer_buffer = transferBuffer;
transferLocation.offset = 0;
SDL_GPUBufferRegion bufferRegion = {};
bufferRegion.buffer = m_vertexBuffer;
bufferRegion.offset = 0;
bufferRegion.size = static_cast<Uint32>(sizeof(GeometryVertex) * m_vertexCount);
SDL_UploadToGPUBuffer(copyPass, &transferLocation, &bufferRegion, false);
SDL_EndGPUCopyPass(copyPass);
SDL_ReleaseGPUTransferBuffer(m_device, transferBuffer);
// Render the graphics
SDL_GPUColorTargetInfo colorTargetInfo = {};
colorTargetInfo.texture = m_transferTexture;
colorTargetInfo.load_op = SDL_GPU_LOADOP_LOAD;
SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {};
depthStencilTargetInfo.texture = m_depthTexture;
depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_LOAD;
depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE;
SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo);
SDL_BindGPUGraphicsPipeline(renderPass, appearance.color.a == 255 ? m_opaquePipeline : m_transparentPipeline);
SDL_PushGPUVertexUniformData(cmdbuf, 0, &m_uniforms, sizeof(m_uniforms));
SDL_PushGPUFragmentUniformData(cmdbuf, 0, &m_lights, sizeof(m_lights));
SDL_PushGPUFragmentUniformData(cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData));
if (m_vertexCount) {
SDL_GPUBufferBinding vertexBufferBinding = {};
@ -354,6 +399,19 @@ HRESULT Direct3DRMSDL3GPURenderer::Render()
SDL_EndGPURenderPass(renderPass);
if (!SDL_SubmitGPUCommandBuffer(cmdbuf)) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_SubmitGPUCommandBuffer failes (%s)", SDL_GetError());
}
}
HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame()
{
SDL_GPUCommandBuffer* cmdbuf = SDL_AcquireGPUCommandBuffer(m_device);
if (cmdbuf == NULL) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer failed (%s)", SDL_GetError());
return DDERR_GENERIC;
}
// Download rendered image
SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdbuf);
SDL_GPUTextureRegion region = {};

View File

@ -2,20 +2,14 @@ struct VS_Input
{
float3 Position : POSITION;
float3 Normal : NORMAL0;
float4 Color : COLOR0;
uint TexId : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float Shininess : TEXCOORD2;
};
struct FS_Input
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL0;
float4 Color : COLOR0;
uint TexId : TEXCOORD0;
float2 TexCoord : TEXCOORD1;
float Shininess : TEXCOORD2;
float3 WorldPosition : TEXCOORD3;
};

View File

@ -2,19 +2,18 @@
cbuffer ViewportUniforms : register(b0, space1)
{
float4x4 perspective;
float4x4 projection;
float4x4 viewMatrix;
}
FS_Input main(VS_Input input)
{
FS_Input output;
output.TexCoord = input.TexCoord;
output.Color = input.Color;
float3 viewPos = mul(viewMatrix, float4(input.Position, 1.0)).xyz;
output.WorldPosition = viewPos;
output.Position = mul(projection, float4(viewPos, 1.0));
output.Normal = input.Normal;
output.Position = mul(perspective, float4(input.Position, 1.0));
output.WorldPosition = input.Position;
output.TexId = input.TexId;
output.Shininess = input.Shininess;
output.TexCoord = input.TexCoord;
return output;
}

View File

@ -1,9 +1,21 @@
#include "Common.hlsl"
cbuffer LightBuffer : register(b0, space3)
cbuffer FragmentShadingData : register(b0, space3)
{
SceneLight lights[3];
int lightCount;
float Shininess;
uint ColorRaw;
}
float4 unpackColor(uint packed)
{
float4 color;
color.r = ((packed >> 0) & 0xFF) / 255.0f;
color.g = ((packed >> 8) & 0xFF) / 255.0f;
color.b = ((packed >> 16) & 0xFF) / 255.0f;
color.a = ((packed >> 24) & 0xFF) / 255.0f;
return color;
}
FS_Output main(FS_Input input)
@ -41,18 +53,17 @@ FS_Output main(FS_Input input)
if (dotNL > 0.0f) {
diffuse += dotNL * lightColor;
if (input.Shininess != 0.0f) {
if (Shininess != 0.0f) {
// Using dotNL ignores view angle, but this matches DirectX 5 behavior.
float spec1 = pow(dotNL, input.Shininess);
float spec1 = pow(dotNL, Shininess);
specular += spec1 * lightColor;
}
}
}
float3 baseColor = input.Color.rgb;
float3 finalColor = saturate(diffuse * baseColor + specular);
output.Color = float4(finalColor, input.Color.a);
float4 Color = unpackColor(ColorRaw);
float3 finalColor = saturate(diffuse * Color.rgb + specular);
output.Color = float4(finalColor, Color.a);
output.Depth = input.Position.w;
return output;
}

View File

@ -1,6 +1,7 @@
#include "d3drmrenderer.h"
#include "d3drmrenderer_software.h"
#include "ddsurface_impl.h"
#include "mathutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
@ -19,20 +20,11 @@ void Direct3DRMSoftwareRenderer::PushLights(const SceneLight* lights, size_t cou
m_lights.assign(lights, lights + count);
}
void Direct3DRMSoftwareRenderer::PushVertices(const PositionColorVertex* vertices, size_t count)
{
if (!count) {
return;
}
m_vertexBuffer.resize(count);
memcpy(m_vertexBuffer.data(), vertices, count * sizeof(PositionColorVertex));
}
void Direct3DRMSoftwareRenderer::SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back)
void Direct3DRMSoftwareRenderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back)
{
m_front = front;
m_back = back;
memcpy(proj, perspective, sizeof(proj));
memcpy(m_projection, projection, sizeof(D3DRMMATRIX4D));
}
void Direct3DRMSoftwareRenderer::ClearZBuffer()
@ -40,12 +32,16 @@ void Direct3DRMSoftwareRenderer::ClearZBuffer()
std::fill(m_zBuffer.begin(), m_zBuffer.end(), std::numeric_limits<float>::infinity());
}
void Direct3DRMSoftwareRenderer::ProjectVertex(const PositionColorVertex& v, D3DRMVECTOR4D& p) const
void Direct3DRMSoftwareRenderer::ProjectVertex(const GeometryVertex& v, D3DRMVECTOR4D& p) const
{
float px = proj[0][0] * v.position.x + proj[1][0] * v.position.y + proj[2][0] * v.position.z + proj[3][0];
float py = proj[0][1] * v.position.x + proj[1][1] * v.position.y + proj[2][1] * v.position.z + proj[3][1];
float pz = proj[0][2] * v.position.x + proj[1][2] * v.position.y + proj[2][2] * v.position.z + proj[3][2];
float pw = proj[0][3] * v.position.x + proj[1][3] * v.position.y + proj[2][3] * v.position.z + proj[3][3];
float px = m_projection[0][0] * v.position.x + m_projection[1][0] * v.position.y +
m_projection[2][0] * v.position.z + m_projection[3][0];
float py = m_projection[0][1] * v.position.x + m_projection[1][1] * v.position.y +
m_projection[2][1] * v.position.z + m_projection[3][1];
float pz = m_projection[0][2] * v.position.x + m_projection[1][2] * v.position.y +
m_projection[2][2] * v.position.z + m_projection[3][2];
float pw = m_projection[0][3] * v.position.x + m_projection[1][3] * v.position.y +
m_projection[2][3] * v.position.z + m_projection[3][3];
p.w = pw;
@ -62,7 +58,7 @@ void Direct3DRMSoftwareRenderer::ProjectVertex(const PositionColorVertex& v, D3D
p.z = pz;
}
PositionColorVertex SplitEdge(PositionColorVertex a, const PositionColorVertex& b, float plane)
GeometryVertex SplitEdge(GeometryVertex a, const GeometryVertex& b, float plane)
{
float t = (plane - a.position.z) / (b.position.z - a.position.z);
a.position.x = a.position.x + t * (b.position.x - a.position.x);
@ -86,15 +82,11 @@ PositionColorVertex SplitEdge(PositionColorVertex a, const PositionColorVertex&
return a;
}
void Direct3DRMSoftwareRenderer::DrawTriangleClipped(
const PositionColorVertex& v0,
const PositionColorVertex& v1,
const PositionColorVertex& v2
)
void Direct3DRMSoftwareRenderer::DrawTriangleClipped(const GeometryVertex (&v)[3], const Appearance& appearance)
{
bool in0 = v0.position.z >= m_front;
bool in1 = v1.position.z >= m_front;
bool in2 = v2.position.z >= m_front;
bool in0 = v[0].position.z >= m_front;
bool in1 = v[1].position.z >= m_front;
bool in2 = v[2].position.z >= m_front;
int insideCount = in0 + in1 + in2;
@ -103,34 +95,34 @@ void Direct3DRMSoftwareRenderer::DrawTriangleClipped(
}
if (insideCount == 3) {
DrawTriangleProjected(v0, v1, v2);
DrawTriangleProjected(v[0], v[1], v[2], appearance);
}
else if (insideCount == 2) {
PositionColorVertex split;
GeometryVertex split;
if (!in0) {
split = SplitEdge(v2, v0, m_front);
DrawTriangleProjected(v1, v2, split);
DrawTriangleProjected(v1, split, SplitEdge(v1, v0, m_front));
split = SplitEdge(v[2], v[0], m_front);
DrawTriangleProjected(v[1], v[2], split, appearance);
DrawTriangleProjected(v[1], split, SplitEdge(v[1], v[0], m_front), appearance);
}
else if (!in1) {
split = SplitEdge(v0, v1, m_front);
DrawTriangleProjected(v2, v0, split);
DrawTriangleProjected(v2, split, SplitEdge(v2, v1, m_front));
split = SplitEdge(v[0], v[1], m_front);
DrawTriangleProjected(v[2], v[0], split, appearance);
DrawTriangleProjected(v[2], split, SplitEdge(v[2], v[1], m_front), appearance);
}
else {
split = SplitEdge(v1, v2, m_front);
DrawTriangleProjected(v0, v1, split);
DrawTriangleProjected(v0, split, SplitEdge(v0, v2, m_front));
split = SplitEdge(v[1], v[2], m_front);
DrawTriangleProjected(v[0], v[1], split, appearance);
DrawTriangleProjected(v[0], split, SplitEdge(v[0], v[2], m_front), appearance);
}
}
else if (in0) {
DrawTriangleProjected(v0, SplitEdge(v0, v1, m_front), SplitEdge(v0, v2, m_front));
DrawTriangleProjected(v[0], SplitEdge(v[0], v[1], m_front), SplitEdge(v[0], v[2], m_front), appearance);
}
else if (in1) {
DrawTriangleProjected(SplitEdge(v1, v0, m_front), v1, SplitEdge(v1, v2, m_front));
DrawTriangleProjected(SplitEdge(v[1], v[0], m_front), v[1], SplitEdge(v[1], v[2], m_front), appearance);
}
else {
DrawTriangleProjected(SplitEdge(v2, v0, m_front), SplitEdge(v2, v1, m_front), v2);
DrawTriangleProjected(SplitEdge(v[2], v[0], m_front), SplitEdge(v[2], v[1], m_front), v[2], appearance);
}
}
@ -157,7 +149,7 @@ void Direct3DRMSoftwareRenderer::BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g,
memcpy(pixelAddr, &blended, m_bytesPerPixel);
}
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const PositionColorVertex& vertex)
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const GeometryVertex& vertex, const Appearance& appearance)
{
FColor specular = {0, 0, 0, 0};
FColor diffuse = {0, 0, 0, 0};
@ -167,7 +159,7 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const PositionColorVertex& v
D3DVECTOR normal = vertex.normals;
float normLen = std::sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
if (normLen == 0.0f) {
return vertex.colors;
return appearance.color;
}
normal.x /= normLen;
@ -209,9 +201,9 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const PositionColorVertex& v
diffuse.g += dotNL * lightColor.g;
diffuse.b += dotNL * lightColor.b;
if (vertex.shininess != 0.0f) {
if (appearance.shininess != 0.0f) {
// Using dotNL ignores view angle, but this matches DirectX 5 behavior.
float spec = std::pow(dotNL, vertex.shininess);
float spec = std::pow(dotNL, appearance.shininess);
specular.r += spec * lightColor.r;
specular.g += spec * lightColor.g;
specular.b += spec * lightColor.b;
@ -220,17 +212,18 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const PositionColorVertex& v
}
return SDL_Color{
static_cast<Uint8>(std::min(255.0f, diffuse.r * vertex.colors.r + specular.r * 255.0f)),
static_cast<Uint8>(std::min(255.0f, diffuse.g * vertex.colors.g + specular.g * 255.0f)),
static_cast<Uint8>(std::min(255.0f, diffuse.b * vertex.colors.b + specular.b * 255.0f)),
vertex.colors.a
static_cast<Uint8>(std::min(255.0f, diffuse.r * appearance.color.r + specular.r * 255.0f)),
static_cast<Uint8>(std::min(255.0f, diffuse.g * appearance.color.g + specular.g * 255.0f)),
static_cast<Uint8>(std::min(255.0f, diffuse.b * appearance.color.b + specular.b * 255.0f)),
appearance.color.a
};
}
void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
const PositionColorVertex& v0,
const PositionColorVertex& v1,
const PositionColorVertex& v2
const GeometryVertex& v0,
const GeometryVertex& v1,
const GeometryVertex& v2,
const Appearance& appearance
)
{
D3DRMVECTOR4D p0, p1, p2;
@ -268,17 +261,17 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
float invArea = 1.0f / area;
// Per-vertex lighting using vertex normals
SDL_Color c0 = ApplyLighting(v0);
SDL_Color c1 = ApplyLighting(v1);
SDL_Color c2 = ApplyLighting(v2);
SDL_Color c0 = ApplyLighting(v0, appearance);
SDL_Color c1 = ApplyLighting(v1, appearance);
SDL_Color c2 = ApplyLighting(v2, appearance);
Uint32 texId = v0.texId;
Uint32 textureId = appearance.textureId;
int texturePitch;
Uint8* texels = nullptr;
int texWidthScale;
int texHeightScale;
if (texId != NO_TEXTURE_ID) {
SDL_Surface* texture = m_textures[texId].cached;
if (textureId != NO_TEXTURE_ID) {
SDL_Surface* texture = m_textures[textureId].cached;
if (texture) {
texturePitch = texture->pitch;
texels = static_cast<Uint8*>(texture->pixels);
@ -319,7 +312,7 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
Uint8 b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel;
if (v0.colors.a == 255) {
if (appearance.color.a == 255) {
zref = z;
if (texels) {
@ -362,7 +355,7 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
}
else {
// Transparent alpha blending with vertex alpha
BlendPixel(pixelAddr, r, g, b, v0.colors.a);
BlendPixel(pixelAddr, r, g, b, appearance.color.a);
}
}
}
@ -461,21 +454,47 @@ const char* Direct3DRMSoftwareRenderer::GetName()
return "Miniwin Emulation";
}
HRESULT Direct3DRMSoftwareRenderer::Render()
HRESULT Direct3DRMSoftwareRenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
{
if (!DDBackBuffer || m_vertexBuffer.size() % 3 != 0 || !SDL_LockSurface(DDBackBuffer)) {
if (!DDBackBuffer || !SDL_LockSurface(DDBackBuffer)) {
return DDERR_GENERIC;
}
ClearZBuffer();
memcpy(m_viewMatrix, viewMatrix, sizeof(D3DRMMATRIX4D));
m_format = SDL_GetPixelFormatDetails(DDBackBuffer->format);
m_palette = SDL_GetSurfacePalette(DDBackBuffer);
m_bytesPerPixel = m_format->bits_per_pixel / 8;
for (size_t i = 0; i + 2 < m_vertexBuffer.size(); i += 3) {
DrawTriangleClipped(m_vertexBuffer[i], m_vertexBuffer[i + 1], m_vertexBuffer[i + 2]);
}
SDL_UnlockSurface(DDBackBuffer);
m_vertexBuffer.clear();
return DD_OK;
}
void Direct3DRMSoftwareRenderer::SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
)
{
D3DRMMATRIX4D mvMatrix;
MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix);
for (size_t i = 0; i + 2 < count; i += 3) {
GeometryVertex vrts[3];
for (size_t j = 0; j < 3; ++j) {
const GeometryVertex& src = vertices[i + j];
vrts[j].position = TransformPoint(src.position, mvMatrix);
vrts[j].normals = Normalize(TransformNormal(src.normals, normalMatrix));
vrts[j].texCoord = src.texCoord;
}
DrawTriangleClipped(vrts, appearance);
}
}
HRESULT Direct3DRMSoftwareRenderer::FinalizeFrame()
{
SDL_UnlockSurface(DDBackBuffer);
return DD_OK;
}

View File

@ -3,6 +3,7 @@
#include "d3drmrenderer.h"
#include "d3drmviewport_impl.h"
#include "ddraw_impl.h"
#include "mathutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
@ -12,8 +13,6 @@
#include <functional>
#include <math.h>
typedef D3DVALUE Matrix3x3[3][3];
Direct3DRMViewportImpl::Direct3DRMViewportImpl(DWORD width, DWORD height, Direct3DRMRenderer* rendere)
: m_width(width), m_height(height), m_renderer(rendere)
{
@ -101,16 +100,6 @@ inline D3DVECTOR CrossProduct(const D3DVECTOR& a, const D3DVECTOR& b)
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
inline D3DVECTOR Normalize(const D3DVECTOR& v)
{
float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
if (len > 0.0f) {
float invLen = 1.0f / len;
return {v.x * invLen, v.y * invLen, v.z * invLen};
}
return {0, 0, 0};
}
D3DVECTOR ComputeTriangleNormal(const D3DVECTOR& v0, const D3DVECTOR& v1, const D3DVECTOR& v2)
{
D3DVECTOR u = {v1.x - v0.x, v1.y - v0.y, v1.z - v0.z};
@ -121,24 +110,6 @@ D3DVECTOR ComputeTriangleNormal(const D3DVECTOR& v0, const D3DVECTOR& v1, const
return normal;
}
inline D3DVECTOR TransformNormal(const D3DVECTOR& v, const Matrix3x3& m)
{
return {
v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0],
v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1],
v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2]
};
}
inline D3DVECTOR TransformPoint(const D3DVECTOR& p, const D3DRMMATRIX4D& m)
{
return {
p.x * m[0][0] + p.y * m[1][0] + p.z * m[2][0] + m[3][0],
p.x * m[0][1] + p.y * m[1][1] + p.z * m[2][1] + m[3][1],
p.x * m[0][2] + p.y * m[1][2] + p.z * m[2][2] + m[3][2]
};
}
void Direct3DRMViewportImpl::CollectLightsFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentToWorld,
@ -241,11 +212,7 @@ bool IsBoxInFrustum(const D3DVECTOR corners[8], const Plane planes[6])
return true;
}
void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix,
std::vector<PositionColorVertex>& verts
)
void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix)
{
Direct3DRMFrameImpl* frameImpl = static_cast<Direct3DRMFrameImpl*>(frame);
D3DRMMATRIX4D localMatrix;
@ -267,7 +234,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* childFrame = nullptr;
visual->QueryInterface(IID_IDirect3DRMFrame, (void**) &childFrame);
if (childFrame) {
CollectMeshesFromFrame(childFrame, worldMatrix, verts);
CollectMeshesFromFrame(childFrame, worldMatrix);
childFrame->Release();
visual->Release();
continue;
@ -306,6 +273,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
DWORD vtxCount, faceCount, vpf, dataSize;
mesh->GetGroup(gi, &vtxCount, &faceCount, &vpf, &dataSize, nullptr);
std::vector<GeometryVertex> verts(dataSize * vpf);
std::vector<D3DRMVERTEX> d3dVerts(vtxCount);
std::vector<DWORD> faces(dataSize);
mesh->GetVertices(gi, 0, vtxCount, d3dVerts.data());
@ -316,9 +284,9 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMTexture* texture = nullptr;
mesh->GetGroupTexture(gi, &texture);
Uint32 texId = NO_TEXTURE_ID;
Uint32 textureId = NO_TEXTURE_ID;
if (texture) {
texId = m_renderer->GetTextureId(texture);
textureId = m_renderer->GetTextureId(texture);
texture->Release();
}
@ -346,22 +314,21 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
norm = dv.normal;
}
D3DVECTOR worldPos = TransformPoint(pos, worldMatrix);
D3DVECTOR viewNorm = TransformNormal(norm, worldMatrixInvert);
verts.push_back(
{TransformPoint(worldPos, m_viewMatrix),
Normalize(viewNorm),
{static_cast<Uint8>((color >> 16) & 0xFF),
static_cast<Uint8>((color >> 8) & 0xFF),
static_cast<Uint8>((color >> 0) & 0xFF),
static_cast<Uint8>((color >> 24) & 0xFF)},
texId,
{dv.tu, dv.tv},
shininess}
);
verts.push_back({pos, norm, {dv.tu, dv.tv}});
}
}
m_renderer->SubmitDraw(
verts.data(),
verts.size(),
worldMatrix,
worldMatrixInvert,
{{static_cast<Uint8>((color >> 16) & 0xFF),
static_cast<Uint8>((color >> 8) & 0xFF),
static_cast<Uint8>((color >> 0) & 0xFF),
static_cast<Uint8>((color >> 24) & 0xFF)},
shininess,
textureId}
);
}
mesh->Release();
visual->Release();
@ -369,7 +336,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
visuals->Release();
}
void Direct3DRMViewportImpl::CollectSceneData()
HRESULT Direct3DRMViewportImpl::RenderScene()
{
m_backgroundColor = static_cast<Direct3DRMFrameImpl*>(m_rootFrame)->m_backgroundColor;
@ -384,11 +351,14 @@ void Direct3DRMViewportImpl::CollectSceneData()
std::vector<SceneLight> lights;
CollectLightsFromFrame(m_rootFrame, identity, lights);
m_renderer->PushLights(lights.data(), lights.size());
HRESULT status = m_renderer->BeginFrame(m_viewMatrix);
if (status != DD_OK) {
return status;
}
std::vector<PositionColorVertex> verts;
ExtractFrustumPlanes(viewProj);
CollectMeshesFromFrame(m_rootFrame, identity, verts);
m_renderer->PushVertices(verts.data(), verts.size());
CollectMeshesFromFrame(m_rootFrame, identity);
return m_renderer->FinalizeFrame();
}
HRESULT Direct3DRMViewportImpl::Render(IDirect3DRMFrame* rootFrame)
@ -397,8 +367,7 @@ HRESULT Direct3DRMViewportImpl::Render(IDirect3DRMFrame* rootFrame)
return DDERR_GENERIC;
}
m_rootFrame = rootFrame;
CollectSceneData();
return m_renderer->Render();
return RenderScene();
}
HRESULT Direct3DRMViewportImpl::ForceUpdate(int x, int y, int w, int h)

View File

@ -1,5 +1,6 @@
#pragma once
#include "mathutils.h"
#include "miniwin/d3drm.h"
#include <SDL3/SDL.h>
@ -10,15 +11,18 @@ struct TexCoord {
float u, v;
};
struct PositionColorVertex {
struct GeometryVertex {
D3DVECTOR position;
D3DVECTOR normals;
SDL_Color colors;
Uint32 texId;
TexCoord texCoord;
float shininess;
};
static_assert(sizeof(PositionColorVertex) == 44);
static_assert(sizeof(GeometryVertex) == 32);
struct Appearance {
SDL_Color color;
float shininess;
Uint32 textureId;
};
struct FColor {
float r, g, b, a;
@ -35,13 +39,20 @@ static_assert(sizeof(SceneLight) == 48);
class Direct3DRMRenderer : public IDirect3DDevice2 {
public:
virtual void PushVertices(const PositionColorVertex* vertices, size_t count) = 0;
virtual void PushLights(const SceneLight* vertices, size_t count) = 0;
virtual void SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back) = 0;
virtual void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) = 0;
virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0;
virtual DWORD GetWidth() = 0;
virtual DWORD GetHeight() = 0;
virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0;
virtual const char* GetName() = 0;
virtual HRESULT Render() = 0;
virtual HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) = 0;
virtual void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) = 0;
virtual HRESULT FinalizeFrame() = 0;
};

View File

@ -15,23 +15,30 @@ public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
OpenGL15Renderer(int width, int height, SDL_GLContext context, GLuint fbo, GLuint colorTex, GLuint depthRb);
~OpenGL15Renderer() override;
void PushVertices(const PositionColorVertex* verts, size_t count) override;
void PushLights(const SceneLight* lightsArray, size_t count) override;
void SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override;
HRESULT Render() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
private:
SDL_GLContext m_context;
D3DRMMATRIX4D m_viewMatrix;
D3DRMMATRIX4D m_projection;
SDL_Surface* m_renderedImage;
int m_width, m_height;
std::vector<PositionColorVertex> m_vertices;
std::vector<SceneLight> m_lights;
SDL_GLContext m_context;
GLuint m_fbo = 0;
GLuint m_colorTex = 0;
GLuint m_depthRb = 0;

View File

@ -8,34 +8,50 @@
DEFINE_GUID(SDL3_GPU_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
typedef struct {
D3DRMMATRIX4D perspective;
D3DRMMATRIX4D projection;
D3DRMMATRIX4D worldViewMatrix;
} ViewportUniforms;
static_assert(sizeof(ViewportUniforms) % 16 == 0);
static_assert(sizeof(ViewportUniforms) == 128);
struct SceneLights {
struct FragmentShadingData {
SceneLight lights[3];
int count;
int lightCount;
float shininess;
SDL_Color color;
int padding1[1];
};
static_assert(sizeof(FragmentShadingData) % 16 == 0);
static_assert(sizeof(FragmentShadingData) == 160);
class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
public:
static Direct3DRMRenderer* Create(DWORD width, DWORD height);
~Direct3DRMSDL3GPURenderer() override;
void PushVertices(const PositionColorVertex* vertices, size_t count) override;
void PushLights(const SceneLight* vertices, size_t count) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
void SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override;
HRESULT Render() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
private:
Direct3DRMSDL3GPURenderer(
DWORD width,
DWORD height,
SDL_GPUDevice* device,
SDL_GPUGraphicsPipeline* pipeline,
SDL_GPUGraphicsPipeline* opaquePipeline,
SDL_GPUGraphicsPipeline* transparentPipeline,
SDL_GPUTexture* transferTexture,
SDL_GPUTexture* depthTexture,
SDL_GPUTransferBuffer* downloadTransferBuffer
@ -49,10 +65,12 @@ private:
int m_vertexCount;
int m_vertexBufferCount = 0;
ViewportUniforms m_uniforms;
SceneLights m_lights;
FragmentShadingData m_fragmentShadingData;
D3DDEVICEDESC m_desc;
D3DRMMATRIX4D m_viewMatrix;
SDL_GPUDevice* m_device;
SDL_GPUGraphicsPipeline* m_pipeline;
SDL_GPUGraphicsPipeline* m_opaquePipeline;
SDL_GPUGraphicsPipeline* m_transparentPipeline;
SDL_GPUTexture* m_transferTexture;
SDL_GPUTexture* m_depthTexture;
SDL_GPUTransferBuffer* m_downloadTransferBuffer;

View File

@ -19,27 +19,35 @@ struct TextureCache {
class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
public:
Direct3DRMSoftwareRenderer(DWORD width, DWORD height);
void PushVertices(const PositionColorVertex* vertices, size_t count) override;
void PushLights(const SceneLight* vertices, size_t count) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture) override;
void SetProjection(D3DRMMATRIX4D perspective, D3DVALUE front, D3DVALUE back) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
DWORD GetWidth() override;
DWORD GetHeight() override;
void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override;
const char* GetName() override;
HRESULT Render() override;
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const GeometryVertex* vertices,
const size_t count,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
private:
void ClearZBuffer();
void DrawTriangleProjected(const PositionColorVertex&, const PositionColorVertex&, const PositionColorVertex&);
void DrawTriangleClipped(
const PositionColorVertex& v0,
const PositionColorVertex& v1,
const PositionColorVertex& v2
void DrawTriangleProjected(
const GeometryVertex& v0,
const GeometryVertex& v1,
const GeometryVertex& v2,
const Appearance& appearance
);
void ProjectVertex(const PositionColorVertex& v, D3DRMVECTOR4D& p) const;
void DrawTriangleClipped(const GeometryVertex (&v)[3], const Appearance& appearance);
void ProjectVertex(const GeometryVertex& v, D3DRMVECTOR4D& p) const;
void BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
SDL_Color ApplyLighting(const PositionColorVertex& vertex);
SDL_Color ApplyLighting(const GeometryVertex& vertex, const Appearance& appearance);
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
DWORD m_width;
@ -51,8 +59,8 @@ private:
std::vector<TextureCache> m_textures;
D3DVALUE m_front;
D3DVALUE m_back;
std::vector<PositionColorVertex> m_vertexBuffer;
float proj[4][4] = {0};
D3DRMMATRIX4D m_viewMatrix;
D3DRMMATRIX4D m_projection;
std::vector<float> m_zBuffer;
};

View File

@ -35,13 +35,9 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMViewp
void CloseDevice();
private:
void CollectSceneData();
HRESULT RenderScene();
void CollectLightsFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix, std::vector<SceneLight>& lights);
void CollectMeshesFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix,
std::vector<PositionColorVertex>& verts
);
void CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix);
void UpdateProjectionMatrix();
Direct3DRMRenderer* m_renderer;
D3DCOLOR m_backgroundColor = 0xFF000000;

View File

@ -0,0 +1,47 @@
#pragma once
#include "miniwin/d3drm.h"
#include <math.h>
typedef D3DVALUE Matrix3x3[3][3];
inline D3DVECTOR TransformNormal(const D3DVECTOR& v, const Matrix3x3& m)
{
return {
v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0],
v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1],
v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2]
};
}
inline D3DVECTOR Normalize(const D3DVECTOR& v)
{
float len = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
if (len > 0.0f) {
float invLen = 1.0f / len;
return {v.x * invLen, v.y * invLen, v.z * invLen};
}
return {0, 0, 0};
}
inline D3DVECTOR TransformPoint(const D3DVECTOR& p, const D3DRMMATRIX4D& m)
{
return {
p.x * m[0][0] + p.y * m[1][0] + p.z * m[2][0] + m[3][0],
p.x * m[0][1] + p.y * m[1][1] + p.z * m[2][1] + m[3][1],
p.x * m[0][2] + p.y * m[1][2] + p.z * m[2][2] + m[3][2]
};
}
inline void MultiplyMatrix(D3DRMMATRIX4D& out, const D3DRMMATRIX4D& a, const D3DRMMATRIX4D& b)
{
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 4; ++col) {
out[row][col] = 0.0;
for (int k = 0; k < 4; ++k) {
out[row][col] += a[row][k] * b[k][col];
}
}
}
}