source: Revenant/geoworld/src/worldfile.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: 15.7 KB
Line 
1#include "worldfile.h"
2
3#include <mars_log.h>
4#include <mars_calc.h>
5
6#include "lodtools.h"
7
8namespace mars
9{
10 template< typename T >
11 inline ObjectStream & operator << (ObjectStream & outs, const CylindricalRegion< T > & rr)
12 { return outs << rr.p << rr.r << rr.z; }
13
14 template< typename T >
15 inline ObjectStream & operator >> (ObjectStream & ins, CylindricalRegion< T > & rr)
16 { return ins >> rr.p >> rr.r >> rr.z; }
17}
18
19namespace geoworld
20{
21 TileMapDetails::TileMapDetails( const unsigned short nTileDim, const unsigned int nTilesW, const unsigned int nTilesH, const unsigned short nLOD /*= 0*/ )
22 : _nTileDim(nTileDim), _nTilesH(nTilesH), _nTilesW(nTilesW), _nLOD(nLOD)
23 {
24 // Must be a power of 2
25 assert(
26 ((static_cast< unsigned long > (_nTilesW) * _nTileDim - 1) & (static_cast< unsigned long > (_nTilesW) * _nTileDim)) == 0 &&
27 ((static_cast< unsigned long > (_nTilesH) * _nTileDim - 1) & (static_cast< unsigned long > (_nTilesH) * _nTileDim)) == 0
28 );
29 }
30
31 FileSource::MineralHostMap::MineralHostMap( mars::ptr< std::fstream > & pfhFile, const unsigned short nLayers, const unsigned short nLOD, const unsigned short nTileDim, const unsigned int nTilesW, const unsigned int nTilesH )
32 : VariableFileChunk(pfhFile), TileMapDetails(nTileDim, nTilesW, nTilesH, nLOD), _ppLayers(new LayerMap * [nLayers]),
33 count(nLayers), _pfhFile(pfhFile),
34 top(pfhFile, nTileDim, nTilesW, nTilesH, nLOD)
35 {
36 for(unsigned short c = 0; c < nLayers; ++c)
37 _ppLayers[c] = new LayerMap(pfhFile, nLOD, nTileDim, nTilesW, nTilesH);
38 }
39
40 FileSource::MineralHostMap::~MineralHostMap()
41 {
42 for(unsigned short c = 0; c < count; ++c)
43 delete _ppLayers[c];
44
45 delete [] _ppLayers;
46 }
47
48 void FileSource::MineralHostMap::init( const std::streamoff & szFileOffset, MainDEM * pPrevChunk )
49 {
50 std::streamoff szc = szFileOffset;
51
52 top.init(szc);
53 szc = top.end();
54 for (unsigned short c = 0; c < count; ++c)
55 {
56 _ppLayers[c]->init(szc);
57 szc = _ppLayers[c]->end();
58 }
59 _szLayers = szc - szFileOffset;
60
61 FileChunk::init(szFileOffset);
62 VariableFileChunk::init(pPrevChunk);
63 }
64
65 void FileSource::MineralHostMap::writeVariableData()
66 {
67 _pfhFile->seekp(getFileOffset() + _szLayers, std::ios::beg);
68
69 mars::ObjectStream outs (_pfhFile.pointer());
70 std::vector< std::string > vsDefs;
71
72 for (unsigned short i = 0; i < count; ++i)
73 *_ppLayers[i] >> outs;
74 }
75
76 void FileSource::MineralHostMap::readVariableData()
77 {
78 _pfhFile->seekg(getFileOffset() + _szLayers, std::ios::beg);
79
80 mars::ObjectStream ins (_pfhFile.pointer());
81 std::vector< std::string > vsDefs;
82
83 for (unsigned short i = 0; i < count; ++i)
84 *_ppLayers[i] << ins;
85 }
86
87 void FileSource::MineralHostMap::operator >> ( Stratum & stratum )
88 {
89 assert(stratum.layers == count);
90
91 top >> stratum.getBase();
92 for (size_t c = 0; c < count; ++c)
93 {
94 GeoStratumField::View & layer = stratum.field(c);
95 *_ppLayers[c] >> layer;
96 _ppLayers[c] ->putDefs(layer);
97 }
98 stratum.updateIndexMap();
99 }
100
101 void FileSource::MineralHostMap::operator << ( const Stratum & stratum )
102 {
103 assert(stratum.layers == count);
104 top << stratum.getBase();
105 for (size_t c = 0; c < count; ++c)
106 {
107 const GeoStratumField::View & layer = stratum.field(c);
108 *_ppLayers[c] << layer;
109 _ppLayers[c] ->setDefs(layer);
110 }
111 }
112
113 FileSource::MineralHostMap::LayerMap::LayerMap( mars::ptr< std::fstream > & pfhFile, const unsigned short nLOD, const unsigned short nTileDim, const unsigned int nTilesW, const unsigned int nTilesH, const std::vector< std::string > & vsDefs /*= std::vector< std::string > ()*/ )
114 : StreamTileMap(pfhFile, nTileDim, nTilesW, nTilesH, nLOD), _vsDefs(vsDefs)
115 {}
116
117 void FileSource::MineralHostMap::LayerMap::putDefs( GeoStratumField::View & field ) const
118 {
119 field.clearRegs();
120 for (DefList::const_iterator i = _vsDefs.begin(); i != _vsDefs.end(); ++i)
121 field.reg(mars::WeakReference< MineralClass > (*i));
122 }
123
124 void FileSource::MineralHostMap::LayerMap::setDefs( const GeoStratumField::View & field )
125 {
126 _vsDefs.clear();
127 for (GeoStratumField::ElementList::const_iterator i = field.beginElements(); i != field.endElements(); ++i)
128 _vsDefs.push_back(i->getName());
129 }
130
131 void FileSource::MineralMap::add( const MineralPtr & pMin, const QuadTreeSpherePacks::MyCylindricalRegion & cr )
132 {
133 _setMinerals.insert(pMin);
134 _qtMinerals.add(mars::ptr< MineralPtr > (new MineralPtr (pMin)), cr);
135 }
136
137 void FileSource::MineralMap::writeVariableData()
138 {
139 assert(_pfhFile->tellp() == getFileOffset());
140
141 _pfhFile->write(reinterpret_cast< const char * > (&_header), sizeof(_header));
142
143 mars::ObjectStream outs (_pfhFile.pointer());
144 size_t c = 0;
145 MineralIndex mapidxMins;
146
147 outs << static_cast< size_t > (_setMinerals.size());
148 for (MineralSet::const_iterator i = _setMinerals.begin(); i != _setMinerals.end(); ++i)
149 {
150 mapidxMins[*i] = c++;
151 outs << i->getName();
152 }
153
154 const long
155 nWidth = static_cast< signed long > (getVirtualWidth()),
156 nHeight = static_cast< signed long > (getVirtualHeight());
157
158 std::vector< SphereIndexReference > idxSector;
159 std::vector< std::streamoff > idxSectorLists;
160
161 _header.listsoff = _pfhFile->tellp() - getFileOffset();
162 for (QuadTreeSpherePacks::MyRectRegion rect(QuadTreeSpherePacks::VECTOR(), QuadTreeSpherePacks::VECTOR() + (getPhysicalTileDim() - 1));
163 rect.v1.y < nHeight; rect.v1.y += getVirtualTileDim(), rect.v2.y += getVirtualTileDim()
164 )
165 for (rect.v1.x = 0, rect.v2.x = getPhysicalTileDim() - 1;
166 rect.v1.x < nWidth; rect.v1.x += getVirtualTileDim(), rect.v2.x += getVirtualTileDim()
167 )
168 {
169 for (QuadTreeSpherePacks::const_EntityRectIterator k = const_cast< const QuadTreeSpherePacks & > (_qtMinerals).contents(QuadTreeSpherePacks::MyRectRegion(rect.v1, rect.v2)); k; ++k)
170 {
171 assert(mapidxMins.find(*k) != mapidxMins.end());
172 idxSector.push_back(SphereIndexReference(k.region(), mapidxMins[*k]));
173 }
174 idxSectorLists.push_back(_pfhFile->tellp() - getFileOffset());
175 outs << idxSector;
176 idxSector.clear();
177 }
178
179 _header.mapoffs = _pfhFile->tellp() - getFileOffset();
180 // Adjust the mapped-offsets now that we actually know where the mineral map begins!
181 for (std::vector< std::streamoff > ::iterator i = idxSectorLists.begin(); i != idxSectorLists.end(); ++i)
182 outs << *i;
183
184 LOG(mars::Log::Debug) << "Mineral map offset: " << _header.mapoffs;
185 LOG(mars::Log::Debug) << "Map index dump: " << idxSectorLists;
186
187 std::streampos pos0 = _pfhFile->tellp();
188
189 _pfhFile->seekp(getFileOffset());
190 _pfhFile->write(reinterpret_cast< const char * > (&_header), sizeof(_header));
191 _pfhFile->seekp(pos0); // Must always leave file pointer at the end of this chunk
192 }
193
194 FileSource::MineralMap::QuadTreeSpherePacks FileSource::MineralMap::createQuadTree( const unsigned short nTileDim, const unsigned int nTilesW, const unsigned int nTilesH )
195 {
196 const unsigned int nMaxAxis = std::max(nTilesH, nTilesW);
197 return QuadTreeSpherePacks(static_cast< long > (nMaxAxis) * nTileDim, mars::LOG2(nMaxAxis));
198 }
199
200 FileSource::MineralMap::MineralMap( mars::ptr< std::fstream > & pfhFile, const std::ios::openmode nOpenMode, const unsigned short nTileDim, const unsigned int nTilesW, const unsigned int nTilesH )
201 : VariableFileChunk(pfhFile), TileMapDetails(nTileDim, nTilesW, nTilesH), _pfhFile(pfhFile),
202 _qtMinerals(createQuadTree(nTileDim, nTilesW, nTilesH))
203 {}
204
205 FileSource::MineralMap::TileResult FileSource::MineralMap::operator () ( const unsigned int i, const unsigned int j )
206 {
207 SphRefVector results;
208
209 mars::ObjectStream ins (_pfhFile.pointer());
210 std::streamoff offList;
211
212 _pfhFile->seekg(
213 _header.mapoffs + getFileOffset()
214 +
215 (
216 static_cast< std::streamoff > (j) * getTilesWide() +
217 static_cast< std::streamoff > (i)
218 ) * sizeof(std::streamoff)
219 );
220
221 ins >> offList;
222 _pfhFile->seekg(getFileOffset() + offList, std::ios::beg);
223 ins >> results;
224 return TileResult(MinDefCache(&_mins), results);
225 }
226
227 void FileSource::MineralMap::readVariableData()
228 {
229 assert(_pfhFile->tellg() == getFileOffset());
230
231 _pfhFile->read(reinterpret_cast< char * > (&_header), sizeof(_header));
232
233 mars::ObjectStream ins (_pfhFile.pointer());
234
235 size_t nCount;
236 std::string s;
237
238 ins >> nCount;
239 _mins.clear();
240 for (size_t c = 0; c < nCount; ++c)
241 {
242 ins >> s;
243 _mins.push_back(s);
244 }
245 }
246
247 FileSource::FileSource( mars::ptr< std::fstream > & pfhFile, const std::ios::openmode nMode, const unsigned short nTileDim, const unsigned int nTilesW, const unsigned int nTilesH, const unsigned short nDepth, const unsigned short nGeoHostLOD, const unsigned short nGeoHostLayers)
248 : TileMapDetails(nTileDim, nTilesW, nTilesH),
249 tilemap(pfhFile, nTileDim, nTilesW, nTilesH),
250 geohost(pfhFile, nGeoHostLayers, nGeoHostLOD, nTileDim, nTilesW, nTilesH),
251 minerals(pfhFile, nMode, nTileDim, nTilesW, nTilesH),
252 _pfhFile(pfhFile), _nOpenMode(nMode),
253 _nHeaderEnd(sizeof(filesource::InfoHeader)),
254 _nDepth(nDepth)
255 {
256 assert(getVirtualTileDim() <= MAX_TILE_DIM);
257 assert(getTilesWide() <= MAX_AXIS_TILES && getTilesHigh() <= MAX_AXIS_TILES);
258 assert(nDepth <= MAX_WORLD_DEPTH);
259 _pfhFile->exceptions(std::ios::failbit | std::ios::badbit);
260
261 tilemap.init(sizeof(filesource::InfoHeader));
262 geohost.init(tilemap.end(), &tilemap);
263 minerals.init(&geohost);
264 }
265
266 FileSource::~FileSource()
267 {
268 if (_pfhFile != NULL)
269 {
270 _pfhFile->close();
271 }
272 }
273
274 FileSource * FileSource::open( const std::string & sFileName, const std::ios::openmode nMode )
275 {
276 using namespace std;
277 using namespace filesource;
278
279 const std::ios::openmode nOpenMode = nMode | ios::binary;
280 mars::ptr< fstream > pfhFile = new fstream(sFileName, nOpenMode);
281 if (!*pfhFile)
282 throw Ex("Failed to open file");
283
284 InfoHeader header;
285
286 pfhFile->read(reinterpret_cast< char * > (&header), sizeof(header));
287 if (!validate(header, pfhFile))
288 throw Ex("Failed to validate file");
289
290 return new FileSource(pfhFile, nOpenMode, header.tdim, header.tx, header.ty, header.depth, header.geohost.lod, header.geohost.layers);
291 }
292
293 FileSource * FileSource::create( const std::string & sFileName, const unsigned long nMinWidth, const unsigned long nMinHeight, const unsigned short nDepth, const unsigned short nTileDim, const unsigned short nGeoHostLOD, const unsigned short nGeoHostLayerCount )
294 {
295 using namespace std;
296 using namespace filesource;
297
298 const std::ios::openmode nOpenMode = ios::in | ios::out | ios::binary | ios::trunc;
299 mars::ptr< fstream > pfhFile = new fstream(sFileName, nOpenMode);
300 if (!*pfhFile)
301 throw Ex("Failed to open file");
302
303 assert(nMinWidth >= nTileDim && nMinHeight >= nTileDim && nTileDim > 0);
304 assert(((nTileDim - 1) & nTileDim) == 0); // Must be a power of 2
305
306 InfoHeader header;
307 const unsigned int
308 nTilesW = static_cast< unsigned int > (dimXp2(nMinWidth / nTileDim + 1)),
309 nTilesH = static_cast< unsigned int > (dimXp2(nMinHeight / nTileDim + 1));
310
311 header.tx = nTilesW;
312 header.ty = nTilesH;
313 header.tdim = nTileDim;
314 header.depth = nDepth;
315 header.geohost.layers = nGeoHostLayerCount;
316 header.geohost.lod = nGeoHostLOD;
317
318 pfhFile->write(reinterpret_cast< const char * > (&header), sizeof(header));
319
320 return new FileSource(pfhFile, nOpenMode, nTileDim, nTilesW, nTilesH, nDepth, nGeoHostLOD, nGeoHostLayerCount);
321 }
322
323 bool FileSource::validate( const filesource::InfoHeader & header, mars::ptr< std::fstream > & pfhFile )
324 {
325 using namespace filesource;
326
327 const std::streamoff off0 = pfhFile->tellg();
328 pfhFile->seekg(0, std::ios::end);
329
330 // TODO: Strong validation for other file layers
331 const bool bFileSize = (pfhFile->tellg() >= (static_cast< std::streampos > (header.tx) * header.ty * mars::SQ(header.tdim + 1) * sizeof(GeoHeightMap::Precision) + sizeof(InfoHeader)));
332 pfhFile->seekg(off0, std::ios::beg);
333
334 return header.validate() && bFileSize;
335 }
336
337 void FileSource::commit()
338 {
339 geohost.commit();
340 minerals.commit();
341 }
342
343 void FileSource::load()
344 {
345 geohost.load();
346 minerals.load();
347 }
348
349 void FileSource::applyDEM( const GeoHeightMap * pHM, const float fCoarseness )
350 {
351 assert (
352 ((pHM->width - 1) & pHM->width) == 0 &&
353 ((pHM->height - 1) & pHM->height) == 0 &&
354 pHM->gridtype == mars::Wrap
355 ); // The low LOD HM must have dimensions as a power of 2
356 assert(pHM->width % getVirtualTileDim() == 0 && pHM->height % getVirtualTileDim() == 0);
357
358 LODMagnifier< GeoHeightMap::Precision > magnifier (
359 *pHM,
360 mars::LOG2(static_cast< unsigned long > (getVirtualWidth()) / pHM->width),
361 getVirtualTileDim(), fCoarseness, getVirtualWidth(), getVirtualHeight()
362 );
363 // TODO: Verify, compare with:
364 /*LODMagnifier< GeoHeightMap::Precision > magnifier (
365 hmLowLOD,
366 LOG2(static_cast< unsigned long > (nTilesW) * nTileDim / hmLowLOD.width),
367 nTileDim, fCoarseness, getWorldWidth(), getWorldHeight()
368 );*/
369
370 magnifier.write(tilemap);
371 }
372
373 const std::streampos & FileChunk::getFileOffset() const
374 {
375 assert(_szFileOffset > -1);
376 return _szFileOffset;
377 }
378
379 void FileChunk::setFileOffset( const std::streamoff & szFileOffset )
380 { _szFileOffset = szFileOffset; }
381
382 FileChunk::FileChunk() : _szFileOffset (-1) {}
383
384 void FileChunk::init( const std::streamoff & szFileOffset )
385 { _szFileOffset = szFileOffset; }
386
387 bool FileChunk::isSetFileOffset() const
388 { return _szFileOffset != static_cast< std::streampos > (-1); }
389
390 void StaticFileChunk::setSize( const std::streamoff & szSize )
391 { _szSize = szSize; }
392
393 std::streampos StaticFileChunk::end() const
394 {
395 assert(getFileOffset() > -1 && _szSize > -1);
396 return getFileOffset() + _szSize;
397 }
398
399
400 VariableFileChunk::VariableFileChunk( const mars::ptr< std::fstream > & pfhFile )
401 : _pfhFile(pfhFile), _pNextChunk(NULL), _pPrevChunk(NULL), _bDirty(false), _szChunkEnd(-1)
402 {}
403
404 void VariableFileChunk::init( FileChunk * pPreviousChunk )
405 {
406 _pPrevChunk = pPreviousChunk;
407
408 VariableFileChunk * pVariablePrevChunk = dynamic_cast< VariableFileChunk * > (pPreviousChunk);
409
410 if (pVariablePrevChunk != NULL)
411 pVariablePrevChunk->_pNextChunk = this;
412 }
413
414 std::streampos VariableFileChunk::end() const
415 {
416 assert(_szChunkEnd > -1);
417 return _szChunkEnd;
418 }
419
420 void VariableFileChunk::dirty()
421 { _bDirty = true; }
422
423 void VariableFileChunk::load()
424 {
425 if (_pPrevChunk != NULL)
426 _pfhFile->seekg(_pPrevChunk->end());
427
428 setFileOffset(_pfhFile->tellg());
429 readVariableData();
430 _szChunkEnd = _pfhFile->tellg();
431
432 _bDirty = false;
433 }
434
435 void VariableFileChunk::commit()
436 {
437 if (_pPrevChunk != NULL)
438 _pfhFile->seekp(_pPrevChunk->end());
439
440 setFileOffset(_pfhFile->tellp());
441 writeVariableData();
442 _szChunkEnd = _pfhFile->tellp();
443
444 _bDirty = false;
445 }
446
447
448 void FileSource::MineralHostMap::Offset::operator >> ( Stratum & stratum )
449 {
450 TopDEM::Block * pHeightBlock = _pMap->createTopDEMBlock();
451 LayerMap::Block * pLayerBlock = _pMap->createLayerBlock();
452
453 _pMap->top.seekg(x, y, std::ios::beg);
454 _pMap->top >> *pHeightBlock;
455 *pHeightBlock >> stratum.getBase();
456 for (size_t c = 0; c < _pMap->count; ++c)
457 {
458 GeoStratumField::View & stratlayer = stratum.field(c);
459 LayerMap & filelayer = _pMap->layer(c);
460 filelayer.seekg(x, y, std::ios::beg);
461 filelayer >> *pLayerBlock;
462 *pLayerBlock >> stratlayer;
463 filelayer.putDefs(stratlayer);
464 }
465 stratum.updateIndexMap();
466
467 delete pLayerBlock;
468 delete pHeightBlock;
469 }
470
471 void FileSource::MineralHostMap::Offset::operator << ( const Stratum & stratum )
472 {
473 TopDEM::Block * pHeightBlock = _pMap->createTopDEMBlock();
474 LayerMap::Block * pLayerBlock = _pMap->createLayerBlock();
475
476 _pMap->top.seekp(x, y, std::ios::beg);
477 *pHeightBlock << stratum.getBase();
478 _pMap->top << *pHeightBlock;
479 for (size_t c = 0; c < _pMap->count; ++c)
480 {
481 const GeoStratumField::View & stratlayer = stratum.field(c);
482 LayerMap & filelayer = _pMap->layer(c);
483 filelayer.seekp(x, y, std::ios::beg);
484 *pLayerBlock << stratlayer;
485 filelayer << *pLayerBlock;
486 filelayer.setDefs(stratlayer);
487 }
488
489 delete pLayerBlock;
490 delete pHeightBlock;
491 }
492
493 FileSource::MineralHostMap::Offset::Offset( MineralHostMap * const pMap, const signed int x, const signed int y )
494 : _pMap(pMap), x(x), y(y) {}
495
496}
Note: See TracBrowser for help on using the repository browser.