OverviewFilesCommitsIssuesDocsReleasesPeers

dc-terrain / libdc / src / dc_mesher.cpp

81 lines · cpp ref:
#include "dc_mesher.h"
#include "dc_octree.h"
#include "dc_pool.h"

DCMeshData dc_mesh_from_grid(const DensityGrid& grid, const DCMesherConfig& config) {
    Pool<OctreeNode> pool;
    int min[3] = {0, 0, 0};
    int size = grid.grid_size;

    OctreeNode* root = construct_octree_grid_pooled(min, size, grid, pool);

    DCMeshData mesh;
    if (root) {
        float origin[3] = { grid.origin[0], grid.origin[1], grid.origin[2] };
        dc_generate_mesh_grid(root, grid.voxel_scale, origin, grid, 0, mesh);

        if (config.auto_smooth && mesh.positions.size() > 0) {
            dc_auto_smooth(mesh, config.smooth_angle_deg);
        }
        if (config.laplacian_smooth && mesh.positions.size() > 0) {
            dc_laplacian_smooth(mesh, config.laplacian_iterations,
                                config.laplacian_lambda,
                                config.smooth_angle_deg);
        }
    }

    return mesh;
}

// Bridge: adapts DCGenerator::evaluate() to DensityGrid::fill()'s callback signature
struct GeneratorFillContext {
    DCGenerator* gen;
    float lod_voxel_size;
};

static float generator_fill_callback(float x, float y, float z, void* ud) {
    auto* ctx = static_cast<GeneratorFillContext*>(ud);
    return ctx->gen->evaluate(x, y, z, ctx->lod_voxel_size);
}

DCMeshData dc_mesh_from_generator(DCGenerator& gen, const float origin[3],
                                   float voxel_size, int grid_size,
                                   const DCMesherConfig& config) {
    // Round up to next power of 2 — octree requires power-of-2 grid size
    int po2 = 1;
    while (po2 < grid_size) po2 <<= 1;
    grid_size = po2;

    // Fill grid for octree corner sampling
    DensityGrid grid;
    grid.allocate(grid_size, voxel_size, origin);

    GeneratorFillContext ctx{&gen, voxel_size};
    grid.fill(generator_fill_callback, &ctx);

    // Build octree from grid
    Pool<OctreeNode> pool;
    int min[3] = {0, 0, 0};
    OctreeNode* root = construct_octree_grid_pooled(min, grid_size, grid, pool);

    DCMeshData mesh;
    if (root) {
        float org[3] = { grid.origin[0], grid.origin[1], grid.origin[2] };

        // Direct evaluation for hermite data — preserves sharp features
        dc_generate_mesh(root, grid.voxel_scale, org,
                          generator_fill_callback, &ctx, mesh);

        if (config.auto_smooth && mesh.positions.size() > 0) {
            dc_auto_smooth(mesh, config.smooth_angle_deg);
        }
        if (config.laplacian_smooth && mesh.positions.size() > 0) {
            dc_laplacian_smooth(mesh, config.laplacian_iterations,
                                config.laplacian_lambda,
                                config.smooth_angle_deg);
        }
    }

    return mesh;
}