source: Revenant/geoworld/src/gwmorphs/mountains.cpp@ 8125274

port/mars-tycoon
Last change on this file since 8125274 was 80a6a52, checked in by Jonathan Neufeld <support@…>, 3 years ago

Get to a compile state for terrain procedural generation

  • Property mode set to 100644
File size: 11.4 KB
Line 
1#include "mountains.h"
2
3#include <mars_ptr.h>
4
5#include "geoworld.h"
6
7namespace geoworld
8{
9 template< typename BFn >
10 class SeedModifiedMidpointDisplacement : public BFn
11 {
12 private:
13 const float _fSeedObedience, _fComplSeedObedience, _fMntRangeWidth;
14 const TaperFn _taper;
15
16 struct NearestSeedResult
17 {
18 mars::Magnitudinal< float > distance;
19 float elevation;
20 };
21
22 class ExpFn
23 {
24 private:
25 float _fMntDistGaussXMult;
26
27 public:
28 ExpFn (const float fMntDistGaussXMult)
29 : _fMntDistGaussXMult(fMntDistGaussXMult) {}
30
31 inline const float f (const float x) const { return expf(-x / _fMntDistGaussXMult); }
32 };
33
34 class CachedExpFn : public mars::CacheFnProxy< float, ExpFn >
35 {
36 public:
37 CachedExpFn (const float fMntDistGaussXMult)
38 : mars::CacheFnProxy< float, ExpFn >(ExpFn(fMntDistGaussXMult), 0, mars::SQ(static_cast< float > (LockedGWSection::MAX_LOCK_DIM)), LockedGWSection::MAX_LOCK_DIM) {}
39 } _fnchExp;
40
41 MountainGM::SeedList::const_iterator _iSeeds0, _iSeedsN;
42 float _fSeedCount;
43 const LockedGWSection::View * _pView;
44
45 int _nHalfStride, _c;
46
47 short compute (const int x, const int y, const short v) const
48 {
49 float fMnt = 0.0f;
50 float fDistSQ = std::numeric_limits< float >::max();
51
52 for (MountainGM::SeedList::const_iterator i = _iSeeds0; i != _iSeedsN; ++i)
53 {
54 const float f = mars::SQ(i->x - x) + mars::SQ(i->y - y);
55
56 if (f < fDistSQ)
57 fDistSQ = f;
58
59 // TODO: V-Tune attributes literally half of the performance issues to this line
60 fMnt += i->z * _fnchExp.f(f);
61 }
62
63 fMnt /= _fSeedCount;
64
65 return static_cast <short> (
66 _taper.blend(
67 sqrt(fDistSQ),
68 static_cast <float> (_pView->getHeightMap() ->getw(x, y)),
69 static_cast <float> (v) * _fComplSeedObedience + fMnt * _fSeedObedience
70 )
71 );
72 }
73
74 public:
75 inline SeedModifiedMidpointDisplacement (const float fSeedObedience, const short nMntRangeWidth, const float fCoarseness, const float fFalloff)
76 : BFn (nMntRangeWidth, fCoarseness), // HACK: Use the mountain range width since PinkFn only uses this to generate a random height-delta
77 _fSeedObedience(fSeedObedience),
78 _fMntRangeWidth(static_cast< float > (nMntRangeWidth)),
79 _fComplSeedObedience(1.0f - fSeedObedience),
80 _fnchExp(2 * mars::SQ(static_cast <float> (nMntRangeWidth))),
81 _taper(TaperFn::createTaperFn(fFalloff * nMntRangeWidth))
82 {}
83
84 inline void init (const LockedGWSection::View * pView, const MountainGM::SeedList & seeds)
85 {
86 _pView = pView;
87 _iSeeds0 = seeds.begin();
88 _iSeedsN = seeds.end();
89 _fSeedCount = static_cast< float > (seeds.size());
90 }
91
92 inline void iteration (const int nStride, const int c)
93 {
94 BFn::iteration(nStride, c);
95 _c = c;
96 _nHalfStride = nStride / 2;
97 }
98
99 inline float getMaxMountainRadius () const
100 { return _taper.outside; }
101
102 inline short operator () (int & state, const int x, const int y, const short & a, const short & b, const short & c)
103 {
104 return compute(x, y, BFn::operator () (state, x, y, a, b, c));
105 }
106 inline short operator () (int & state, const int x, const int y, const short & a, const short & b, const short & c, const short & d)
107 {
108 return compute(x, y, BFn::operator () (state, x, y, a, b, c, d));
109 }
110 };
111
112 void MountainGM::init(SynthesisSession & manager, const IGeoWorldAccessor & accessor, const unsigned short nMaxWidth, const unsigned short nMaxHeight)
113 {
114 using namespace mars;
115
116 vector3Df
117 vdir = mars::U<mars::vector3Df>( mars::vector3Df(mars::RANDf<float>(), mars::RANDf<float>(), 0.0f) ),
118 vrange;
119 BBox< float > bbox0(0,0,0,0), bbox(0,0,0,0);
120
121 const float
122 fWidth = static_cast< float > (_nMntRangeWidth),
123 fDisplace = fWidth * _fClumpMaxDisplace,
124 fAvgHeight = static_cast< float > (_nMntRangeAvgHeight),
125 fHeightFlux = fAvgHeight * _fPeakHeightFluxPct,
126 fPeakStep = fWidth * _fCoarseness;
127
128 _seeds.clear();
129
130 const float fMaxMtnRadius =
131 SeedModifiedMidpointDisplacement< MidpointDisplacementGrid< GeoHeightMap::Precision >::BrownianFn > (1.0f, _nMntRangeWidth, _fCoarseness, _fFalloff).getMaxMountainRadius();
132
133 for (unsigned int c = 0; c < _nNumMountains; ++c)
134 {
135 const unsigned short nClumpCount = _mmnClumpSize.next();
136
137 for (unsigned int c = 0; c < nClumpCount; ++c)
138 {
139 vector3Df v = vrange +
140 vector3Df (
141 RANDf(fDisplace * 2) - fDisplace,
142 RANDf(fDisplace * 2) - fDisplace,
143 fAvgHeight - RANDf(fHeightFlux)
144 );
145
146 bbox.add(v - fMaxMtnRadius);
147 bbox.add(v + fMaxMtnRadius);
148
149 if (bbox.getWidth() <= nMaxWidth && bbox.getHeight() <= nMaxHeight)
150 {
151 bbox0 = bbox;
152 _seeds.push_back(v);
153 } else
154 bbox = bbox0;
155 }
156
157 vrange += vdir * RANDf(fPeakStep);
158 vdir = Matrix3D <float>::rotateZ(RANDf(_fRotateThreshold) - _fRotateThreshold / 2) * vdir;
159 }
160
161 bbox.add(
162 VectorTag< float >::V2(
163 bbox.left + static_cast< float > (
164 mars::MidpointDisplacementGrid <GeoHeightMap::Precision>
165 ::dimensionFor(static_cast< unsigned short > (bbox.getWidth()), mars::Normal)
166 ),
167 bbox.top + static_cast< float > (
168 mars::MidpointDisplacementGrid <GeoHeightMap::Precision>
169 ::dimensionFor(static_cast< unsigned short > (bbox.getHeight()), mars::Normal)
170 )
171 )
172 );
173
174 _bbox =
175 static_cast< BBox< long > > (bbox)
176 + _ptOrigin;
177
178 const GWSurfacePos ptsOffset = _ptOrigin - _bbox.getMinimum();
179 const VectorTag< float > ::V3 ptOffset (
180 static_cast< float > (ptsOffset.x),
181 static_cast< float > (ptsOffset.y),
182 0
183 );
184 for (MountainGM::SeedList::iterator i = _seeds.begin(); i != _seeds.end(); ++i)
185 *i += ptOffset;
186 }
187
188 void MountainGM::doMorph (LockedGWSection & section) const
189 {
190 using namespace mars;
191
192 mars::ptr< mars::MidpointDisplacementGrid <GeoHeightMap::Precision> >
193 pMPDG = MidpointDisplacementGrid <GeoHeightMap::Precision>
194 ::createInstance (
195 static_cast< unsigned short > (_bbox.getWidth()),
196 static_cast< unsigned short > (_bbox.getHeight()),
197 mars::Normal
198 );
199
200 const unsigned short
201 nSeedIterations = static_cast< unsigned short > (mars::RNDi(static_cast< float > (pMPDG->itercount) * _fSeedIterations));
202
203 const int nStride = pMPDG->mindim - 1;
204 const GWSurfacePos ptgwspOffset = _ptOrigin - _bbox.getMinimum();
205
206 // Initialize iteration count
207 const LockedGWSection::View * pView = section.createView(_bbox.left, _bbox.top, _bbox.right, _bbox.bottom);
208
209 MidpointDisplacementGrid <GeoHeightMap::Precision>::PinkFn
210 funcDefault(pMPDG->mindim, _fCoarseness);
211
212 funcDefault.iteration(pMPDG->stride(), 0);
213
214 pMPDG->copyEdges(mars::StitchTop | mars::StitchLeft | mars::StitchBottom | mars::StitchRight, pView->getHeightMap());
215 SeedModifiedMidpointDisplacement< MidpointDisplacementGrid< GeoHeightMap::Precision >::PinkFn >
216 funcSeeding (_fSeedObedience, _nMntRangeWidth, _fCoarseness, _fFalloff);
217 MidpointDisplacementGrid< GeoHeightMap::Precision >::PinkFn
218 funcNoisy (_nMntRangeWidth, _fCoarseness);
219
220 funcSeeding.init(pView, _seeds);
221 pMPDG->iterations(nSeedIterations, funcSeeding);
222 pMPDG->iterations(pMPDG->itercount - nSeedIterations, funcNoisy, mars::StitchBottom | mars::StitchTop | mars::StitchRight | mars::StitchLeft);
223 DEMDUMP << *pMPDG;
224
225 section.at(_bbox.left, _bbox.top) << *pMPDG;
226 section.releaseView(pView);
227 }
228
229 mars::ptr< PersistentGeoMorph::State > MountainGM::createState() const
230 {
231 MtnState * pState = new MtnState();
232
233 pState->seeds = _seeds;
234 pState->nNumMountains = _nNumMountains;
235 pState->fSeedObedience = _fSeedObedience;
236 pState->fSeedIterations = _fSeedIterations;
237 pState->fRotateThreshold = _fRotateThreshold;
238 pState->fPeakHeightFluxPct = _fPeakHeightFluxPct;
239 pState->fCoarseness = _fCoarseness;
240 pState->fFalloff = _fFalloff;
241 pState->fClumpMaxDisplace = _fClumpMaxDisplace;
242 pState->nMntRangeWidth = _nMntRangeWidth;
243 pState->nMntRangeAvgHeight = _nMntRangeAvgHeight;
244 pState->ptOrigin = _ptOrigin;
245 pState->mmnClumpSize = _mmnClumpSize;
246 pState->bbox = _bbox;
247
248 return pState;
249 }
250
251 MountainGM::MountainGM( const MtnState & state ) :
252 _ptOrigin(state.ptOrigin),
253 _fSeedObedience(state.fSeedObedience),
254 _fSeedIterations(state.fSeedIterations),
255 _nMntRangeWidth(state.nMntRangeWidth),
256 _nMntRangeAvgHeight(state.nMntRangeAvgHeight),
257 _mmnClumpSize(state.mmnClumpSize),
258 _fClumpMaxDisplace(state.fClumpMaxDisplace),
259 _nNumMountains(state.nNumMountains),
260 _fRotateThreshold(state.fRotateThreshold),
261 _fPeakHeightFluxPct (state.fPeakHeightFluxPct),
262 _fCoarseness(state.fCoarseness),
263 _fFalloff(state.fFalloff),
264 _bbox(state.bbox)
265 {
266
267 }
268
269 MountainGM::MountainGM(
270 const GWSurfacePos & ptOrigin,
271 const float fSeedObedience,
272 const float fSeedIterations,
273 const unsigned short nMntRangeWidth,
274 const unsigned short nMntRangeAvgHeight,
275 const mars::RangeX< unsigned short > mmnClumpSize,
276 const float fClumpMaxDisplace,
277 const unsigned short nNumMountains,
278 const float fRotateThreshold,
279 const float frPeakHeightFlux,
280 const float frCoarseness,
281 const float fFalloff )
282 :
283 _ptOrigin(ptOrigin),
284 _fSeedObedience(fSeedObedience),
285 _fSeedIterations(fSeedIterations),
286 _nMntRangeWidth(nMntRangeWidth),
287 _nMntRangeAvgHeight(nMntRangeAvgHeight),
288 _mmnClumpSize(mmnClumpSize),
289 _fClumpMaxDisplace(fClumpMaxDisplace),
290 _nNumMountains(nNumMountains),
291 _fRotateThreshold(fRotateThreshold),
292 _fPeakHeightFluxPct (frPeakHeightFlux),
293 _fCoarseness(frCoarseness),
294 _fFalloff(fFalloff)
295 {
296
297 }
298
299 GeoMorph * MountainGMFactory::createRandomInstance( const long x, const long y ) const
300 {
301 return new MountainGM(
302 GWSurfacePos(x, y),
303 _fSeedObedience,
304 _mmfSeedIterations.next(),
305 _mmnRangeWidth.next(),
306 _mmnPeakAvgHeight.next(),
307 _mmnClumpSize,
308 _fClumpMaxDisplace,
309 _mmnNumMountains.next(),
310 _mmfRotateThreshold.next(),
311 _frPeakHeightFlux,
312 _fCoarseness,
313 _fFalloff
314 );
315 }
316
317 void MountainGMFactory::configure( IConfigGMFactory * pFactoryConfig, const IConfigGMFactory::Settings & settings )
318 {
319 const geoworld::IConfigSection & section = *pFactoryConfig->getSection();
320
321 *section["seed_adherence"] >> _fSeedObedience;
322 *section["seed_iterations"] >> _mmfSeedIterations;
323 *section["num_peaks"] >> _mmnNumMountains;
324 *section["clump_size"] >> _mmnClumpSize;
325 *section["clump_displace"] >> _fClumpMaxDisplace;
326 *section["non_straightness"] >> _mmfRotateThreshold;
327 *section["range_width"] >> _mmnRangeWidth;
328 *section["height_flux"] >> _frPeakHeightFlux;
329 *section["peak_height"] >> _mmnPeakAvgHeight;
330 *section["coarseness"] >> _fCoarseness;
331 *section["falloff"] >> _fFalloff;
332 }
333
334 void MountainGMFactory::save( const GeoMorph * pGM, mars::ObjectStream & outs ) const
335 {
336 const MountainGM * pMGM = dynamic_cast< const MountainGM * > (pGM);
337
338 assert(pMGM != NULL);
339 *(pMGM->createState()) >> outs;
340 }
341
342 const GeoMorph * MountainGMFactory::restore( mars::ObjectStream & ins ) const
343 {
344 MountainGM::MtnState state;
345
346 state << ins;
347 return new MountainGM(state);
348 }
349
350 mars::ObjectStream & MountainGM::MtnState::operator >> ( mars::ObjectStream & outs ) const
351 {
352 outs << seeds << nNumMountains << fSeedObedience << fSeedIterations << fRotateThreshold << fPeakHeightFluxPct << fCoarseness << fFalloff << fClumpMaxDisplace << nMntRangeWidth << nMntRangeAvgHeight << ptOrigin << mmnClumpSize << bbox;
353 return outs;
354 }
355
356 mars::ObjectStream & MountainGM::MtnState::operator << ( mars::ObjectStream & ins )
357 {
358 ins >> seeds >> nNumMountains >> fSeedObedience >> fSeedIterations >> fRotateThreshold >> fPeakHeightFluxPct >> fCoarseness >> fFalloff >> fClumpMaxDisplace >> nMntRangeWidth >> nMntRangeAvgHeight >> ptOrigin >> mmnClumpSize >> bbox;
359 return ins;
360 }
361
362}
Note: See TracBrowser for help on using the repository browser.