15struct HeightmapArrays {
22void buildSmooth(
const procgen::Heightmap& heightmap,
float cellSize,
float heightScale,
24 const int width = heightmap.getWidth();
25 const int height = heightmap.getHeight();
26 if (
width < 2 ||
height < 2 || cellSize == 0.0F)
return;
32 return heightmap.height(std::clamp(
x, 0,
width - 1), std::clamp(
y, 0,
height - 1));
37 {
static_cast<float>(
x) * cellSize,
38 heightmap.height(
x,
y) * heightScale,
39 static_cast<float>(
y) * cellSize});
49 output.normals.insert(
output.normals.end(), {nx, ny, nz});
51 {static_cast<float>(x) / static_cast<float>(width - 1),
52 static_cast<float>(y) / static_cast<float>(height - 1)});
56 for (
int x = 0;
x <
width - 1; ++
x) {
57 const std::uint32_t i00 =
static_cast<std::uint32_t
>(
y *
width +
x);
58 const std::uint32_t i10 = i00 + 1U;
59 const std::uint32_t i01 = i00 +
static_cast<std::uint32_t
>(
width);
60 const std::uint32_t i11 = i01 + 1U;
61 output.indices.insert(
output.indices.end(), {i00, i01, i10, i10, i01, i11});
66void addFlatTriangle(HeightmapArrays&
output,
float cellSize,
float heightScale,
67 float textureWidth,
float textureHeight,
float ax,
float ay,
float ah,
68 float bx,
float by,
float bh,
float cx,
float cy,
float ch) {
69 const float p0x =
ax * cellSize, p0y = ah * heightScale, p0z =
ay * cellSize;
70 const float p1x =
bx * cellSize, p1y = bh * heightScale, p1z =
by * cellSize;
71 const float p2x =
cx * cellSize, p2y = ch * heightScale, p2z =
cy * cellSize;
72 float nx = (p1y - p0y) * (p2z - p0z) - (p1z - p0z) * (p2y - p0y);
73 float ny = (p1z - p0z) * (p2x - p0x) - (p1x - p0x) * (p2z - p0z);
74 float nz = (p1x - p0x) * (p2y - p0y) - (p1y - p0y) * (p2x - p0x);
81 const std::uint32_t base =
static_cast<std::uint32_t
>(
output.positions.size() / 3U);
82 output.positions.insert(
output.positions.end(), {p0x, p0y, p0z, p1x, p1y, p1z, p2x, p2y, p2z});
85 {
ax / textureWidth,
ay / textureHeight,
bx / textureWidth,
86 by / textureHeight,
cx / textureWidth,
cy / textureHeight});
87 output.indices.insert(
output.indices.end(), {base, base + 1U, base + 2U});
90void buildFlat(
const procgen::Heightmap& heightmap,
float cellSize,
float heightScale,
92 const int width = heightmap.getWidth();
93 const int height = heightmap.getHeight();
95 const float textureWidth =
static_cast<float>(
width - 1);
96 const float textureHeight =
static_cast<float>(
height - 1);
98 for (
int x = 0;
x <
width - 1; ++
x) {
99 const float h00 = heightmap.height(
x,
y);
100 const float h10 = heightmap.height(
x + 1,
y);
101 const float h01 = heightmap.height(
x,
y + 1);
102 const float h11 = heightmap.height(
x + 1,
y + 1);
103 addFlatTriangle(
output, cellSize, heightScale, textureWidth, textureHeight,
104 static_cast<float>(
x),
static_cast<float>(
y), h00,
105 static_cast<float>(
x),
static_cast<float>(
y + 1), h01,
106 static_cast<float>(
x + 1),
static_cast<float>(
y), h10);
107 addFlatTriangle(
output, cellSize, heightScale, textureWidth, textureHeight,
108 static_cast<float>(
x + 1),
static_cast<float>(
y), h10,
109 static_cast<float>(
x),
static_cast<float>(
y + 1), h01,
110 static_cast<float>(
x + 1),
static_cast<float>(
y + 1), h11);
115HeightmapArrays build(
const procgen::Heightmap& heightmap,
float cellSize,
float heightScale,
116 bool smoothNormals) {
117 HeightmapArrays result;
119 buildSmooth(heightmap, cellSize, heightScale, result);
121 buildFlat(heightmap, cellSize, heightScale, result);
128 float heightScale,
bool smoothNormals) {
129 auto* graphics = ModuleManager::getInstance<eve::graphics::Graphics>(
"Graphics");
130 if (!graphics || !heightmap)
131 return eve::editing::failed<graphics::Mesh*>(
132 editing::Status::Unsupported,
editing::RuleId(
"procgen.preview.provider-absent"),
133 "Heightmap preview requires Graphics and a source heightmap");
134 HeightmapArrays arrays = build(*heightmap, cellSize, heightScale, smoothNormals);
135 if (arrays.indices.empty())
136 return eve::editing::failed<graphics::Mesh*>(
137 editing::Status::Rejected,
editing::RuleId(
"procgen.preview.empty-heightmap"),
138 "Heightmap preview requires a valid grid and cell size");
139 auto*
mesh = graphics->newMeshFromArrays(
140 arrays.positions.data(), arrays.normals.data(), arrays.texcoords.data(),
141 static_cast<int>(arrays.positions.size() / 3U), arrays.indices.data(),
142 static_cast<int>(arrays.indices.size()));
144 return eve::editing::failed<graphics::Mesh*>(
145 editing::Status::Failed,
editing::RuleId(
"procgen.preview.mesh-create-failed"),
146 "Graphics rejected the heightmap preview mesh");
147 return eve::editing::applied<graphics::Mesh*>(
mesh);
152 float heightScale,
bool smoothNormals) {
153 if (!
mesh || !graphics || !heightmap)
154 return eve::editing::failed<void>(
155 editing::Status::Rejected,
editing::RuleId(
"procgen.preview.invalid-update"),
156 "Heightmap preview update requires mesh, Graphics and heightmap");
157 HeightmapArrays arrays = build(*heightmap, cellSize, heightScale, smoothNormals);
158 if (arrays.indices.empty())
159 return eve::editing::failed<void>(
160 editing::Status::Rejected,
editing::RuleId(
"procgen.preview.empty-heightmap"),
161 "Heightmap preview requires a valid grid and cell size");
163 arrays.texcoords.data(),
164 static_cast<int>(arrays.positions.size() / 3U),
nullptr, 0))
165 return eve::editing::failed<void>(
166 editing::Status::Failed,
editing::RuleId(
"procgen.preview.mesh-update-failed"),
167 "Graphics rejected the heightmap preview update");
168 return eve::editing::applied<void>();
virtual bool updateMeshVertices(Mesh *mesh, const float *posXYZ, const float *nrmXYZ, const float *uvST, int vertexCount, const uint32_t *indices, int indexCount)=0
In-place update of a mesh's vertex/index data (CPU -> host-visible VBO). Mirrors bakeMeshMorph: the u...
editing::Result< void > updateHeightmapMesh(graphics::Mesh *mesh, graphics::Graphics *graphics, procgen::Heightmap *heightmap, float cellSize, float heightScale, bool smoothNormals)
Update preview vertices without replacing the mesh identity.