13 #include "TerrainMod.h"
15 #include "BasePoint.h"
19 #include <wfmath/MersenneTwister.h>
38 m_res(resolution), m_size(m_res+1),
40 m_heightMap(resolution)
63 populateHeightMap(m_heightMap);
65 for (
auto& entry : m_terrainMods) {
66 applyMod(entry.second);
70 void Segment::populateHeightMap(
HeightMap& heightMap)
72 heightMap.
fill2d(m_controlPoints(0, 0), m_controlPoints(1, 0),
73 m_controlPoints(1, 1), m_controlPoints(0, 1));
98 void Segment::invalidateSurfaces()
100 for(
auto& entry : m_surfaces) {
101 entry.second->invalidate();
115 assert(m_res == m_size - 1);
117 if (m_normals.empty()) {
118 m_normals.reserve(m_size * m_size * 3);
121 auto * np = m_normals.data();
125 for (
int j = 1; j < m_res; ++j) {
126 for (
int i = 1; i < m_res; ++i) {
133 np[j * m_size * 3 + i * 3] = (h1 - h3) / 2.f;
134 np[j * m_size * 3 + i * 3 + 1] = 1.0;
135 np[j * m_size * 3 + i * 3 + 2] = (h4 - h2) / 2.f;
142 for (
int i=1; i < m_res; ++i) {
143 h1 = m_heightMap.
get(i - 1, 0);
144 h2 = m_heightMap.
get(i + 1, 0);
146 np[i * 3] = (h1 - h2) / 2.f;
150 h1 = m_heightMap.
get(i - 1, m_res);
151 h2 = m_heightMap.
get(i + 1, m_res);
153 np[m_res * m_size * 3 + i * 3] = (h1 - h2) / 2.f;
154 np[m_res * m_size * 3 + i * 3 + 1] = 1.0f;
155 np[m_res * m_size * 3 + i * 3 + 2] = 0.0f;
159 for (
int j=1; j < m_res; ++j) {
160 h1 = m_heightMap.
get(0, j - 1);
161 h2 = m_heightMap.
get(0, j + 1);
163 np[j * m_size * 3] = 0;
164 np[j * m_size * 3 + 1] = 1.f;
165 np[j * m_size * 3 + 2] = (h1 - h2) / 2.f;
167 h1 = m_heightMap.
get(m_res, j - 1);
168 h2 = m_heightMap.
get(m_res, j + 1);
170 np[j * m_size * 3 + m_res * 3] = 0.f;
171 np[j * m_size * 3 + m_res * 3 + 1] = 1.f;
172 np[j * m_size * 3 + m_res * 3 + 2] = (h1 - h2) / 2.f;
181 np[m_res * m_size * 3] = 0.f;
182 np[m_res * m_size * 3 + 1] = 1.f;
183 np[m_res * m_size * 3 + 2] = 0.f;
186 np[m_res * 3 + 1] = 1.f;
187 np[m_res * 3 + 2] = 0.f;
189 np[m_res * m_size * 3 + m_res * 3] = 0.f;
190 np[m_res * m_size * 3 + m_res * 3 + 1] = 1.f;
191 np[m_res * m_size * 3 + m_res * 3 + 2] = 0.f;
199 for (
const auto& entry : m_surfaces) {
200 if (entry.second->m_shader.checkIntersect(*
this)) {
201 entry.second->populate();
206 void Segment::getHeight(
float x,
float y,
float &h)
const
208 m_heightMap.getHeight(x, y, h);
224 WFMath::Vector<3> &normal)
const
239 int &lx,
int &hx,
int &lz,
int &hz)
const
241 lx = I_ROUND(bbox.lowCorner()[0]);
242 if (lx > m_res)
return false;
245 hx = I_ROUND(bbox.highCorner()[0]);
246 if (hx < 0)
return false;
247 if (hx > m_res) hx = m_res;
249 lz = I_ROUND(bbox.lowCorner()[1]);
250 if (lz > m_res)
return false;
253 hz = I_ROUND(bbox.highCorner()[1]);
254 if (hz < 0)
return false;
255 if (hz > m_res) hz = m_res;
260 void Segment::updateMod(
long id,
const TerrainMod *t)
263 m_terrainMods[id] = t;
265 m_terrainMods.erase(
id);
276 if (!m_terrainMods.empty()) {
277 m_terrainMods.clear();
290 float* points = m_heightMap.
getData();
291 WFMath::AxisBox<2> bbox=t->
bbox();
292 bbox.shift(WFMath::Vector<2>(-m_xRef, -m_zRef));
294 for (
int i=lz; i<=hz; i++) {
295 for (
int j=lx; j<=hx; j++) {
296 float& h = points[i * m_size + j];
297 t->
apply(h, j + m_xRef, i + m_zRef);
307 void Segment::updateArea(
long id,
const Area* area,
const Shader* shader)
309 auto areaLookupI = m_areaLookup.find(
id);
310 if (areaLookupI != m_areaLookup.end()) {
311 auto& areaEntry = areaLookupI->second->second;
312 auto J = m_surfaces.find(areaEntry.area->getLayer());
313 if (J != m_surfaces.end()) {
316 J->second->invalidate();
318 m_areas.erase(areaLookupI->second);
319 m_areaLookup.erase(areaLookupI);
324 auto result = m_areas.emplace(area->getLayer(), AreaEntry{id, area});
325 m_areaLookup.emplace(
id, result);
326 auto J = m_surfaces.find(area->getLayer());
327 if (J != m_surfaces.end()) {
328 J->second->invalidate();
331 m_surfaces[area->getLayer()] = shader->newSurface(*
this);
339 WFMath::Point<2> lp(m_xRef, m_zRef),
340 hp(lp.x() + m_res, lp.y() + m_res);
341 return WFMath::AxisBox<2>(lp, hp);
void invalidate()
De-allocate the storage for this buffer.
DataType * getData()
Accessor for a pointer to buffer containing data values.
bool isValid() const
Determine if this buffer has valid allocated storage.
void allocate()
Allocate the storage required by the buffer.
const WFMath::AxisBox< 2 > & bbox() const
Accessor for the bounding box of the geometric shape.
Class storing heightfield and other data for a single fixed size square area of terrain defined by fo...
void fill2d(const BasePoint &p1, const BasePoint &p2, const BasePoint &p3, const BasePoint &p4)
Two dimensional midpoint displacement fractal.
void checkMaxMin(float h)
Check a value against m_min and m_max and set one of them if appropriate.
void getHeightAndNormal(float x, float z, float &h, WFMath::Vector< 3 > &normal) const
Get an accurate height and normal vector at a given coordinate relative to this segment.
float get(int x, int z) const
Get the height at a relative integer position in the Segment.
bool clipToSegment(const WFMath::AxisBox< 2 > &bbox, int &lx, int &hx, int &lz, int &hz) const
Determine the intersection between an axis aligned box and this segment.
void populate()
Populate the Segment with heightfield data.
WFMath::AxisBox< 2 > getRect() const
The 2d area covered by this segment.
void populateNormals()
Populate the Segment with surface normal data.
Segment(int x, int z, int resolution)
Construct an empty segment with the given resolution.
void getHeightAndNormal(float x, float z, float &h, WFMath::Vector< 3 > &normal) const
Get an accurate height and normal vector at a given coordinate relative to this segment.
void populateSurfaces()
Populate the surfaces associated with this Segment.
void invalidate(bool points=true)
Mark the contents of this Segment as stale.
void clearMods()
Delete all the modifications applied to this Segment.
float get(int x, int z) const
Get the height at a relative integer position in the Segment.
~Segment()
Destruct the Segment.
Base class for modifiers to the procedurally generated terrain.
virtual void apply(float &point, int x, int z) const =0
Apply this modifier on a terrain segment.