#include "volcano.h" #include #include "geoworld.h" namespace geoworld { void VolcanoGM::init(SynthesisSession & manager, const IGeoWorldAccessor & accessor, const unsigned short nMaxWidth, const unsigned short nMaxHeight) { using namespace mars; const int nOutside = RNDi(_czone.outside()); _bbox = BBox< long > ( -nOutside, -nOutside, +nOutside, +nOutside ); const GWCoords gcOrigin = GWCoords(0, 0, accessor.mean(_ptOrigin.x, _ptOrigin.y)); for (unsigned int i = 0; i < _nNumLavaFlows; ++i) { const VectorTag< float >::V3 vc = _czone.random(gcOrigin); _chans.addStartPoint (vc, PolarCoords< float > (vc).azimuth); } const float nNewHalfWidth = static_cast< float > (nMaxWidth) / 2, nNewHalfHeight = static_cast< float > (nMaxHeight) / 2; _chans.init( new FluiDynQueryBridge(&accessor, _ptOrigin), // TODO: Is it right to use ptOrigin with a local bbox? _mmnLevels.next(), mars::BBox< float > ( -nNewHalfWidth + 1, -nNewHalfHeight + 1, +nNewHalfWidth - 1, +nNewHalfHeight - 1 ) ); _bbox.add (static_cast< BBox< long > > (_chans.getBBox())); _bbox += _ptOrigin; } void VolcanoGM::doMorph( LockedGWSection & section ) const { using namespace mars; const unsigned short nDim = static_cast (_czone.outside() * 2.0f), nInnerDim = static_cast< unsigned short > (_czone.getIntersect()); const unsigned short nVolcHalfDim = static_cast< unsigned short > (ceil (_czone.outside())); const GWCoords gcOrigin = section.createCoordsRVN(_ptOrigin, nVolcHalfDim / 2); LockedGWSection::View * pView = section.createView( gcOrigin.x - nVolcHalfDim, gcOrigin.y - nVolcHalfDim, gcOrigin.x + nVolcHalfDim, gcOrigin.y + nVolcHalfDim ); ptr< NoiseGenerator< float >::NoiseMap > mpgrid = _noise.compute(nDim, nDim), mpcones = _noise.compute(nInnerDim, nInnerDim); for (ConeZone::UpsideDEMIterator it = _czone.walkUpside(GWCoords(0, 0, gcOrigin.z)); it; ++it) { const VectorTag< short > ::V2 i2d = it->v2D(), a = i2d + nVolcHalfDim; (*pView->getHeightMap())(a.x, a.y) = blend( (*pView->getHeightMap())(a.x, a.y), it->z + (*mpgrid)(i2d.x, i2d.y), _czone.taper(i2d.x, i2d.y) ); } // TODO: Verify use of RNDi const GWCoords::Precision fFull = static_cast< GWCoords::Precision > (mars::RNDi(_czone.full(_frCalderaFull))); for (std::vector< ConeZone >::const_iterator i = _inners.begin(); i != _inners.end(); ++i) { const ConeZone & ic = *i; ADDCROSS_GLOBALDEM( static_cast< unsigned short > (ic.delta.x + gcOrigin.x), static_cast< unsigned short > (ic.delta.y + gcOrigin.y) ); INCCROSS_GLOBALDEM(); const GWCoords::Precision ic_delta_x = static_cast< GWCoords::Precision > (mars::RNDi(ic.delta.x)), ic_delta_y = static_cast< GWCoords::Precision > (mars::RNDi(ic.delta.y)), x = gcOrigin.x + ic_delta_x, // TODO: Verify use of RNDi y = gcOrigin.y + ic_delta_y; // TODO: Verify use of RNDi const GWCoords gcInner( x, y, std::max( section.getSurfaceMean(x, y), static_cast (fFull + gcOrigin.z + (*mpgrid)(0, 0)) ) ); for (ConeZone::UpsideDEMIterator< ConeZone > j = ic.walkUpside(gcInner); j; ++j) { const VectorTag< short > ::V2 j2d = j->v2D(), r = j2d - static_cast< GWSurfacePos > (gcInner), a = j2d - _ptOrigin + nVolcHalfDim; (*pView->getHeightMap())(a.x, a.y) = blend( (*pView->getHeightMap())(a.x, a.y), std::max( (*pView->getHeightMap())(a.x, a.y), static_cast< GeoHeightMap::Precision > ( j->z + (*mpcones)(j->x + ic_delta_x, j->y + ic_delta_y) ) ), ic.taper(r.x, r.y) ); } } section.releaseView(pView); mars::BBox< long > bbox = getBBox(); pView = section.createView(bbox.left, bbox.top, bbox.right, bbox.bottom); _chans.run(pView); section.releaseView(pView); } VolcanoGM::VolcanoGM ( const GWSurfacePos & ptOrigin, const float frNoise, const float fScale, const float fConeBroadness, const float fConeAmplitude, const float fCalderaBroadness, const float frCalderaDepthRatio, const float frCalderaFull, const float fConeFalloffFactor, const unsigned int nNumInnerCones, const mars::RangeX< float > & mmfInnerConeRelativeScale, const mars::RangeX< float > & mmfInnerConeBroadness, const mars::RangeX< float > & mmfInnerConeAmplitude, const mars::RangeX< float > & mmfInnerCalderaBroadness, const mars::RangeX< float > & mmfrInnerCalderaDepthRatio, const mars::RangeX< float > & mmfrInnerConeDisplaceRatio, // Lava flow configs // TODO: Sort out this mess of parameters, way too many! const unsigned int nNumLavaFlows, const float fLavaWaveScale, const float fLavaWavePhase, const float fLavaWaveAmplitude, const float fLavaViscosity, const float frLavaWavePerturbance, const float fLavaFlowHeight, // FluiDyn configs const mars::RangeX< float > & mmfBendZenith, const unsigned short nBendZenithSteps, const unsigned short nCandidateSampleAmt, const mars::RangeX< float > & mmfSplineSeg, const float fGravitySlopeGrace, const float frSnapToGuide, const mars::RangeX< float > & mmfFlowLineWidth, const mars::RangeX< unsigned int > & mmnLevels, const mars::RangeX< unsigned int > & mmnKidsPerLevel, const float fwStraightness, const float fwElevationInfluence, const float fwDensityInfluence, const float fwChaosInfluence ) : _czone( ConeFn(fScale, fConeAmplitude, fConeBroadness, 0), CalderaFn(fScale, fCalderaBroadness, fConeAmplitude * frCalderaDepthRatio), fConeFalloffFactor ), _frCalderaFull(frCalderaFull), _mmfInnerConeRelativeScale(mmfInnerConeRelativeScale), _mmfInnerConeBroadness(mmfInnerConeBroadness), _mmfInnerConeAmplitude(mmfInnerConeAmplitude), _mmfrInnerCalderaDepthRatio(mmfrInnerCalderaDepthRatio), _mmfInnerCalderaBroadness(mmfInnerCalderaBroadness), _mmfrInnerConeDisplaceRatio(mmfrInnerConeDisplaceRatio), _ptOrigin(ptOrigin), _nNumLavaFlows (nNumLavaFlows), _mmnLevels(mmnLevels), _chans( mmfBendZenith, nBendZenithSteps, nCandidateSampleAmt, mmfSplineSeg, fGravitySlopeGrace, frSnapToGuide, mmfFlowLineWidth, mmnKidsPerLevel, fwStraightness, fwElevationInfluence, fwDensityInfluence, fwChaosInfluence, fLavaFlowHeight, fLavaWaveScale, fLavaWavePhase, fLavaWaveAmplitude, fLavaViscosity, frLavaWavePerturbance, 1.0f ), _noise(0.4f, frNoise) { for (unsigned int i = 0; i < nNumInnerCones; ++i) addInner( _mmfInnerConeRelativeScale.next(), _mmfInnerConeAmplitude.next(), _mmfInnerConeBroadness.next(), _mmfInnerCalderaBroadness.next(), _mmfrInnerCalderaDepthRatio.next(), fConeFalloffFactor, VectorTag< float > ::PC ( _mmfrInnerConeDisplaceRatio.next(), mars::RANDf(static_cast< float > (mars::PI * 2.0)) ) ); } VolcanoGM::VolcanoGM() : _frCalderaFull(0), _nNumLavaFlows (0), _noise(0.4f, 0) {} VolcanoGM * VolcanoGM::createInstance( mars::ObjectStream & ins ) { VolcanoGM * pVGM = new VolcanoGM (); ins >> pVGM->_ptOrigin >> pVGM->_bbox >> pVGM->_mmnLevels >> pVGM->_nNumLavaFlows >> pVGM->_mmfInnerConeRelativeScale >> pVGM->_mmfInnerConeBroadness >> pVGM->_mmfInnerConeAmplitude >> pVGM->_mmfrInnerCalderaDepthRatio >> pVGM->_mmfInnerCalderaBroadness >> pVGM->_mmfrInnerConeDisplaceRatio >> pVGM->_frCalderaFull >> pVGM->_noise.noise; size_t nInnerCount; ins >> nInnerCount; pVGM->_inners.clear(); pVGM->_inners.reserve(nInnerCount); ConeZone inner; for (size_t c = 0; c < nInnerCount; ++c) { inner << ins; pVGM->_inners.push_back(inner); } pVGM->_czone << ins; pVGM->_chans << ins; return pVGM; } mars::ObjectStream & VolcanoGM::operator >> ( mars::ObjectStream & outs ) const { outs << _ptOrigin << _bbox << _mmnLevels << _nNumLavaFlows << _mmfInnerConeRelativeScale << _mmfInnerConeBroadness << _mmfInnerConeAmplitude << _mmfrInnerCalderaDepthRatio << _mmfInnerCalderaBroadness << _mmfrInnerConeDisplaceRatio << _frCalderaFull << _noise.noise; outs << static_cast< size_t > (_inners.size()); for (InnersList::const_iterator i = _inners.begin(); i != _inners.end(); ++i) *i >> outs; _czone >> outs; _chans >> outs; return outs; } void VolcanoGM::MyChannelSet::applyFlowLine( const FlowLineType & fl, VolcanoGM::LavaFlowData * pData ) const { const mars::ptr< FlowPerturbation > ppert = _ngenPert.compute ( static_cast< short > (mars::RNDi(fl.radius * 2)), // TODO: Verify use of RNDi static_cast< short > (mars::RNDi(fl.getLength())) // TODO: Verify use of RNDi ); for (MyChannelSet::FlowLineType::Iterator it = fl.iterate(_fnEaseIn, _fnEaseOut); it; ++it) { const mars::vector2D & pos = *it; const float fTotalRadius = static_cast (it.crad()), fRad = it.trad(), fBevel = fTotalRadius * _pfnBevel->f(fRad); pData->hmbb(pos.x, pos.y) = std::max( static_cast< GeoHeightMap::Precision > ( pData->view.mean5(pos.x, pos.y) + _fnWave.f(static_cast< float > (it.sradius()), it.distance(), fTotalRadius, *ppert) * fBevel + fBevel ), pData->hmbbb(pos.x, pos.y) ); } pData->hmbb >> pData->hmbbb; } void VolcanoGM::MyChannelSet::run( LockedGWSection::View * pView ) const { LavaFlowData data(pView->getHeightMap()); VolcanoGM::ChannelSetType::run(&data); } void VolcanoGM::MyChannelSet::init( const mars::ptr< FluiDynQueryBridge > & pQuery, const unsigned int nLevels, const mars::BBox< float > & bboxSearch ) { using namespace mars; ChannelSetType::init(pQuery, bboxSearch, nLevels); const BBox< long > bbox = getBBox(); const GWCoords pos3d = GWCoords(-bbox.left, -bbox.top, 0); for (MyChannelSet::GuideList::iterator i = begin(); i != end(); ++i) (*i)->offsetBy(pos3d); } mars::ObjectStream & VolcanoGM::MyChannelSet::operator >> ( mars::ObjectStream & outs ) const { ChannelSetType::operator >> (outs); outs << _ngenPert.noise << _pfnBevel->amplitude << _pfnBevel->getResolution(); _fnWave >> outs; return outs; } mars::ObjectStream & VolcanoGM::MyChannelSet::operator << ( mars::ObjectStream & ins ) { ChannelSetType::operator << (ins); unsigned short nFlowBevelResolution; float fFlowBevelAmplitude; ins >> _ngenPert.noise >> fFlowBevelAmplitude >> nFlowBevelResolution; _fnWave << ins; delete _pfnBevel; _pfnBevel = new FlowBevelFn(nFlowBevelResolution, fFlowBevelAmplitude); return ins; } VolcanoGM::MyChannelSet::MyChannelSet ( const mars::RangeX< float > & mmfBendZenith, const unsigned int nBendZenithSteps, const unsigned int nCandidateSampleAmt, const mars::RangeX< float > & mmfSplineSeg, const float fGravitySlopeGrace, const float frSnapToGuide, const mars::RangeX< float > & mmfFlowLineWidth, const mars::RangeX< unsigned int > & mmnKidsPerLevel, const float fwStraightness, const float fwElevationInfluence, const float fwDensityInfluence, const float fwChaosInfluence, const float fLavaFlowHeight, const float fWaveScale, const float fPhase, const float fAmplitude, const float fViscosity, const float fPerturbance, const float fPertNoise ) : ChannelSet( mmfBendZenith, nBendZenithSteps, nCandidateSampleAmt, mmfSplineSeg, fGravitySlopeGrace, frSnapToGuide, mmfFlowLineWidth, mmnKidsPerLevel, fwStraightness, fwElevationInfluence, fwDensityInfluence, fwChaosInfluence ), _fnEaseOut(createEaseOutFn()), _fnEaseIn(createEaseInFn()), _pfnBevel(new FlowBevelFn( mmfFlowLineWidth.maximum, fLavaFlowHeight )), _fnWave( fPhase, fAmplitude, fViscosity, fPerturbance, fWaveScale ), _ngenPert(0.8f, fPertNoise) {} VolcanoGM::MyChannelSet::MyChannelSet() : _fnEaseOut(createEaseOutFn()), _fnEaseIn(createEaseInFn()), _pfnBevel(NULL), _ngenPert(0.8f, 0) {} VolcanoGM::MyChannelSet::~MyChannelSet() { delete _pfnBevel; } GeoMorph * VolcanoGMFactory::createRandomInstance( const long x, const long y ) const { return new VolcanoGM( GWSurfacePos (x, y), _frNoise, _mmfScale.next(), _mmfConeBroadness.next(), _mmfConeAmplitude.next(), _mmfCalderaBroadness.next(), _mmfrCalderaDepthRatio.next(), _mmfrCalderaFull.next(), _fConeFalloffFactor, _mmnNumInnerCones.next(), _mmfInnerConeRelativeScale, _mmfInnerConeBroadness, _mmfInnerConeAmplitude, _mmfInnerCalderaBroadness, _mmfrInnerCalderaDepthRatio, _mmfrInnerConeDisplaceRatio, _mmnNumLavaFlows.next(), _mmfLavaWaveScale.next(), _mmfLavaWavePhase.next(), _mmfLavaWaveAmplitude.next(), _mmfLavaViscosity.next(), _frLavaWavePerturbance, _mmfLavaFlowHeight.next(), _mmfBendZenith, _nBendZenithSteps, _nCandidateSampleAmt, _mmfSplineSeg, _fGravitySlopeGrace, _frSnapToGuide, _mmfFlowLineWidth, _mmnLevels, _mmnKidsPerLevel, _fwStraightness, _fwElevationInfluence, _fwDensityInfluence, _fwChaosInfluence ); } void VolcanoGMFactory::configure( IConfigGMFactory * pFactoryConfig, const IConfigGMFactory::Settings & settings ) { geoworld::IConfigSection & section = *pFactoryConfig->getSection(), & sectCone = *section.getmap("cone"), & sectCaldera = *section.getmap("caldera"), & sectInnerCones = *section.getmap("innercones"), & sectInnerConesCalderas = *sectInnerCones.getmap("caldera"), & sectLava = *section.getmap("lavaflows"), & sectLavaWaves = *sectLava.getmap("waves"), & sectLavaCandidates = *sectLava.getmap("candidates"), & sectLavaFlowlines = *sectLava.getmap("flowlines"), & sectLavaWeights = *sectLava.getmap("weights"); *section["noise"] >> _frNoise; *section["scale"] >> _mmfScale; *sectCone["broadness"] >> _mmfConeBroadness; *sectCone["amplitude"] >> _mmfConeAmplitude; *sectCone["falloff"] >> _fConeFalloffFactor; *sectCaldera["broadness"] >> _mmfCalderaBroadness; *sectCaldera["fullness"] >> _mmfrCalderaFull; *sectCaldera["depth"] >> _mmfrCalderaDepthRatio; *sectInnerCones["amount"] >> _mmnNumInnerCones; *sectInnerCones["scale"] >> _mmfInnerConeRelativeScale; *sectInnerCones["broadness"] >> _mmfInnerConeBroadness; *sectInnerCones["amplitude"] >> _mmfInnerConeAmplitude; *sectInnerConesCalderas["broadness"] >> _mmfInnerCalderaBroadness; *sectInnerConesCalderas["depth"] >> _mmfrInnerCalderaDepthRatio; *sectInnerCones["displacement"] >> _mmfrInnerConeDisplaceRatio; *sectLavaCandidates["bend_zenith"] >> _mmfBendZenith; *sectLavaCandidates["zenith_steps"] >> _nBendZenithSteps; *sectLavaCandidates["samples"] >> _nCandidateSampleAmt; *sectLava["segment"] >> _mmfSplineSeg; *sectLava["slope_grace"] >> _fGravitySlopeGrace; *sectLava["guide_snap"] >> _frSnapToGuide; *sectLava["amount"] >> _mmnNumLavaFlows; *sectLava["height"] >> _mmfLavaFlowHeight; *sectLavaWaves["scale"] >> _mmfLavaWaveScale; *sectLavaWaves["frequency"] >> _mmfLavaWavePhase; *sectLavaWaves["amplitude"] >> _mmfLavaWaveAmplitude; *sectLavaWaves["viscosity"] >> _mmfLavaViscosity; *sectLavaWaves["perturbation"] >> _frLavaWavePerturbance; *sectLavaFlowlines["width"] >> _mmfFlowLineWidth; *sectLavaFlowlines["levels"] >> _mmnLevels; *sectLavaFlowlines["children"] >> _mmnKidsPerLevel; *sectLavaWeights["straightness"] >> _fwStraightness; *sectLavaWeights["elevation"] >> _fwElevationInfluence; *sectLavaWeights["density"] >> _fwDensityInfluence; *sectLavaWeights["chaos"] >> _fwChaosInfluence; } void VolcanoGMFactory::save( const GeoMorph * pGM, mars::ObjectStream & outs ) const { const VolcanoGM * pVGM = dynamic_cast< const VolcanoGM * > (pGM); assert(pVGM != NULL); *pVGM >> outs; } const GeoMorph * VolcanoGMFactory::restore( mars::ObjectStream & ins ) const { VolcanoGM * pVGM; pVGM << ins; return pVGM; } }