// Test MCA mesh simplification
// Build: g++ -std=c++17 -O2 -I src test/test_simplify.cpp src/dc_simplify.cpp -o test/test_simplify
// Run: ./test/test_simplify
#include "dc_simplify.h"
#include <cstdio>
#include <cassert>
#include <cmath>
// Create a simple box mesh (12 triangles, 8 vertices)
static DCMeshData make_box(float size = 1.0f) {
DCMeshData m;
float s = size * 0.5f;
// 8 corners
float verts[][3] = {
{-s,-s,-s}, { s,-s,-s}, { s, s,-s}, {-s, s,-s}, // front face
{-s,-s, s}, { s,-s, s}, { s, s, s}, {-s, s, s}, // back face
};
for (int i = 0; i < 8; i++) {
m.positions.push_back(verts[i][0]);
m.positions.push_back(verts[i][1]);
m.positions.push_back(verts[i][2]);
// Simple normals (will be averaged)
float nx = verts[i][0], ny = verts[i][1], nz = verts[i][2];
float len = std::sqrt(nx*nx + ny*ny + nz*nz);
m.normals.push_back(nx/len); m.normals.push_back(ny/len); m.normals.push_back(nz/len);
}
// 6 faces x 2 triangles
int faces[][4] = {
{0,1,2,3}, {5,4,7,6}, {1,5,6,2}, {4,0,3,7}, {3,2,6,7}, {4,5,1,0}
};
for (int f = 0; f < 6; f++) {
m.indices.push_back(faces[f][0]);
m.indices.push_back(faces[f][1]);
m.indices.push_back(faces[f][2]);
m.indices.push_back(faces[f][0]);
m.indices.push_back(faces[f][2]);
m.indices.push_back(faces[f][3]);
}
return m;
}
// Create a subdivided plane mesh
static DCMeshData make_plane(int res = 10) {
DCMeshData m;
for (int z = 0; z <= res; z++) {
for (int x = 0; x <= res; x++) {
float fx = static_cast<float>(x) / res - 0.5f;
float fz = static_cast<float>(z) / res - 0.5f;
m.positions.push_back(fx);
m.positions.push_back(0.0f);
m.positions.push_back(fz);
m.normals.push_back(0); m.normals.push_back(1); m.normals.push_back(0);
}
}
for (int z = 0; z < res; z++) {
for (int x = 0; x < res; x++) {
int i = z * (res+1) + x;
m.indices.push_back(i);
m.indices.push_back(i+1);
m.indices.push_back(i+res+1);
m.indices.push_back(i+1);
m.indices.push_back(i+res+2);
m.indices.push_back(i+res+1);
}
}
return m;
}
int main() {
printf("=== MCA Mesh Simplification Tests ===\n\n");
// Test 1: Box simplification
{
DCMeshData box = make_box();
int orig_tris = static_cast<int>(box.indices.size()) / 3;
printf("Test 1: Box mesh (%d verts, %d tris)\n",
static_cast<int>(box.positions.size())/3, orig_tris);
int collapses = dc_simplify_mca(box, 6); // target: 6 triangles
int new_tris = static_cast<int>(box.indices.size()) / 3;
int new_verts = static_cast<int>(box.positions.size()) / 3;
printf(" After: %d verts, %d tris (%d collapses)\n", new_verts, new_tris, collapses);
assert(new_tris <= orig_tris);
assert(collapses > 0);
printf(" PASS\n\n");
}
// Test 2: Plane simplification (200 tris -> 50)
{
DCMeshData plane = make_plane(10);
int orig_tris = static_cast<int>(plane.indices.size()) / 3;
int orig_verts = static_cast<int>(plane.positions.size()) / 3;
printf("Test 2: Plane mesh (%d verts, %d tris)\n", orig_verts, orig_tris);
int collapses = dc_simplify_mca(plane, 50);
int new_tris = static_cast<int>(plane.indices.size()) / 3;
int new_verts = static_cast<int>(plane.positions.size()) / 3;
printf(" After: %d verts, %d tris (%d collapses)\n", new_verts, new_tris, collapses);
assert(new_tris <= 50 + 10); // allow small overshoot due to MCA randomness
assert(new_tris < orig_tris);
printf(" PASS\n\n");
}
// Test 3: No-op (already below target)
{
DCMeshData box = make_box();
int collapses = dc_simplify_mca(box, 100); // target > current
assert(collapses == 0);
printf("Test 3: No-op when below target: PASS\n\n");
}
// Test 4: Large plane (50x50 = 5000 tris -> 500)
{
DCMeshData plane = make_plane(50);
int orig_tris = static_cast<int>(plane.indices.size()) / 3;
printf("Test 4: Large plane (%d verts, %d tris) -> target 500\n",
static_cast<int>(plane.positions.size())/3, orig_tris);
int collapses = dc_simplify_mca(plane, 500);
int new_tris = static_cast<int>(plane.indices.size()) / 3;
printf(" After: %d verts, %d tris (%d collapses)\n",
static_cast<int>(plane.positions.size())/3, new_tris, collapses);
assert(new_tris < orig_tris);
printf(" PASS\n\n");
}
printf("All tests passed!\n");
return 0;
}