From cd4a24ec9efca4738ab52ca03e185ea09d3e8f58 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Mon, 9 Jun 2025 04:56:29 +0200 Subject: [PATCH] Use indexed faces (#257) --- miniwin/CMakeLists.txt | 1 + miniwin/include/miniwin/d3drm.h | 4 +- .../src/d3drm/backends/opengl15/renderer.cpp | 82 +++++++++++++----- .../src/d3drm/backends/sdl3gpu/renderer.cpp | 40 +++++++-- .../src/d3drm/backends/software/renderer.cpp | 50 ++++++++--- miniwin/src/d3drm/d3drmmesh.cpp | 16 ++-- miniwin/src/d3drm/d3drmviewport.cpp | 83 +++++-------------- miniwin/src/internal/d3drmmesh_impl.h | 12 +-- miniwin/src/internal/d3drmrenderer.h | 6 +- miniwin/src/internal/d3drmrenderer_opengl15.h | 4 +- miniwin/src/internal/d3drmrenderer_sdl3gpu.h | 4 +- miniwin/src/internal/d3drmrenderer_software.h | 4 +- miniwin/src/internal/d3drmviewport_impl.h | 1 - miniwin/src/internal/mathutils.h | 5 ++ miniwin/src/internal/meshutils.cpp | 77 +++++++++++++++++ miniwin/src/internal/meshutils.h | 15 ++++ 16 files changed, 282 insertions(+), 122 deletions(-) create mode 100644 miniwin/src/internal/meshutils.cpp create mode 100644 miniwin/src/internal/meshutils.h diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index 58ce92f7..0bdda184 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -15,6 +15,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 diff --git a/miniwin/include/miniwin/d3drm.h b/miniwin/include/miniwin/d3drm.h index 3bcd1ffc..307ecd05 100644 --- a/miniwin/include/miniwin/d3drm.h +++ b/miniwin/include/miniwin/d3drm.h @@ -191,8 +191,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; diff --git a/miniwin/src/d3drm/backends/opengl15/renderer.cpp b/miniwin/src/d3drm/backends/opengl15/renderer.cpp index b43b7341..ed13ed36 100644 --- a/miniwin/src/d3drm/backends/opengl15/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl15/renderer.cpp @@ -2,8 +2,10 @@ #include "ddraw_impl.h" #include "ddsurface_impl.h" #include "mathutils.h" +#include "meshutils.h" #include +#include #include #include @@ -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 newVertices; + std::vector 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 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 positions; + positions.resize(newVertices.size()); + std::transform(newVertices.begin(), newVertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { + return v.position; + }); + std::vector 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(newIndices.size()), GL_UNSIGNED_INT, newIndices.data()); glPopMatrix(); } diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index edf130a4..d61f6954 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -3,6 +3,7 @@ #include "d3drmrenderer_sdl3gpu.h" #include "ddraw_impl.h" #include "mathutils.h" +#include "meshutils.h" #include "miniwin.h" #include @@ -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 flatVertices; + if (appearance.flat) { + std::vector newVertices; + std::vector 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(sizeof(D3DRMVERTEX) * count); + bufferCreateInfo.size = static_cast(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 diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index 8e5d627a..a19f6a47 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -2,6 +2,7 @@ #include "d3drmrenderer_software.h" #include "ddsurface_impl.h" #include "mathutils.h" +#include "meshutils.h" #include "miniwin.h" #include @@ -452,7 +453,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 +464,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 newVertices; + std::vector 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 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 + ); } } diff --git a/miniwin/src/d3drm/d3drmmesh.cpp b/miniwin/src/d3drm/d3drmmesh.cpp index de651797..78b3c080 100644 --- a/miniwin/src/d3drm/d3drmmesh.cpp +++ b/miniwin/src/d3drm/d3drmmesh.cpp @@ -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(group.vertices.size()); } if (faceCount) { - *faceCount = static_cast(group.faces.size() / group.vertexPerFace); + *faceCount = static_cast(group.indices.size() / group.vertexPerFace); } if (vertexPerFace) { *vertexPerFace = static_cast(group.vertexPerFace); } - if (dataSize) { - *dataSize = static_cast(group.faces.size()); + if (indexCount) { + *indexCount = static_cast(group.indices.size()); } - if (data) { - std::copy(group.faces.begin(), group.faces.end(), reinterpret_cast(data)); + if (indices) { + std::copy(group.indices.begin(), group.indices.end(), reinterpret_cast(indices)); } return DD_OK; diff --git a/miniwin/src/d3drm/d3drmviewport.cpp b/miniwin/src/d3drm/d3drmviewport.cpp index 0aedea2c..ace78812 100644 --- a/miniwin/src/d3drm/d3drmviewport.cpp +++ b/miniwin/src/d3drm/d3drmviewport.cpp @@ -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& verts, std::vector& d3dVerts, - std::vector& faces + std::vector& indices ) { Direct3DRMFrameImpl* frameImpl = static_cast(frame); @@ -240,7 +224,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; @@ -276,19 +260,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); @@ -306,28 +287,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((color >> 16) & 0xFF), @@ -336,7 +300,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame( static_cast((color >> 24) & 0xFF)}, shininess, textureId, - flat} + quality == D3DRMRENDER_FLAT || quality == D3DRMRENDER_UNLITFLAT} ); } mesh->Release(); @@ -365,11 +329,10 @@ HRESULT Direct3DRMViewportImpl::RenderScene() return status; } - std::vector verts; std::vector d3dVerts; - std::vector faces; + std::vector indices; ExtractFrustumPlanes(viewProj); - CollectMeshesFromFrame(m_rootFrame, identity, verts, d3dVerts, faces); + CollectMeshesFromFrame(m_rootFrame, identity, d3dVerts, indices); return m_renderer->FinalizeFrame(); } @@ -724,23 +687,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 vertices(vtxCount); mesh->GetVertices(g, 0, vtxCount, vertices.data()); - std::vector faces(faceCount * vpf); - mesh->GetGroup(g, nullptr, nullptr, nullptr, nullptr, faces.data()); + std::vector 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]; diff --git a/miniwin/src/internal/d3drmmesh_impl.h b/miniwin/src/internal/d3drmmesh_impl.h index d893e145..726c3c64 100644 --- a/miniwin/src/internal/d3drmmesh_impl.h +++ b/miniwin/src/internal/d3drmmesh_impl.h @@ -12,13 +12,13 @@ struct MeshGroup { D3DRMRENDERQUALITY quality = D3DRMRENDER_GOURAUD; int vertexPerFace = 0; std::vector vertices; - std::vector faces; + std::vector 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 { 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; diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index 2cbef824..448ecf9a 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -13,7 +13,7 @@ struct Appearance { SDL_Color color; float shininess; Uint32 textureId; - bool flat; + Uint32 flat; }; struct FColor { @@ -41,7 +41,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 diff --git a/miniwin/src/internal/d3drmrenderer_opengl15.h b/miniwin/src/internal/d3drmrenderer_opengl15.h index ad59f0e1..16ed55c7 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl15.h +++ b/miniwin/src/internal/d3drmrenderer_opengl15.h @@ -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 diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index 2fbda765..168bde51 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -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 diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 93f5ae68..d253cd52 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -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 diff --git a/miniwin/src/internal/d3drmviewport_impl.h b/miniwin/src/internal/d3drmviewport_impl.h index 6d4cce8c..4010e307 100644 --- a/miniwin/src/internal/d3drmviewport_impl.h +++ b/miniwin/src/internal/d3drmviewport_impl.h @@ -40,7 +40,6 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl& verts, std::vector& d3dVerts, std::vector& faces ); diff --git a/miniwin/src/internal/mathutils.h b/miniwin/src/internal/mathutils.h index e977c5a2..460a7156 100644 --- a/miniwin/src/internal/mathutils.h +++ b/miniwin/src/internal/mathutils.h @@ -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 { diff --git a/miniwin/src/internal/meshutils.cpp b/miniwin/src/internal/meshutils.cpp new file mode 100644 index 00000000..d56f1d54 --- /dev/null +++ b/miniwin/src/internal/meshutils.cpp @@ -0,0 +1,77 @@ +#include "meshutils.h" + +#include "mathutils.h" + +#include +#include + +bool operator==(const D3DRMVERTEX& a, const D3DRMVERTEX& b) +{ + return memcmp(&a, &b, sizeof(D3DRMVERTEX)) == 0; +} + +namespace std +{ +template <> +struct hash { + size_t operator()(const D3DRMVERTEX& v) const + { + const float* f = reinterpret_cast(&v); + size_t h = 0; + for (int i = 0; i < sizeof(D3DRMVERTEX) / sizeof(float); ++i) { + h ^= std::hash()(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& dedupedVertices, + std::vector& newIndices +) +{ + std::unordered_map 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(dedupedVertices.size()); + uniqueVertexMap[v] = newIndex; + dedupedVertices.push_back(v); + newIndices.push_back(newIndex); + } + } + } +} diff --git a/miniwin/src/internal/meshutils.h b/miniwin/src/internal/meshutils.h new file mode 100644 index 00000000..2ffdd17e --- /dev/null +++ b/miniwin/src/internal/meshutils.h @@ -0,0 +1,15 @@ +#pragma once + +#include "miniwin/d3drm.h" + +#include + +void FlattenSurfaces( + const D3DRMVERTEX* vertices, + const size_t vertexCount, + const DWORD* indices, + const size_t indexCount, + bool hasTexture, + std::vector& dedupedVertices, + std::vector& newIndices +);