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);
118 m_normals = std::make_unique<std::vector<float>>(m_size * m_size * 3);
121 float * 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);
325 m_areaLookup.emplace(
id, result);
326 auto J = m_surfaces.find(area->
getLayer());
327 if (J != m_surfaces.end()) {
328 J->second->invalidate();
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 fill2d(const BasePoint &p1, const BasePoint &p2, const BasePoint &p3, const BasePoint &p4)
Two dimensional midpoint displacement fractal.
Class storing heightfield and other data for a single fixed size square area of terrain defined by fo...
DataType * getData()
Accessor for a pointer to buffer containing data values.
void populateSurfaces()
Populate the surfaces associated with this Segment.
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 invalidate()
De-allocate the storage for this buffer.
float get(int x, int z) const
Get the height at a relative integer position in the Segment.
virtual void apply(float &point, int x, int z) const =0
Apply this modifier on a terrain segment.
Base class for Shader objects which create surface data for use when rendering terrain.
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 invalidate(bool points=true)
Mark the contents of this Segment as stale.
std::unique_ptr< Surface > newSurface(const Segment &) const
Create a new Surface which matches the requirements of this shader.
void allocate()
Allocate the storage required by the buffer.
bool isValid() const
Determine if this buffer has valid allocated storage.
void clearMods()
Delete all the modifications applied to this Segment.
const WFMath::AxisBox< 2 > & bbox() const
Accessor for the bounding box of the geometric shape.
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.
int getLayer() const
Accessor for the layer number.
Region of terrain surface which is modified.
void checkMaxMin(float h)
Check a value against m_min and m_max and set one of them if appropriate.
void populateNormals()
Populate the Segment with surface normal data.
~Segment()
Destruct the Segment.
Base class for modifiers to the procedurally generated terrain.
void populate()
Populate the Segment with heightfield data.
WFMath::AxisBox< 2 > getRect() const
The 2d area covered by this segment.