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/d3drmtexture.cpp
src/d3drm/d3drmviewport.cpp
src/internal/meshutils.cpp
# D3DRM backends
src/d3drm/backends/software/renderer.cpp

View File

@ -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;

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>
@ -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<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);
@ -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<Uint8>((color >> 16) & 0xFF),
@ -336,7 +300,7 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(
static_cast<Uint8>((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<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();
}
@ -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<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

@ -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

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

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
);