#ifndef DC_CONTOUR_H
#define DC_CONTOUR_H
// Dual Contouring mesh generation: hermite data collection, QEF solving,
// and recursive contouring (cellProc/faceProc/edgeProc).
// Pure C++ -- no Godot dependencies.
#include "dc_octree.h"
#include "dc_density_grid.h"
#include <vector>
struct DCMeshData {
std::vector<float> positions; // x,y,z triples
std::vector<float> normals; // x,y,z triples
std::vector<float> materials; // per-vertex material_id (route ② texturing; empty on CPU path)
// Per-vertex horizontal Laplacian of density, in metres — the third
// material attribute (altitude, slope, curvature). Computed in qef_solve
// from the density grid it already reads; empty on the CPU path.
std::vector<float> curv;
std::vector<float> proj; // per-vertex projection index, candidate 0 (Stage-2; empty on CPU path)
std::vector<float> proj2; // per-vertex projection index, candidate 1 (crease other face; Stage-2)
std::vector<int> indices; // triangle indices (visual: includes +1 boundary extension)
std::vector<int> collision_indices; // collision: strict nominal bounds (no overlap)
std::vector<float> positions_coarse; // x,y,z triples (parent-LOD positions)
std::vector<float> normals_coarse; // x,y,z triples (parent-LOD normals)
};
// Post-process mesh normals: compute face normals from geometry, then split
// vertices where adjacent face normals exceed the angle threshold.
// This reveals DC's sharp feature preservation in the rendered mesh.
// angle_threshold_degrees: faces with angle > this get split normals (default 30°).
void dc_auto_smooth(DCMeshData& mesh, float angle_threshold_degrees = 60.0f);
// Laplacian mesh smoothing: moves vertices toward the average of their
// neighbors, reducing noise and spiky geometry. Constrained to preserve
// sharp features (edges where normal angle > threshold are not smoothed across).
// iterations: number of smoothing passes (1-5 typical)
// lambda: smoothing factor per step (0.0-1.0, default 0.5)
// angle_threshold_degrees: edges sharper than this are preserved
void dc_laplacian_smooth(DCMeshData& mesh, int iterations = 2,
float lambda = 0.5f,
float angle_threshold_degrees = 60.0f);
// Remove degenerate triangles with extreme aspect ratio.
// max_aspect_ratio: triangles with longest_edge/shortest_altitude > this are removed.
void dc_remove_degenerate_tris(DCMeshData& mesh, float max_aspect_ratio = 15.0f);
// Remove small disconnected mesh islands (floating fragments).
// Finds connected components via triangle adjacency, removes any
// component with fewer than min_triangles. Cleans up SDF artifacts.
void dc_remove_islands(DCMeshData& mesh, int min_triangles = 8);
// Full pipeline: collect hermite data, solve QEFs, contour tree -> mesh.
// density_fn and userdata are needed for hermite data (zero-crossing search
// + normal computation via central differences).
void dc_generate_mesh(
OctreeNode* root,
float voxel_scale,
float origin[3],
DensityFunc density_fn,
void* userdata,
DCMeshData& out_mesh
);
// Grid-accelerated version: uses pre-computed density grid for
// bisection and normal computation instead of calling density_fn.
// Much faster (~10x) since trilinear interpolation replaces noise evaluation.
struct TerrainEdit; // forward declaration
void dc_generate_mesh_grid(
OctreeNode* root,
float voxel_scale,
float origin[3],
const DensityGrid& grid,
int overlap,
DCMeshData& out_mesh,
const std::vector<TerrainEdit>* edits = nullptr
);
// SDF-guided edge subdivision: subdivide edges on curved surfaces
// and project new vertices onto the actual SDF surface.
// Flat edges are left untouched. This smooths sphere/cylinder CSG
// without adding geometry to flat box faces.
// angle_threshold_degrees: edges with normal angle > this get subdivided
// iterations: number of subdivision passes (1 = 2× on curves, 2 = 4×)
void dc_subdivide_curved(DCMeshData& mesh,
DensityFunc density_fn, void* userdata,
float voxel_scale,
float angle_threshold_degrees = 15.0f,
int iterations = 1);
// Convex decomposition: group adjacent coplanar triangles by normal similarity.
// Coplanar groups emit a box (AABB extended into solid along normal).
// Non-coplanar groups emit a convex hull point cloud.
struct ConvexHull {
enum Type { HULL, BOX };
Type type = HULL;
std::vector<float> points; // HULL: xyz triples (point cloud)
float box_min[3] = {}; // BOX: AABB min
float box_max[3] = {}; // BOX: AABB max
};
struct ConvexHullSet {
std::vector<ConvexHull> hulls;
};
void dc_convex_decompose(const DCMeshData& mesh, ConvexHullSet& out,
float cos_threshold = 0.7071f);
// Clip mesh to an AABB: discard faces where ALL 3 vertices are outside
// the bounding box. This is the Cepero seam fix — each chunk generates
// overlap geometry but only keeps faces within its nominal bounds.
void dc_clip_to_aabb(DCMeshData& mesh,
const float aabb_min[3], const float aabb_max[3]);
#endif // DC_CONTOUR_H