Use indexed faces (#257)

This commit is contained in:
Anders Jenbo 2025-06-09 04:56:29 +02:00 committed by GitHub
parent 897700c19a
commit cd4a24ec9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 282 additions and 122 deletions

View File

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

View File

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

View File

@ -2,8 +2,10 @@
#include "ddraw_impl.h" #include "ddraw_impl.h"
#include "ddsurface_impl.h" #include "ddsurface_impl.h"
#include "mathutils.h" #include "mathutils.h"
#include "meshutils.h"
#include <GL/glew.h> #include <GL/glew.h>
#include <algorithm>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
@ -305,7 +307,9 @@ HRESULT OpenGL15Renderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
void OpenGL15Renderer::SubmitDraw( void OpenGL15Renderer::SubmitDraw(
const D3DRMVERTEX* vertices, const D3DRMVERTEX* vertices,
const size_t count, const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix, const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
@ -319,27 +323,46 @@ void OpenGL15Renderer::SubmitDraw(
glLoadMatrixf(&mvMatrix[0][0]); glLoadMatrixf(&mvMatrix[0][0]);
glEnable(GL_NORMALIZE); glEnable(GL_NORMALIZE);
glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a); std::vector<D3DRMVERTEX> newVertices;
std::vector<DWORD> newIndices;
// 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);
}
if (appearance.flat) { if (appearance.flat) {
glShadeModel(GL_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 { else {
glShadeModel(GL_SMOOTH); 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; float shininess = appearance.shininess;
glMaterialf(GL_FRONT, GL_SHININESS, shininess); glMaterialf(GL_FRONT, GL_SHININESS, shininess);
if (shininess != 0.0f) { if (shininess != 0.0f) {
@ -351,14 +374,29 @@ void OpenGL15Renderer::SubmitDraw(
glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec); glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec);
} }
glBegin(GL_TRIANGLES); std::vector<D3DVECTOR> positions;
for (size_t i = 0; i < count; i++) { positions.resize(newVertices.size());
const D3DRMVERTEX& v = vertices[i]; std::transform(newVertices.begin(), newVertices.end(), positions.begin(), [](const D3DRMVERTEX& v) {
glNormal3f(v.normal.x, v.normal.y, v.normal.z); return v.position;
glTexCoord2f(v.texCoord.u, v.texCoord.v); });
glVertex3f(v.position.x, v.position.y, v.position.z); 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(); glPopMatrix();
} }

View File

@ -3,6 +3,7 @@
#include "d3drmrenderer_sdl3gpu.h" #include "d3drmrenderer_sdl3gpu.h"
#include "ddraw_impl.h" #include "ddraw_impl.h"
#include "mathutils.h" #include "mathutils.h"
#include "meshutils.h"
#include "miniwin.h" #include "miniwin.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
@ -600,7 +601,9 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size)
void Direct3DRMSDL3GPURenderer::SubmitDraw( void Direct3DRMSDL3GPURenderer::SubmitDraw(
const D3DRMVERTEX* vertices, const D3DRMVERTEX* vertices,
const size_t count, const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix, const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
@ -613,21 +616,46 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw(
m_fragmentShadingData.color = appearance.color; m_fragmentShadingData.color = appearance.color;
m_fragmentShadingData.shininess = appearance.shininess; 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) { if (m_vertexBuffer) {
SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer); SDL_ReleaseGPUBuffer(m_device, m_vertexBuffer);
} }
SDL_GPUBufferCreateInfo bufferCreateInfo = {}; SDL_GPUBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.usage = SDL_GPU_BUFFERUSAGE_VERTEX; 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); m_vertexBuffer = SDL_CreateGPUBuffer(m_device, &bufferCreateInfo);
if (!m_vertexBuffer) { if (!m_vertexBuffer) {
SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUBuffer failed (%s)", SDL_GetError()); 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); SDL_GPUTransferBuffer* uploadBuffer = GetUploadBuffer(sizeof(D3DRMVERTEX) * m_vertexCount);
if (!uploadBuffer) { if (!uploadBuffer) {
@ -639,7 +667,7 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw(
return; return;
} }
memcpy(transferData, vertices, m_vertexCount * sizeof(D3DRMVERTEX)); memcpy(transferData, flatVertices.data(), m_vertexCount * sizeof(D3DRMVERTEX));
SDL_UnmapGPUTransferBuffer(m_device, uploadBuffer); SDL_UnmapGPUTransferBuffer(m_device, uploadBuffer);
// Upload the transfer data to the vertex buffer // Upload the transfer data to the vertex buffer

View File

@ -2,6 +2,7 @@
#include "d3drmrenderer_software.h" #include "d3drmrenderer_software.h"
#include "ddsurface_impl.h" #include "ddsurface_impl.h"
#include "mathutils.h" #include "mathutils.h"
#include "meshutils.h"
#include "miniwin.h" #include "miniwin.h"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
@ -452,7 +453,9 @@ HRESULT Direct3DRMSoftwareRenderer::BeginFrame(const D3DRMMATRIX4D& viewMatrix)
void Direct3DRMSoftwareRenderer::SubmitDraw( void Direct3DRMSoftwareRenderer::SubmitDraw(
const D3DRMVERTEX* vertices, const D3DRMVERTEX* vertices,
const size_t count, const size_t vertexCount,
const DWORD* indices,
const size_t indexCount,
const D3DRMMATRIX4D& worldMatrix, const D3DRMMATRIX4D& worldMatrix,
const Matrix3x3& normalMatrix, const Matrix3x3& normalMatrix,
const Appearance& appearance const Appearance& appearance
@ -461,15 +464,42 @@ void Direct3DRMSoftwareRenderer::SubmitDraw(
D3DRMMATRIX4D mvMatrix; D3DRMMATRIX4D mvMatrix;
MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix); MultiplyMatrix(mvMatrix, worldMatrix, m_viewMatrix);
for (size_t i = 0; i + 2 < count; i += 3) { std::vector<D3DRMVERTEX> newVertices;
D3DRMVERTEX vrts[3]; std::vector<DWORD> newIndices;
for (size_t j = 0; j < 3; ++j) { if (appearance.flat) {
const D3DRMVERTEX& src = vertices[i + j]; // FIXME move this to a one time mesh upload stage
vrts[j].position = TransformPoint(src.position, mvMatrix); FlattenSurfaces(
vrts[j].normal = Normalize(TransformNormal(src.normal, normalMatrix)); vertices,
vrts[j].texCoord = src.texCoord; vertexCount,
} indices,
DrawTriangleClipped(vrts, appearance); 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; group.vertexPerFace = vertexPerFace;
DWORD* src = faceBuffer; DWORD* src = faceBuffer;
group.faces.assign(src, src + faceCount * vertexPerFace); group.indices.assign(src, src + faceCount * vertexPerFace);
m_groups.push_back(std::move(group)); m_groups.push_back(std::move(group));
@ -72,8 +72,8 @@ HRESULT Direct3DRMMeshImpl::GetGroup(
DWORD* vertexCount, DWORD* vertexCount,
DWORD* faceCount, DWORD* faceCount,
DWORD* vertexPerFace, DWORD* vertexPerFace,
DWORD* dataSize, DWORD* indexCount,
DWORD* data DWORD* indices
) )
{ {
if (groupIndex >= m_groups.size()) { if (groupIndex >= m_groups.size()) {
@ -86,16 +86,16 @@ HRESULT Direct3DRMMeshImpl::GetGroup(
*vertexCount = static_cast<DWORD>(group.vertices.size()); *vertexCount = static_cast<DWORD>(group.vertices.size());
} }
if (faceCount) { if (faceCount) {
*faceCount = static_cast<DWORD>(group.faces.size() / group.vertexPerFace); *faceCount = static_cast<DWORD>(group.indices.size() / group.vertexPerFace);
} }
if (vertexPerFace) { if (vertexPerFace) {
*vertexPerFace = static_cast<DWORD>(group.vertexPerFace); *vertexPerFace = static_cast<DWORD>(group.vertexPerFace);
} }
if (dataSize) { if (indexCount) {
*dataSize = static_cast<DWORD>(group.faces.size()); *indexCount = static_cast<DWORD>(group.indices.size());
} }
if (data) { if (indices) {
std::copy(group.faces.begin(), group.faces.end(), reinterpret_cast<unsigned int*>(data)); std::copy(group.indices.begin(), group.indices.end(), reinterpret_cast<unsigned int*>(indices));
} }
return DD_OK; return DD_OK;

View File

@ -95,21 +95,6 @@ static void ComputeFrameWorldMatrix(IDirect3DRMFrame* frame, D3DRMMATRIX4D out)
memcpy(out, acc, sizeof(acc)); 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( void Direct3DRMViewportImpl::CollectLightsFromFrame(
IDirect3DRMFrame* frame, IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentToWorld, D3DRMMATRIX4D parentToWorld,
@ -215,9 +200,8 @@ bool IsBoxInFrustum(const D3DVECTOR corners[8], const Plane planes[6])
void Direct3DRMViewportImpl::CollectMeshesFromFrame( void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* frame, IDirect3DRMFrame* frame,
D3DRMMATRIX4D parentMatrix, D3DRMMATRIX4D parentMatrix,
std::vector<D3DRMVERTEX>& verts,
std::vector<D3DRMVERTEX>& d3dVerts, std::vector<D3DRMVERTEX>& d3dVerts,
std::vector<DWORD>& faces std::vector<DWORD>& indices
) )
{ {
Direct3DRMFrameImpl* frameImpl = static_cast<Direct3DRMFrameImpl*>(frame); Direct3DRMFrameImpl* frameImpl = static_cast<Direct3DRMFrameImpl*>(frame);
@ -240,7 +224,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
IDirect3DRMFrame* childFrame = nullptr; IDirect3DRMFrame* childFrame = nullptr;
visual->QueryInterface(IID_IDirect3DRMFrame, (void**) &childFrame); visual->QueryInterface(IID_IDirect3DRMFrame, (void**) &childFrame);
if (childFrame) { if (childFrame) {
CollectMeshesFromFrame(childFrame, worldMatrix, verts, d3dVerts, faces); CollectMeshesFromFrame(childFrame, worldMatrix, d3dVerts, indices);
childFrame->Release(); childFrame->Release();
visual->Release(); visual->Release();
continue; continue;
@ -276,19 +260,16 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
DWORD groupCount = mesh->GetGroupCount(); DWORD groupCount = mesh->GetGroupCount();
for (DWORD gi = 0; gi < groupCount; ++gi) { for (DWORD gi = 0; gi < groupCount; ++gi) {
DWORD vtxCount, faceCount, vpf, dataSize; DWORD vtxCount, indexCount;
mesh->GetGroup(gi, &vtxCount, &faceCount, &vpf, &dataSize, nullptr); mesh->GetGroup(gi, &vtxCount, nullptr, nullptr, &indexCount, nullptr);
verts.reserve(dataSize);
verts.clear();
d3dVerts.resize(vtxCount); d3dVerts.resize(vtxCount);
faces.resize(dataSize); indices.resize(indexCount);
mesh->GetVertices(gi, 0, vtxCount, d3dVerts.data()); 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); D3DCOLOR color = mesh->GetGroupColor(gi);
D3DRMRENDERQUALITY quality = mesh->GetGroupQuality(gi); D3DRMRENDERQUALITY quality = mesh->GetGroupQuality(gi);
bool flat = quality == D3DRMRENDER_FLAT || quality == D3DRMRENDER_UNLITFLAT;
IDirect3DRMTexture* texture = nullptr; IDirect3DRMTexture* texture = nullptr;
mesh->GetGroupTexture(gi, &texture); mesh->GetGroupTexture(gi, &texture);
@ -306,28 +287,11 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
material->Release(); 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( m_renderer->SubmitDraw(
verts.data(), d3dVerts.data(),
verts.size(), d3dVerts.size(),
indices.data(),
indices.size(),
worldMatrix, worldMatrix,
worldMatrixInvert, worldMatrixInvert,
{{static_cast<Uint8>((color >> 16) & 0xFF), {{static_cast<Uint8>((color >> 16) & 0xFF),
@ -336,7 +300,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
static_cast<Uint8>((color >> 24) & 0xFF)}, static_cast<Uint8>((color >> 24) & 0xFF)},
shininess, shininess,
textureId, textureId,
flat} quality == D3DRMRENDER_FLAT || quality == D3DRMRENDER_UNLITFLAT}
); );
} }
mesh->Release(); mesh->Release();
@ -365,11 +329,10 @@ HRESULT Direct3DRMViewportImpl::RenderScene()
return status; return status;
} }
std::vector<D3DRMVERTEX> verts;
std::vector<D3DRMVERTEX> d3dVerts; std::vector<D3DRMVERTEX> d3dVerts;
std::vector<DWORD> faces; std::vector<DWORD> indices;
ExtractFrustumPlanes(viewProj); ExtractFrustumPlanes(viewProj);
CollectMeshesFromFrame(m_rootFrame, identity, verts, d3dVerts, faces); CollectMeshesFromFrame(m_rootFrame, identity, d3dVerts, indices);
return m_renderer->FinalizeFrame(); return m_renderer->FinalizeFrame();
} }
@ -724,23 +687,19 @@ bool RayIntersectsMeshTriangles(
{ {
DWORD groupCount = mesh->GetGroupCount(); DWORD groupCount = mesh->GetGroupCount();
for (DWORD g = 0; g < groupCount; ++g) { for (DWORD g = 0; g < groupCount; ++g) {
DWORD vtxCount = 0, faceCount = 0, vpf = 0, dataSize = 0; DWORD vtxCount, faceCount, indexCount;
mesh->GetGroup(g, &vtxCount, &faceCount, &vpf, &dataSize, nullptr); mesh->GetGroup(g, &vtxCount, &faceCount, nullptr, &indexCount, nullptr);
std::vector<D3DRMVERTEX> vertices(vtxCount); std::vector<D3DRMVERTEX> vertices(vtxCount);
mesh->GetVertices(g, 0, vtxCount, vertices.data()); mesh->GetVertices(g, 0, vtxCount, vertices.data());
std::vector<DWORD> faces(faceCount * vpf); std::vector<DWORD> indices(indexCount);
mesh->GetGroup(g, nullptr, nullptr, nullptr, nullptr, faces.data()); mesh->GetGroup(g, nullptr, nullptr, nullptr, nullptr, indices.data());
// Iterate over each face and do ray-triangle tests // Iterate over each face and do ray-triangle tests
for (DWORD fi = 0; fi < faceCount; ++fi) { for (DWORD fi = 0; fi < faceCount; fi += 3) {
DWORD i0 = faces[fi * vpf + 0]; DWORD i0 = indices[fi + 0];
DWORD i1 = faces[fi * vpf + 1]; DWORD i1 = indices[fi + 1];
DWORD i2 = faces[fi * vpf + 2]; DWORD i2 = indices[fi + 2];
if (i0 >= vtxCount || i1 >= vtxCount || i2 >= vtxCount) {
continue;
}
// Transform vertices to world space // Transform vertices to world space
D3DVECTOR tri[3]; D3DVECTOR tri[3];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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