3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 (c) 2010 Perttu Ahola <celeron55@gmail.com>
24 #include "heightmap.h"
30 ValueGenerator* ValueGenerator::deSerialize(std::string line)
32 std::istringstream ss(line);
33 //ss.imbue(std::locale("C"));
36 std::getline(ss, name, ' ');
38 if(name == "constant")
43 return new ConstantGenerator(value);
45 else if(name == "linear")
54 return new LinearGenerator(height, slope);
56 else if(name == "power")
67 return new PowerGenerator(height, slope, power);
71 throw SerializationError
72 ("Invalid heightmap generator (deSerialize)");
80 f32 FixedHeightmap::avgNeighbours(v2s16 p, s16 d)
90 for(u16 i=0; i<4; i++){
91 v2s16 p2 = p + dirs[i] * d;
92 f32 n = getGroundHeightParent(p2);
93 if(n < GROUNDHEIGHT_VALID_MINVALUE)
98 assert(count > 0.001);
102 f32 FixedHeightmap::avgDiagNeighbours(v2s16 p, s16 d)
112 for(u16 i=0; i<4; i++){
113 v2s16 p2 = p + dirs[i] * d;
114 f32 n = getGroundHeightParent(p2);
115 if(n < GROUNDHEIGHT_VALID_MINVALUE)
120 assert(count > 0.001);
125 Adds a point to transform into a diamond pattern
126 center = Center of the diamond phase (center of a square)
127 a = Side length of the existing square (2, 4, 8, ...)
129 Adds the center points of the next squares to next_squares as
132 void FixedHeightmap::makeDiamond(
136 core::map<v2s16, bool> &next_squares)
138 /*dstream<<"makeDiamond(): center="
139 <<"("<<center.X<<","<<center.Y<<")"
140 <<", a="<<a<<", randmax="<<randmax
141 <<", next_squares.size()="<<next_squares.size()
144 f32 n = avgDiagNeighbours(center, a/2);
145 // Add (-1.0...1.0) * randmax
146 n += ((float)myrand() / (float)(MYRAND_MAX/2) - 1.0)*randmax;
147 bool worked = setGroundHeightParent(center, n);
151 next_squares[center + a/2*v2s16(-1,0)] = true;
152 next_squares[center + a/2*v2s16(1,0)] = true;
153 next_squares[center + a/2*v2s16(0,-1)] = true;
154 next_squares[center + a/2*v2s16(0,1)] = true;
159 Adds a point to transform into a square pattern
160 center = The point that is added. The center of a diamond.
161 a = Diameter of the existing diamond. (2, 4, 8, 16, ...)
163 Adds center points of the next diamonds to next_diamonds.
165 void FixedHeightmap::makeSquare(
169 core::map<v2s16, bool> &next_diamonds)
171 /*dstream<<"makeSquare(): center="
172 <<"("<<center.X<<","<<center.Y<<")"
173 <<", a="<<a<<", randmax="<<randmax
174 <<", next_diamonds.size()="<<next_diamonds.size()
177 f32 n = avgNeighbours(center, a/2);
178 // Add (-1.0...1.0) * randmax
179 n += ((float)myrand() / (float)(MYRAND_MAX/2) - 1.0)*randmax;
180 bool worked = setGroundHeightParent(center, n);
184 next_diamonds[center + a/4*v2s16(1,1)] = true;
185 next_diamonds[center + a/4*v2s16(-1,1)] = true;
186 next_diamonds[center + a/4*v2s16(-1,-1)] = true;
187 next_diamonds[center + a/4*v2s16(1,-1)] = true;
191 void FixedHeightmap::DiamondSquare(f32 randmax, f32 randfactor)
199 // Check that a is a power of two
203 core::map<v2s16, bool> next_diamonds;
204 core::map<v2s16, bool> next_squares;
206 next_diamonds[v2s16(a/2, a/2)] = true;
210 next_squares.clear();
212 for(core::map<v2s16, bool>::Iterator
213 i = next_diamonds.getIterator();
214 i.atEnd() == false; i++)
216 v2s16 p = i.getNode()->getKey();
217 makeDiamond(p, a, randmax, next_squares);
222 next_diamonds.clear();
224 for(core::map<v2s16, bool>::Iterator
225 i = next_squares.getIterator();
226 i.atEnd() == false; i++)
228 v2s16 p = i.getNode()->getKey();
229 makeSquare(p, a, randmax, next_diamonds);
235 randmax *= randfactor;
239 void FixedHeightmap::generateContinued(f32 randmax, f32 randfactor,
242 DSTACK(__FUNCTION_NAME);
243 /*dstream<<"FixedHeightmap("<<m_pos_on_master.X
244 <<","<<m_pos_on_master.Y
245 <<")::generateContinued()"<<std::endl;*/
247 // Works only with blocksize=2,4,8,16,32,64,...
250 // Check that a is a power of two
251 assert((a & (a-1)) == 0);
253 // Overwrite with GROUNDHEIGHT_NOTFOUND_SETVALUE
254 for(s16 y=0; y<=a; y++){
255 for(s16 x=0; x<=a; x++){
257 setGroundHeight(p, GROUNDHEIGHT_NOTFOUND_SETVALUE);
262 Seed borders from master heightmap
263 NOTE: Does this actually have any effect on the output?
267 v2s16 neighbour_start;
268 v2s16 heightmap_start;
274 { // Z- edge on X-axis
275 v2s16(0, -1), // neighbour_start
276 v2s16(0, 0), // heightmap_start
279 { // Z+ edge on X-axis
280 v2s16(0, m_blocksize),
281 v2s16(0, m_blocksize),
284 { // X- edge on Z-axis
289 { // X+ edge on Z-axis
290 v2s16(m_blocksize, 0),
291 v2s16(m_blocksize, 0),
296 for(s16 i=0; i<4; i++){
297 v2s16 npos = seeds[i].neighbour_start + m_pos_on_master * m_blocksize;
298 v2s16 hpos = seeds[i].heightmap_start;
299 for(s16 s=0; s<m_blocksize+1; s++){
300 f32 h = m_master->getGroundHeight(npos, false);
301 //dstream<<"h="<<h<<std::endl;
302 if(h < GROUNDHEIGHT_VALID_MINVALUE)
305 setGroundHeight(hpos, h);
306 hpos += seeds[i].dir;
307 npos += seeds[i].dir;
311 /*dstream<<"borders seeded:"<<std::endl;
315 Fill with corners[] (if not already set)
323 for(u16 i=0; i<4; i++){
324 v2s16 npos = dirs[i] * a;
325 // Don't replace already seeded corners
326 f32 h = getGroundHeight(npos);
327 if(h > GROUNDHEIGHT_VALID_MINVALUE)
329 setGroundHeight(dirs[i] * a, corners[i]);
332 /*dstream<<"corners filled:"<<std::endl;
335 DiamondSquare(randmax, randfactor);
338 u32 FixedHeightmap::serializedLength(u8 version, u16 blocksize)
340 if(!ser_ver_supported(version))
341 throw VersionMismatchException("ERROR: FixedHeightmap format not supported");
345 /*// [0] s32 blocksize
346 // [4] v2s16 pos_on_master
347 // [8] s32 data[W*H] (W=H=blocksize+1)
348 return 4 + 4 + (blocksize+1)*(blocksize+1)*4;*/
350 // [8] s32 data[W*H] (W=H=blocksize+1)
351 return (blocksize+1)*(blocksize+1)*4;
355 u32 FixedHeightmap::serializedLength(u8 version)
357 return serializedLength(version, m_blocksize);
360 void FixedHeightmap::serialize(u8 *dest, u8 version)
362 //dstream<<"FixedHeightmap::serialize"<<std::endl;
364 if(!ser_ver_supported(version))
365 throw VersionMismatchException("ERROR: FixedHeightmap format not supported");
369 /*writeU32(&dest[0], m_blocksize);
370 writeV2S16(&dest[4], m_pos_on_master);
372 for(u32 i=0; i<nodecount; i++)
374 writeS32(&dest[8+i*4], (s32)(m_data[i]*1000.0));
378 for(u32 i=0; i<nodecount; i++)
380 writeS32(&dest[i*4], (s32)(m_data[i]*1000.0));
385 void FixedHeightmap::deSerialize(u8 *source, u8 version)
387 /*dstream<<"FixedHeightmap::deSerialize m_blocksize="
388 <<m_blocksize<<std::endl;*/
390 if(!ser_ver_supported(version))
391 throw VersionMismatchException("ERROR: FixedHeightmap format not supported");
395 u32 nodecount = (m_blocksize+1)*(m_blocksize+1);
396 for(u32 i=0; i<nodecount; i++)
398 m_data[i] = ((f32)readS32(&source[i*4]))/1000.0;
401 /*printf("source[0,1,2,3]=%x,%x,%x,%x\n",
405 (int)source[3]&0xff);
407 dstream<<"m_data[0]="<<m_data[0]<<", "
408 <<"readS32(&source[0])="<<readS32(&source[0])
410 dstream<<"m_data[4*4]="<<m_data[4*4]<<", "
411 <<"readS32(&source[4*4])="<<readS32(&source[4*4])
417 void setcolor(f32 h, f32 rangemin, f32 rangemax)
420 const char *colors[] =
429 u16 colorcount = sizeof(colors)/sizeof(colors[0]);
430 f32 scaled = (h - rangemin) / (rangemax - rangemin);
431 u8 color = scaled * colorcount;
432 if(color > colorcount-1)
433 color = colorcount-1;
434 /*printf("rangemin=%f, rangemax=%f, h=%f -> color=%i\n",
439 printf("%s", colors[color]);
440 //printf("\x1b[31;40m");
441 //printf("\x1b[44;1m");
455 void UnlimitedHeightmap::print()
461 core::map<v2s16, FixedHeightmap*>::Iterator i;
462 i = m_heightmaps.getIterator();
464 printf("UnlimitedHeightmap::print(): empty.\n");
467 for(; i.atEnd() == false; i++)
469 v2s16 p = i.getNode()->getValue()->getPosOnMaster();
470 if(p.X < minx) minx = p.X;
471 if(p.Y < miny) miny = p.Y;
472 if(p.X > maxx) maxx = p.X;
473 if(p.Y > maxy) maxy = p.Y;
475 minx = minx * m_blocksize;
476 miny = miny * m_blocksize;
477 maxx = (maxx+1) * m_blocksize;
478 maxy = (maxy+1) * m_blocksize;
479 printf("UnlimitedHeightmap::print(): from (%i,%i) to (%i,%i)\n",
480 minx, miny, maxx, maxy);
484 f32 rangemax = -1e10;
485 for(s32 y=miny; y<=maxy; y++){
486 for(s32 x=minx; x<=maxx; x++){
487 f32 h = getGroundHeight(v2s16(x,y), false);
488 if(h < GROUNDHEIGHT_VALID_MINVALUE)
498 for(s32 x=minx; x<=maxx; x++){
503 for(s32 y=miny; y<=maxy; y++){
505 for(s32 x=minx; x<=maxx; x++){
506 f32 n = getGroundHeight(v2s16(x,y), false);
507 if(n < GROUNDHEIGHT_VALID_MINVALUE)
511 setcolor(n, rangemin, rangemax);
512 printf("% -5.1f", getGroundHeight(v2s16(x,y), false));
520 FixedHeightmap * UnlimitedHeightmap::getHeightmap(v2s16 p_from, bool generate)
522 DSTACK("UnlimitedHeightmap::getHeightmap()");
524 We want to check that all neighbours of the wanted heightmap
526 This is because generating the neighboring heightmaps will
527 modify the current one.
532 // Go through all neighbors (corners also) and the current one
533 // and generate every one of them.
534 for(s16 x=p_from.X-1; x<=p_from.X+1; x++)
535 for(s16 y=p_from.Y-1; y<=p_from.Y+1; y++)
540 core::map<v2s16, FixedHeightmap*>::Node *n = m_heightmaps.find(p);
547 FixedHeightmap *heightmap = new FixedHeightmap(this, p, m_blocksize);
549 m_heightmaps.insert(p, heightmap);
555 //TODO: palist must be taken into account in generateContinued.
556 // It is almost useless in here.
558 Settings *attr = m_palist->getNearAttr(p / div);
560 corners[0] = attr->getFloat("baseheight");
561 corners[1] = attr->getFloat("baseheight");
562 corners[2] = attr->getFloat("baseheight");
563 corners[3] = attr->getFloat("baseheight");
567 corners[0] = m_base_generator->getValue(p+v2s16(0,0));
568 corners[1] = m_base_generator->getValue(p+v2s16(1,0));
569 corners[2] = m_base_generator->getValue(p+v2s16(1,1));
570 corners[3] = m_base_generator->getValue(p+v2s16(0,1));
573 f32 randmax = m_randmax_generator->getValue(p);
574 f32 randfactor = m_randfactor_generator->getValue(p);
576 heightmap->generateContinued(randmax, randfactor, corners);
580 core::map<v2s16, FixedHeightmap*>::Node *n = m_heightmaps.find(p_from);
584 return n->getValue();
588 throw InvalidPositionException
589 ("Something went really wrong in UnlimitedHeightmap::getHeightmap");
593 f32 UnlimitedHeightmap::getGroundHeight(v2s16 p, bool generate)
595 v2s16 heightmappos = getNodeHeightmapPos(p);
596 v2s16 relpos = p - heightmappos*m_blocksize;
598 FixedHeightmap * href = getHeightmap(heightmappos, generate);
599 f32 h = href->getGroundHeight(relpos);
600 if(h > GROUNDHEIGHT_VALID_MINVALUE)
603 catch(InvalidPositionException){}
605 If on border or in the (0,0) corner, try to get from
606 overlapping heightmaps
610 FixedHeightmap * href = getHeightmap(
611 heightmappos-v2s16(1,0), false);
612 f32 h = href->getGroundHeight(v2s16(m_blocksize, relpos.Y));
613 if(h > GROUNDHEIGHT_VALID_MINVALUE)
616 catch(InvalidPositionException){}
620 FixedHeightmap * href = getHeightmap(
621 heightmappos-v2s16(0,1), false);
622 f32 h = href->getGroundHeight(v2s16(relpos.X, m_blocksize));
623 if(h > GROUNDHEIGHT_VALID_MINVALUE)
626 catch(InvalidPositionException){}
628 if(relpos.X == 0 && relpos.Y == 0){
630 FixedHeightmap * href = getHeightmap(
631 heightmappos-v2s16(1,1), false);
632 f32 h = href->getGroundHeight(v2s16(m_blocksize, m_blocksize));
633 if(h > GROUNDHEIGHT_VALID_MINVALUE)
636 catch(InvalidPositionException){}
638 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
641 void UnlimitedHeightmap::setGroundHeight(v2s16 p, f32 y, bool generate)
643 bool was_set = false;
645 v2s16 heightmappos = getNodeHeightmapPos(p);
646 v2s16 relpos = p - heightmappos*m_blocksize;
647 /*dstream<<"UnlimitedHeightmap::setGroundHeight(("
648 <<p.X<<","<<p.Y<<"), "<<y<<"): "
649 <<"heightmappos=("<<heightmappos.X<<","
650 <<heightmappos.Y<<") relpos=("
651 <<relpos.X<<","<<relpos.Y<<")"
654 FixedHeightmap * href = getHeightmap(heightmappos, generate);
655 href->setGroundHeight(relpos, y);
657 }catch(InvalidPositionException){}
658 // Update in neighbour heightmap if it's at border
661 FixedHeightmap * href = getHeightmap(
662 heightmappos-v2s16(1,0), generate);
663 href->setGroundHeight(v2s16(m_blocksize, relpos.Y), y);
665 }catch(InvalidPositionException){}
669 FixedHeightmap * href = getHeightmap(
670 heightmappos-v2s16(0,1), generate);
671 href->setGroundHeight(v2s16(relpos.X, m_blocksize), y);
673 }catch(InvalidPositionException){}
675 if(relpos.X == 0 && relpos.Y == 0){
677 FixedHeightmap * href = getHeightmap(
678 heightmappos-v2s16(1,1), generate);
679 href->setGroundHeight(v2s16(m_blocksize, m_blocksize), y);
681 }catch(InvalidPositionException){}
686 throw InvalidPositionException
687 ("UnlimitedHeightmap failed to set height");
692 void UnlimitedHeightmap::serialize(std::ostream &os, u8 version)
694 //dstream<<"UnlimitedHeightmap::serialize()"<<std::endl;
696 if(!ser_ver_supported(version))
697 throw VersionMismatchException
698 ("ERROR: UnlimitedHeightmap format not supported");
702 /*if(m_base_generator->getId() != VALUE_GENERATOR_ID_CONSTANT
703 || m_randmax_generator->getId() != VALUE_GENERATOR_ID_CONSTANT
704 || m_randfactor_generator->getId() != VALUE_GENERATOR_ID_CONSTANT)*/
705 if(std::string(m_base_generator->getName()) != "constant"
706 || std::string(m_randmax_generator->getName()) != "constant"
707 || std::string(m_randfactor_generator->getName()) != "constant")
709 throw SerializationError
710 ("Cannot write UnlimitedHeightmap in old version: "
711 "Generators are not ConstantGenerators.");
714 f32 basevalue = ((ConstantGenerator*)m_base_generator)->m_value;
715 f32 randmax = ((ConstantGenerator*)m_randmax_generator)->m_value;
716 f32 randfactor = ((ConstantGenerator*)m_randfactor_generator)->m_value;
719 os.write((char*)&version, 1);
724 [6] s32 randfactor*1000
725 [10] s32 basevalue*1000
726 [14] u32 heightmap_count
727 [18] X * (v2s16 pos + heightmap)
730 FixedHeightmap::serializedLength(version, m_blocksize);
731 u32 heightmap_count = m_heightmaps.size();
733 //dstream<<"heightmap_size="<<heightmap_size<<std::endl;
735 u32 datasize = 2+4+4+4+4+heightmap_count*(4+heightmap_size);
736 SharedBuffer<u8> data(datasize);
738 writeU16(&data[0], m_blocksize);
739 writeU32(&data[2], (s32)(randmax*1000.0));
740 writeU32(&data[6], (s32)(randfactor*1000.0));
741 writeU32(&data[10], (s32)(basevalue*1000.0));
742 writeU32(&data[14], heightmap_count);
744 core::map<v2s16, FixedHeightmap*>::Iterator j;
745 j = m_heightmaps.getIterator();
747 for(; j.atEnd() == false; j++)
749 FixedHeightmap *hm = j.getNode()->getValue();
750 v2s16 pos = j.getNode()->getKey();
751 writeV2S16(&data[18+i*(4+heightmap_size)], pos);
752 hm->serialize(&data[18+i*(4+heightmap_size)+4], version);
756 os.write((char*)*data, data.getSize());
761 os.write((char*)&version, 1);
765 writeU16(buf, m_blocksize);
766 os.write((char*)buf, 2);
768 /*m_randmax_generator->serialize(os, version);
769 m_randfactor_generator->serialize(os, version);
770 m_base_generator->serialize(os, version);*/
771 m_randmax_generator->serialize(os);
772 m_randfactor_generator->serialize(os);
773 m_base_generator->serialize(os);
775 u32 heightmap_count = m_heightmaps.size();
776 writeU32(buf, heightmap_count);
777 os.write((char*)buf, 4);
780 FixedHeightmap::serializedLength(version, m_blocksize);
782 SharedBuffer<u8> hmdata(heightmap_size);
784 core::map<v2s16, FixedHeightmap*>::Iterator j;
785 j = m_heightmaps.getIterator();
787 for(; j.atEnd() == false; j++)
789 v2s16 pos = j.getNode()->getKey();
790 writeV2S16(buf, pos);
791 os.write((char*)buf, 4);
793 FixedHeightmap *hm = j.getNode()->getValue();
794 hm->serialize(*hmdata, version);
795 os.write((char*)*hmdata, hmdata.getSize());
802 UnlimitedHeightmap * UnlimitedHeightmap::deSerialize(std::istream &is)
805 is.read((char*)&version, 1);
807 if(!ser_ver_supported(version))
808 throw VersionMismatchException("ERROR: UnlimitedHeightmap format not supported");
815 [6] s32 randfactor*1000
816 [10] s32 basevalue*1000
817 [14] u32 heightmap_count
818 [18] X * (v2s16 pos + heightmap)
820 SharedBuffer<u8> data(18);
821 is.read((char*)*data, 18);
822 if(is.gcount() != 18)
823 throw SerializationError
824 ("UnlimitedHeightmap::deSerialize: no enough input data");
825 s16 blocksize = readU16(&data[0]);
826 f32 randmax = (f32)readU32(&data[2]) / 1000.0;
827 f32 randfactor = (f32)readU32(&data[6]) / 1000.0;
828 f32 basevalue = (f32)readU32(&data[10]) / 1000.0;
829 u32 heightmap_count = readU32(&data[14]);
831 /*dstream<<"UnlimitedHeightmap::deSerialize():"
832 <<" blocksize="<<blocksize
833 <<" heightmap_count="<<heightmap_count
837 FixedHeightmap::serializedLength(version, blocksize);
839 //dstream<<"heightmap_size="<<heightmap_size<<std::endl;
841 ValueGenerator *maxgen = new ConstantGenerator(randmax);
842 ValueGenerator *factorgen = new ConstantGenerator(randfactor);
843 ValueGenerator *basegen = new ConstantGenerator(basevalue);
845 UnlimitedHeightmap *hm = new UnlimitedHeightmap
846 (blocksize, maxgen, factorgen, basegen, NULL);
848 for(u32 i=0; i<heightmap_count; i++)
850 //dstream<<"i="<<i<<std::endl;
851 SharedBuffer<u8> data(4+heightmap_size);
852 is.read((char*)*data, 4+heightmap_size);
853 if(is.gcount() != (s32)(4+heightmap_size)){
855 throw SerializationError
856 ("UnlimitedHeightmap::deSerialize: no enough input data");
858 v2s16 pos = readV2S16(&data[0]);
859 FixedHeightmap *f = new FixedHeightmap(hm, pos, blocksize);
860 f->deSerialize(&data[4], version);
861 hm->m_heightmaps.insert(pos, f);
869 is.read((char*)buf, 2);
870 s16 blocksize = readU16(buf);
872 ValueGenerator *maxgen = ValueGenerator::deSerialize(is);
873 ValueGenerator *factorgen = ValueGenerator::deSerialize(is);
874 ValueGenerator *basegen = ValueGenerator::deSerialize(is);
876 is.read((char*)buf, 4);
877 u32 heightmap_count = readU32(buf);
880 FixedHeightmap::serializedLength(version, blocksize);
882 UnlimitedHeightmap *hm = new UnlimitedHeightmap
883 (blocksize, maxgen, factorgen, basegen, NULL);
885 for(u32 i=0; i<heightmap_count; i++)
887 is.read((char*)buf, 4);
888 v2s16 pos = readV2S16(buf);
890 SharedBuffer<u8> data(heightmap_size);
891 is.read((char*)*data, heightmap_size);
892 if(is.gcount() != (s32)(heightmap_size)){
894 throw SerializationError
895 ("UnlimitedHeightmap::deSerialize: no enough input data");
897 FixedHeightmap *f = new FixedHeightmap(hm, pos, blocksize);
898 f->deSerialize(*data, version);
899 hm->m_heightmaps.insert(pos, f);