Merge branch 'master' into add-IDirect3DRMMiniwinDevice-interface

This commit is contained in:
Anders Jenbo 2025-06-09 05:08:24 +02:00 committed by GitHub
commit 9af819ab5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 335 additions and 144 deletions

View File

@ -18,6 +18,7 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL
src/d3drm/d3drmmesh.cpp
src/d3drm/d3drmtexture.cpp
src/d3drm/d3drmviewport.cpp
src/internal/meshutils.cpp
# D3DRM backends
src/d3drm/backends/software/renderer.cpp

View File

@ -192,8 +192,8 @@ struct IDirect3DRMMesh : public IDirect3DRMVisual {
DWORD* vertexCount,
DWORD* faceCount,
DWORD* vertexPerFace,
DWORD* dataSize,
DWORD* data
DWORD* indexCount,
DWORD* indices
) = 0;
virtual DWORD GetGroupCount() = 0;
virtual HRESULT SetGroupColor(DWORD groupIndex, D3DCOLOR color) = 0;

View File

@ -2,8 +2,10 @@
#include "ddraw_impl.h"
#include "ddsurface_impl.h"
#include "mathutils.h"
#include "meshutils.h"
#include <GL/glew.h>
#include <algorithm>
#include <cstring>
#include <vector>
@ -305,7 +307,9 @@ HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
void OpenGL15Renderer::SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -319,27 +323,46 @@ void OpenGL15Renderer::SubmitDraw(
glLoadMatrixf(&mvMatrix[0][0]);
glEnable(GL_NORMALIZE);
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
// Bind texture if present
if (appearance.textureId != NO_TEXTURE_ID) {
auto& tex = m_textures[appearance.textureId];
if (tex.glTextureId) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
}
}
else {
glDisable(GL_TEXTURE_2D);
}
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
if (appearance.flat) {
glShadeModel(GL_FLAT);
// FIXME move this to a one time mesh upload stage
FlattenSurfaces(
vertices,
vertexCount,
indices,
indexCount,
appearance.textureId != NO_TEXTURE_ID,
newVertices,
newIndices
);
}
else {
glShadeModel(GL_SMOOTH);
newVertices.assign(vertices, vertices + vertexCount);
newIndices.assign(indices, indices + indexCount);
}
// Bind texture if present
std::vector<TexCoord> texcoords;
if (appearance.textureId != NO_TEXTURE_ID) {
auto& tex = m_textures[appearance.textureId];
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex.glTextureId);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
texcoords.resize(newVertices.size());
std::transform(newVertices.begin(), newVertices.end(), texcoords.begin(), [](const D3DRMVERTEX& v) {
return v.texCoord;
});
}
else {
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a);
float shininess = appearance.shininess;
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
if (shininess != 0.0f) {
@ -351,14 +374,29 @@ void OpenGL15Renderer::SubmitDraw(
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
}
glBegin(GL_TRIANGLES);
for (size_t i = 0; i < count; i++) {
const D3DRMVERTEX& v = vertices[i];
glNormal3f(v.normal.x, v.normal.y, v.normal.z);
glTexCoord2f(v.texCoord.u, v.texCoord.v);
glVertex3f(v.position.x, v.position.y, v.position.z);
std::vector<D3DVECTOR> positions;
positions.resize(newVertices.size());
std::transform(newVertices.begin(), newVertices.end(), positions.begin(), [](const D3DRMVERTEX& v) {
return v.position;
});
std::vector<D3DVECTOR> normals;
normals.resize(newVertices.size());
std::transform(newVertices.begin(), newVertices.end(), normals.begin(), [](const D3DRMVERTEX& v) {
return v.normal;
});
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, positions.data());
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals.data());
if (appearance.textureId != NO_TEXTURE_ID) {
glTexCoordPointer(2, GL_FLOAT, 0, texcoords.data());
}
glEnd();
// Draw triangles
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(newIndices.size()), GL_UNSIGNED_INT, newIndices.data());
glPopMatrix();
}

View File

@ -3,6 +3,7 @@
#include "d3drmrenderer_sdl3gpu.h"
#include "ddraw_impl.h"
#include "mathutils.h"
#include "meshutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
@ -600,7 +601,9 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
void Direct3DRMSDL3GPURenderer::SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -613,21 +616,46 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw(
m_fragmentShadingData.color = appearance.color;
m_fragmentShadingData.shininess = appearance.shininess;
if (count > m_vertexBufferCount) {
std::vector<D3DRMVERTEX> flatVertices;
if (appearance.flat) {
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
// FIXME move this to a one time mesh upload stage
FlattenSurfaces(
vertices,
vertexCount,
indices,
indexCount,
appearance.textureId != NO_TEXTURE_ID,
newVertices,
newIndices
);
for (DWORD& index : newIndices) {
flatVertices.push_back(newVertices[index]);
}
}
else {
// TODO handle indexed verticies on GPU
for (int i = 0; i < indexCount; ++i) {
flatVertices.push_back(vertices[indices[i]]);
}
}
if (flatVertices.size() > 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(D3DRMVERTEX) * count);
bufferCreateInfo.size = static_cast<Uint32>(sizeof(D3DRMVERTEX) * flatVertices.size());
m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!m_vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer failed (%s)", SDL_GetError());
}
m_vertexBufferCount = count;
m_vertexBufferCount = flatVertices.size();
}
m_vertexCount = count;
m_vertexCount = flatVertices.size();
SDL_GPUTransferBuffer* uploadBuffer = GetUploadBuffer(sizeof(D3DRMVERTEX) * m_vertexCount);
if (!uploadBuffer) {
@ -639,7 +667,7 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw(
return;
}
memcpy(transferData, vertices, m_vertexCount * sizeof(D3DRMVERTEX));
memcpy(transferData, flatVertices.data(), m_vertexCount * sizeof(D3DRMVERTEX));
SDL_UnmapGPUTransferBuffer(m_device, uploadBuffer);
// Upload the transfer data to the vertex buffer

View File

@ -2,6 +2,7 @@
#include "d3drmrenderer_software.h"
#include "ddsurface_impl.h"
#include "mathutils.h"
#include "meshutils.h"
#include "miniwin.h"
#include <SDL3/SDL.h>
@ -145,15 +146,15 @@ void Direct3DRMSoftwareRenderer::BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g,
memcpy(pixelAddr, &blended, m_bytesPerPixel);
}
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const D3DRMVERTEX& vertex, const Appearance& appearance)
SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(
const D3DVECTOR& position,
const D3DVECTOR& normal,
const Appearance& appearance
)
{
FColor specular = {0, 0, 0, 0};
FColor diffuse = {0, 0, 0, 0};
// Position and normal
D3DVECTOR position = vertex.position;
D3DVECTOR normal = Normalize(vertex.normal);
for (const auto& light : m_lights) {
FColor lightColor = light.color;
@ -200,6 +201,16 @@ SDL_Color Direct3DRMSoftwareRenderer::ApplyLighting(const D3DRMVERTEX& vertex, c
};
}
inline float EdgeFloat(float x0, float y0, float x1, float y1, float x, float y)
{
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
}
inline float EdgeDouble(double x0, double y0, double x1, double y1, double x, double y)
{
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
}
void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
const D3DRMVERTEX& v0,
const D3DRMVERTEX& v1,
@ -234,19 +245,20 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
return;
}
auto edge = [](double x0, double y0, double x1, double y1, double x, double y) {
return (x - x0) * (y1 - y0) - (y - y0) * (x1 - x0);
};
float area = edge(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
// Cull backfaces
float area = EdgeFloat(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
if (area >= 0) {
return;
}
float invArea = 1.0f / area;
// Per-vertex lighting using vertex normals
SDL_Color c0 = ApplyLighting(v0, appearance);
SDL_Color c1 = ApplyLighting(v1, appearance);
SDL_Color c2 = ApplyLighting(v2, appearance);
Uint8 r, g, b;
SDL_Color c0 = ApplyLighting(v0.position, v0.normal, appearance);
SDL_Color c1, c2;
if (!appearance.flat) {
c1 = ApplyLighting(v1.position, v1.normal, appearance);
c2 = ApplyLighting(v2.position, v2.normal, appearance);
}
Uint32 textureId = appearance.textureId;
int texturePitch;
@ -270,12 +282,12 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
for (int x = minX; x <= maxX; ++x) {
float px = x + 0.5f;
float py = y + 0.5f;
float w0 = edge(p1.x, p1.y, p2.x, p2.y, px, py) * invArea;
float w0 = EdgeDouble(p1.x, p1.y, p2.x, p2.y, px, py) * invArea;
if (w0 < 0.0f || w0 > 1.0f) {
continue;
}
float w1 = edge(p2.x, p2.y, p0.x, p0.y, px, py) * invArea;
float w1 = EdgeDouble(p2.x, p2.y, p0.x, p0.y, px, py) * invArea;
if (w1 < 0.0f || w1 > 1.0f - w0) {
continue;
}
@ -289,10 +301,16 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
continue;
}
// Interpolate color
Uint8 r = static_cast<Uint8>(w0 * c0.r + w1 * c1.r + w2 * c2.r);
Uint8 g = static_cast<Uint8>(w0 * c0.g + w1 * c1.g + w2 * c2.g);
Uint8 b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
if (appearance.flat) {
r = c0.r;
g = c0.g;
b = c0.b;
}
else {
r = static_cast<Uint8>(w0 * c0.r + w1 * c1.r + w2 * c2.r);
g = static_cast<Uint8>(w0 * c0.g + w1 * c1.g + w2 * c2.g);
b = static_cast<Uint8>(w0 * c0.b + w1 * c1.b + w2 * c2.b);
}
Uint8* pixelAddr = pixels + y * pitch + x * m_bytesPerPixel;
if (appearance.color.a == 255) {
@ -321,8 +339,22 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected(
Uint8* texelAddr = texels + texY * texturePitch + texX * m_bytesPerPixel;
Uint32 texelColor = 0;
memcpy(&texelColor, texelAddr, m_bytesPerPixel);
Uint32 texelColor;
switch (m_bytesPerPixel) {
case 1:
texelColor = *texelAddr;
break;
case 2:
texelColor = *(Uint16*) texelAddr;
break;
case 3:
// Manually build the 24-bit color (assuming byte order)
texelColor = texelAddr[0] | (texelAddr[1] << 8) | (texelAddr[2] << 16);
break;
case 4:
texelColor = *(Uint32*) texelAddr;
break;
}
Uint8 tr, tg, tb, ta;
SDL_GetRGBA(texelColor, m_format, m_palette, &tr, &tg, &tb, &ta);
@ -452,7 +484,9 @@ HRESULT Direct3DRMSoftwareRenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
void Direct3DRMSoftwareRenderer::SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -461,15 +495,42 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
D3DRMMATRIX4D mvMatrix;
MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix);
for (size_t i = 0; i + 2 < count; i += 3) {
D3DRMVERTEX vrts[3];
for (size_t j = 0; j < 3; ++j) {
const D3DRMVERTEX& src = vertices[i + j];
vrts[j].position = TransformPoint(src.position, mvMatrix);
vrts[j].normal = Normalize(TransformNormal(src.normal, normalMatrix));
vrts[j].texCoord = src.texCoord;
}
DrawTriangleClipped(vrts, appearance);
std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
if (appearance.flat) {
// FIXME move this to a one time mesh upload stage
FlattenSurfaces(
vertices,
vertexCount,
indices,
indexCount,
appearance.textureId != NO_TEXTURE_ID,
newVertices,
newIndices
);
}
else {
newVertices.assign(vertices, vertices + vertexCount);
newIndices.assign(indices, indices + indexCount);
}
// Pre-transform all vertex positions and normals
std::vector<D3DRMVERTEX> transformedVerts(newVertices.size());
for (size_t i = 0; i < newVertices.size(); ++i) {
const D3DRMVERTEX& src = newVertices[i];
D3DRMVERTEX& dst = transformedVerts[i];
dst.position = TransformPoint(src.position, mvMatrix);
// TODO defer normal transformation til lighting to allow culling first
dst.normal = Normalize(TransformNormal(src.normal, normalMatrix));
dst.texCoord = src.texCoord;
}
// Assemble triangles using index buffer
for (size_t i = 0; i + 2 < newIndices.size(); i += 3) {
DrawTriangleClipped(
{transformedVerts[newIndices[i]], transformedVerts[newIndices[i + 1]], transformedVerts[newIndices[i + 2]]},
appearance
);
}
}

View File

@ -60,7 +60,7 @@ HRESULT Direct3DRMMeshImpl::AddGroup(
group.vertexPerFace = vertexPerFace;
DWORD* src = faceBuffer;
group.faces.assign(src, src + faceCount * vertexPerFace);
group.indices.assign(src, src + faceCount * vertexPerFace);
m_groups.push_back(std::move(group));
@ -72,8 +72,8 @@ HRESULT Direct3DRMMeshImpl::GetGroup(
DWORD* vertexCount,
DWORD* faceCount,
DWORD* vertexPerFace,
DWORD* dataSize,
DWORD* data
DWORD* indexCount,
DWORD* indices
)
{
if (groupIndex >= m_groups.size()) {
@ -86,16 +86,16 @@ HRESULT Direct3DRMMeshImpl::GetGroup(
*vertexCount = static_cast<DWORD>(group.vertices.size());
}
if (faceCount) {
*faceCount = static_cast<DWORD>(group.faces.size() / group.vertexPerFace);
*faceCount = static_cast<DWORD>(group.indices.size() / group.vertexPerFace);
}
if (vertexPerFace) {
*vertexPerFace = static_cast<DWORD>(group.vertexPerFace);
}
if (dataSize) {
*dataSize = static_cast<DWORD>(group.faces.size());
if (indexCount) {
*indexCount = static_cast<DWORD>(group.indices.size());
}
if (data) {
std::copy(group.faces.begin(), group.faces.end(), reinterpret_cast<unsigned int*>(data));
if (indices) {
std::copy(group.indices.begin(), group.indices.end(), reinterpret_cast<unsigned int*>(indices));
}
return DD_OK;

View File

@ -95,21 +95,6 @@ static void ComputeFrameWorldMatrix(IDirect3DRMFrame* frame, D3DRMMATRIX4D out)
memcpy(out, acc, sizeof(acc));
}
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};
}
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};
D3DVECTOR v = {v2.x - v0.x, v2.y - v0.y, v2.z - v0.z};
D3DVECTOR normal = CrossProduct(u, v);
normal = Normalize(normal);
return normal;
}
void Direct3DRMViewportImpl::CollectLightsFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentToWorld,
@ -215,9 +200,8 @@ bool IsBoxInFrustum(const D3DVECTOR corners[8], const Plane planes[6])
void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix,
std::vector<D3DRMVERTEX>& verts,
std::vector<D3DRMVERTEX>& d3dVerts,
std::vector<DWORD>& faces
std::vector<DWORD>& indices
)
{
Direct3DRMFrameImpl* frameImpl = static_cast<Direct3DRMFrameImpl*>(frame);
@ -242,7 +226,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* childFrame = nullptr;
visual->QueryInterface(IID_IDirect3DRMFrame, (void**) &childFrame);
if (childFrame) {
CollectMeshesFromFrame(childFrame, worldMatrix, verts, d3dVerts, faces);
CollectMeshesFromFrame(childFrame, worldMatrix, d3dVerts, indices);
childFrame->Release();
visual->Release();
continue;
@ -278,19 +262,16 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
DWORD groupCount = mesh->GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) {
DWORD vtxCount, faceCount, vpf, dataSize;
mesh->GetGroup(gi, &vtxCount, &faceCount, &vpf, &dataSize, nullptr);
DWORD vtxCount, indexCount;
mesh->GetGroup(gi, &vtxCount, nullptr, nullptr, &indexCount, nullptr);
verts.reserve(dataSize);
verts.clear();
d3dVerts.resize(vtxCount);
faces.resize(dataSize);
indices.resize(indexCount);
mesh->GetVertices(gi, 0, vtxCount, d3dVerts.data());
mesh->GetGroup(gi, nullptr, nullptr, nullptr, nullptr, faces.data());
mesh->GetGroup(gi, nullptr, nullptr, nullptr, nullptr, indices.data());
D3DCOLOR color = mesh->GetGroupColor(gi);
D3DRMRENDERQUALITY quality = mesh->GetGroupQuality(gi);
bool flat = quality == D3DRMRENDER_FLAT || quality == D3DRMRENDER_UNLITFLAT;
IDirect3DRMTexture* texture = nullptr;
mesh->GetGroupTexture(gi, &texture);
@ -308,28 +289,11 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
material->Release();
}
for (DWORD fi = 0; fi < faceCount; ++fi) {
D3DVECTOR norm;
if (flat) {
D3DRMVERTEX& v0 = d3dVerts[faces[fi * vpf + 0]];
D3DRMVERTEX& v1 = d3dVerts[faces[fi * vpf + 1]];
D3DRMVERTEX& v2 = d3dVerts[faces[fi * vpf + 2]];
norm = ComputeTriangleNormal(v0.position, v1.position, v2.position);
}
for (DWORD idx = 0; idx < vpf; ++idx) {
D3DRMVERTEX& dv = d3dVerts[faces[fi * vpf + idx]];
D3DVECTOR pos = dv.position;
if (quality == D3DRMRENDER_GOURAUD || quality == D3DRMRENDER_PHONG) {
norm = dv.normal;
}
verts.push_back({pos, norm, {dv.tu, dv.tv}});
}
}
m_renderer->SubmitDraw(
verts.data(),
verts.size(),
d3dVerts.data(),
d3dVerts.size(),
indices.data(),
indices.size(),
worldMatrix,
worldMatrixInvert,
{{static_cast<Uint8>((color >> 16) & 0xFF),
@ -338,7 +302,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
static_cast<Uint8>((color >> 24) & 0xFF)},
shininess,
textureId,
flat}
quality == D3DRMRENDER_FLAT || quality == D3DRMRENDER_UNLITFLAT}
);
}
mesh->Release();
@ -367,11 +331,10 @@ HRESULT Direct3DRMViewportImpl::RenderScene()
return status;
}
std::vector<D3DRMVERTEX> verts;
std::vector<D3DRMVERTEX> d3dVerts;
std::vector<DWORD> faces;
std::vector<DWORD> indices;
ExtractFrustumPlanes(viewProj);
CollectMeshesFromFrame(m_rootFrame, identity, verts, d3dVerts, faces);
CollectMeshesFromFrame(m_rootFrame, identity, d3dVerts, indices);
return m_renderer->FinalizeFrame();
}
@ -726,23 +689,19 @@ bool RayIntersectsMeshTriangles(
{
DWORD groupCount = mesh->GetGroupCount();
for (DWORD g = 0; g < groupCount; ++g) {
DWORD vtxCount = 0, faceCount = 0, vpf = 0, dataSize = 0;
mesh->GetGroup(g, &vtxCount, &faceCount, &vpf, &dataSize, nullptr);
DWORD vtxCount, faceCount, indexCount;
mesh->GetGroup(g, &vtxCount, &faceCount, nullptr, &indexCount, nullptr);
std::vector<D3DRMVERTEX> vertices(vtxCount);
mesh->GetVertices(g, 0, vtxCount, vertices.data());
std::vector<DWORD> faces(faceCount * vpf);
mesh->GetGroup(g, nullptr, nullptr, nullptr, nullptr, faces.data());
std::vector<DWORD> indices(indexCount);
mesh->GetGroup(g, nullptr, nullptr, nullptr, nullptr, indices.data());
// Iterate over each face and do ray-triangle tests
for (DWORD fi = 0; fi < faceCount; ++fi) {
DWORD i0 = faces[fi * vpf + 0];
DWORD i1 = faces[fi * vpf + 1];
DWORD i2 = faces[fi * vpf + 2];
if (i0 >= vtxCount || i1 >= vtxCount || i2 >= vtxCount) {
continue;
}
for (DWORD fi = 0; fi < faceCount; fi += 3) {
DWORD i0 = indices[fi + 0];
DWORD i1 = indices[fi + 1];
DWORD i2 = indices[fi + 2];
// Transform vertices to world space
D3DVECTOR tri[3];

View File

@ -12,13 +12,13 @@ struct MeshGroup {
D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD;
int vertexPerFace = 0;
std::vector<D3DRMVERTEX> vertices;
std::vector<unsigned int> faces;
std::vector<unsigned int> indices;
MeshGroup() = default;
MeshGroup(const MeshGroup& other)
: color(other.color), texture(other.texture), material(other.material), quality(other.quality),
vertexPerFace(other.vertexPerFace), vertices(std::move(other.vertices)), faces(std::move(other.faces))
vertexPerFace(other.vertexPerFace), vertices(std::move(other.vertices)), indices(std::move(other.indices))
{
if (texture) {
texture->AddRef();
@ -31,7 +31,7 @@ struct MeshGroup {
// Move constructor
MeshGroup(MeshGroup&& other) noexcept
: color(other.color), texture(other.texture), material(other.material), quality(other.quality),
vertexPerFace(other.vertexPerFace), vertices(other.vertices), faces(other.faces)
vertexPerFace(other.vertexPerFace), vertices(other.vertices), indices(other.indices)
{
other.texture = nullptr;
other.material = nullptr;
@ -46,7 +46,7 @@ struct MeshGroup {
quality = other.quality;
vertexPerFace = other.vertexPerFace;
vertices = std::move(other.vertices);
faces = std::move(other.faces);
indices = std::move(other.indices);
other.texture = nullptr;
other.material = nullptr;
return *this;
@ -73,8 +73,8 @@ struct Direct3DRMMeshImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMMesh> {
DWORD* vertexCount,
DWORD* faceCount,
DWORD* vertexPerFace,
DWORD* dataSize,
DWORD* data
DWORD* indexCount,
DWORD* indices
) override;
DWORD GetGroupCount() override;
HRESULT SetGroupColor(DWORD groupIndex, D3DCOLOR color) override;

View File

@ -14,7 +14,7 @@ struct Appearance {
SDL_Color color;
float shininess;
Uint32 textureId;
bool flat;
Uint32 flat;
};
struct FColor {
@ -42,7 +42,9 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
virtual HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) = 0;
virtual void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance

View File

@ -31,7 +31,9 @@ class OpenGL15Renderer : public Direct3DRMRenderer {
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance

View File

@ -48,7 +48,9 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer {
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance

View File

@ -29,7 +29,9 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
HRESULT BeginFrame(const D3DRMMATRIX4D& viewMatrix) override;
void SubmitDraw(
const D3DRMVERTEX* vertices,
const size_t count,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
@ -48,7 +50,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
void DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance);
void ProjectVertex(const D3DRMVERTEX& v, D3DRMVECTOR4D& p) const;
void BlendPixel(Uint8* pixelAddr, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
SDL_Color ApplyLighting(const D3DRMVERTEX& vertex, const Appearance& appearance);
SDL_Color ApplyLighting(const D3DVECTOR& position, const D3DVECTOR& normal, const Appearance& appearance);
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
DWORD m_width;

View File

@ -40,7 +40,6 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl<IDirect3DRMViewp
void CollectMeshesFromFrame(
IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix,
std::vector<D3DRMVERTEX>& verts,
std::vector<D3DRMVERTEX>& d3dVerts,
std::vector<DWORD>& faces
);

View File

@ -25,6 +25,11 @@ inline D3DVECTOR Normalize(const D3DVECTOR& v)
return {0, 0, 0};
}
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 TransformPoint(const D3DVECTOR& p, const D3DRMMATRIX4D& m)
{
return {

View File

@ -0,0 +1,77 @@
#include "meshutils.h"
#include "mathutils.h"
#include <tuple>
#include <unordered_map>
bool operator==(const D3DRMVERTEX& a, const D3DRMVERTEX& b)
{
return memcmp(&a, &b, sizeof(D3DRMVERTEX)) == 0;
}
namespace std
{
template <>
struct hash<D3DRMVERTEX> {
size_t operator()(const D3DRMVERTEX& v) const
{
const float* f = reinterpret_cast<const float*>(&v);
size_t h = 0;
for (int i = 0; i < sizeof(D3DRMVERTEX) / sizeof(float); ++i) {
h ^= std::hash<float>()(f[i]) + 0x9e3779b9 + (h << 6) + (h >> 2);
}
return h;
}
};
} // namespace std
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};
D3DVECTOR v = {v2.x - v0.x, v2.y - v0.y, v2.z - v0.z};
D3DVECTOR normal = CrossProduct(u, v);
normal = Normalize(normal);
return normal;
}
void FlattenSurfaces(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
bool hasTexture,
std::vector<D3DRMVERTEX>& dedupedVertices,
std::vector<DWORD>& newIndices
)
{
std::unordered_map<D3DRMVERTEX, DWORD> uniqueVertexMap;
dedupedVertices.reserve(vertexCount);
newIndices.reserve(indexCount);
for (size_t i = 0; i < indexCount; i += 3) {
D3DRMVERTEX v0 = vertices[indices[i + 0]];
D3DRMVERTEX v1 = vertices[indices[i + 1]];
D3DRMVERTEX v2 = vertices[indices[i + 2]];
v0.normal = v1.normal = v2.normal = ComputeTriangleNormal(v0.position, v1.position, v2.position);
if (!hasTexture) {
v0.texCoord = v1.texCoord = v2.texCoord = {0.0f, 0.0f};
}
// Deduplicate vertecies
for (const D3DRMVERTEX& v : {v0, v1, v2}) {
auto it = uniqueVertexMap.find(v);
if (it != uniqueVertexMap.end()) {
newIndices.push_back(it->second);
}
else {
DWORD newIndex = static_cast<DWORD>(dedupedVertices.size());
uniqueVertexMap[v] = newIndex;
dedupedVertices.push_back(v);
newIndices.push_back(newIndex);
}
}
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "miniwin/d3drm.h"
#include <vector>
void FlattenSurfaces(
const D3DRMVERTEX* vertices,
const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
bool hasTexture,
std::vector<D3DRMVERTEX>& dedupedVertices,
std::vector<DWORD>& newIndices
);