13#include "TerrainMod.h"
19#include <wfmath/MersenneTwister.h>
42 inline float calc(
float loc)
44 return ((noCalc) ?
ep1 :
45 ((m_size-loc) *
ep1 + loc * ep2));
52 LinInterp(
float size,
float l,
float h) : m_size(size), noCalc(false),
53 ep1(l/size), ep2(h/size)
76 float ep1, ep2, ep3, ep4;
78 inline float calc(
float locX,
float locY)
80 return ((noCalc) ?
ep1 :
81 ((
ep1*(m_size-locX) + ep2 * locX) * (m_size-locY) +
82 ( ep4*(m_size-locX) + ep3 * locX) * (locY) ) / m_size );
91 QuadInterp(
float size,
float e1,
float e2,
float e3,
float e4)
92 : m_size(size), noCalc(false),
93 ep1(e1/size), ep2(e2/size), ep3(e3/size), ep4(e4/size)
95 if ((e1==e2) && (e3==e4) && (e2==e3)) {
107 m_max(std::numeric_limits<float>::lowest()),
108 m_min(std::numeric_limits<float>::max())
128inline float randHalf(WFMath::MTRand& rng)
131 return rng.rand<
float>() - 0.5f;
136float HeightMap::qRMD(WFMath::MTRand& rng,
float nn,
float fn,
float ff,
float nf,
137 float roughness,
float falloff,
float depth)
const
139 float max = std::max(std::max(nn, fn), std::max(nf, ff)),
140 min = std::min(std::min(nn, fn), std::min(nf, ff)),
141 heightDifference = max - min;
143 return ((nn+fn+ff+nf)/4.f) + randHalf(rng) * roughness * heightDifference / (1.f+std::pow(depth,falloff));
152void HeightMap::fill1d(
const BasePoint& l,
const BasePoint &h,
155 array[0] = l.height();
156 array[m_res] = h.height();
157 LinInterp li((
float)m_res, l.roughness(), h.roughness());
164 WFMath::MTRand::uint32 seed[2]={ l.seed(), h.seed() };
165 WFMath::MTRand rng(seed, 2);
171 int stride = m_res/2;
178 for (
int i=stride;i<m_res;i+=stride*2) {
179 float hh = array[i-stride];
180 float lh = array[i+stride];
181 float hd = std::fabs(hh-lh);
182 float roughness = li.calc((
float)i);
185 if ((hd*100.f) < roughness) {
186 hd+=0.05f * roughness;
189 array[i] = ((hh+lh)/2.f) + randHalf(rng) * roughness * hd / (1.f+std::pow(depth,
BasePoint::FALLOFF));
205 m_max = std::numeric_limits<float>::lowest();
206 m_min = std::numeric_limits<float>::max();
215 std::vector<float> edgeData;
217 float* edge = edgeData.data();
219 float* points =
m_data.data();
223 for (
int i=0;i<=m_res;i++) {
224 points[0*
m_size + i] = edge[i];
230 for (
int i=0;i<=m_res;i++) {
231 points[i*
m_size + 0] = edge[i];
237 for (
int i=0;i<=m_res;i++) {
238 points[i*
m_size + m_res] = edge[i];
244 for (
int i=0;i<=m_res;i++) {
245 points[m_res*
m_size + i] = edge[i];
252 WFMath::MTRand::uint32 seed[4]={ p1.
seed(), p2.
seed(), p3.
seed(), p4.
seed() };
253 WFMath::MTRand rng(seed, 4);
261 int stride = m_res/2;
264 float roughness = qi.
calc((
float)stride,(
float) stride);
265 float f = falloffQi.
calc((
float)stride, (
float)stride);
266 points[stride*
m_size + stride] = qRMD(rng, points[0 *
m_size + stride],
267 points[stride*
m_size + 0],
268 points[stride*
m_size + m_res],
269 points[m_res*
m_size + stride],
286 for (
int i=stride;i<m_res;i+=stride*2) {
287 for (
int j=stride;j<m_res;j+=stride*2) {
288 roughness=qi.
calc((
float)i,(
float)j);
289 f = falloffQi.
calc((
float)i, (
float)j);
290 points[j*
m_size + i] = qRMD(rng, points[(i-stride) + (j+stride) * (
m_size)],
291 points[(i+stride) + (j-stride) * (
m_size)],
292 points[(i+stride) + (j+stride) * (
m_size)],
293 points[(i-stride) + (j-stride) * (
m_size)],
294 roughness, f, depth);
304 for (
int i=stride*2;i<m_res;i+=stride*2) {
305 for (
int j=stride;j<m_res;j+=stride*2) {
306 roughness=qi.
calc((
float)i,(
float)j);
307 f = falloffQi.
calc((
float)i, (
float)j);
308 points[j*
m_size + i] = qRMD(rng, points[(i-stride) + (j) * (
m_size)],
309 points[(i+stride) + (j) * (
m_size)],
310 points[(i) + (j+stride) * (
m_size)],
311 points[(i) + (j-stride) * (
m_size)],
312 roughness, f , depth);
317 for (
int i=stride;i<m_res;i+=stride*2) {
318 for (
int j=stride*2;j<m_res;j+=stride*2) {
319 roughness=qi.
calc((
float)i,(
float)j);
320 f = falloffQi.
calc((
float)i, (
float)j);
321 points[j*
m_size + i] = qRMD(rng, points[(i-stride) + (j) * (
m_size)],
322 points[(i+stride) + (j) * (
m_size)],
323 points[(i) + (j+stride) * (
m_size)],
324 points[(i) + (j-stride) * (
m_size)],
325 roughness, f, depth);
335void HeightMap::getHeight(
float x,
float z,
float &h)
const
344 int tile_x = I_ROUND(std::floor(x));
345 int tile_z = I_ROUND(std::floor(z));
348 float off_x = x - (float)tile_x;
349 float off_z = z - (float)tile_z;
351 float h1=
get(tile_x, tile_z);
352 float h2=
get(tile_x, tile_z+1);
353 float h3=
get(tile_x+1, tile_z+1);
354 float h4=
get(tile_x+1, tile_z);
358 if ((off_x - off_z) <= 0.f) {
359 h = h1 + (h3-h2) * off_x + (h2-h1) * off_z;
363 h = h1 + (h4-h1) * off_x + (h3-h4) * off_z;
381 WFMath::Vector<3> &normal)
const
390 int tile_x = I_ROUND(std::floor(x));
391 int tile_z = I_ROUND(std::floor(z));
394 float off_x = x - (float)tile_x;
395 float off_z = z - (float)tile_z;
397 float h1=
get(tile_x, tile_z);
398 float h2=
get(tile_x, tile_z+1);
399 float h3=
get(tile_x+1, tile_z+1);
400 float h4=
get(tile_x+1, tile_z);
404 if ((off_x - off_z) <= 0.f) {
405 normal = WFMath::Vector<3>(h2-h3, 1.0f, h1-h2);
408 if (off_x == off_z) {
409 normal += WFMath::Vector<3>(h1-h4, 1.0f, h4-h3);
412 h = h1 + (h3-h2) * off_x + (h2-h1) * off_z;
416 normal = WFMath::Vector<3>(h1-h4, 1.0f, h4-h3);
418 h = h1 + (h4-h1) * off_x + (h3-h4) * off_z;
Point on the fundamental grid that is used as the basis for terrain.
static constexpr float FALLOFF
Default falloff at the base point.
float falloff() const
Accessor for the falloff at the base point.
float roughness() const
Accessor for the roughness at the base point.
unsigned int seed() const
Calculate the random seed used at this base point.
Template for managing buffers of data for a segment.
const unsigned int m_size
The size of segment, m_res + 1.
std::vector< float > m_data
Pointer to buffer containing data values.
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.
HeightMap(int resolution)
Construct an empty height map with the given resolution.
Helper to interpolate on a line.
LinInterp(float size, float l, float h)
Constructor.
float ep1
Values at the two ends.
float calc(float loc)
Determine the interpolated value along the line.
Helper to interpolate in a quad.
QuadInterp(float size, float e1, float e2, float e3, float e4)
Constructor.
float calc(float locX, float locY)
Determine the interpolated value within the quad.
float ep1
Values at the four corners.