From 4e249fb3fbf75f0359758760d88e22aa5b14533c Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 27 Nov 2010 01:02:21 +0200 Subject: Initial files --- src/heightmap.h | 556 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 556 insertions(+) create mode 100644 src/heightmap.h (limited to 'src/heightmap.h') diff --git a/src/heightmap.h b/src/heightmap.h new file mode 100644 index 000000000..a5da092aa --- /dev/null +++ b/src/heightmap.h @@ -0,0 +1,556 @@ +/* +(c) 2010 Perttu Ahola +*/ + +#ifndef HEIGHTMAP_HEADER +#define HEIGHTMAP_HEADER + +#include +#include +#include + +#include "debug.h" +#include "common_irrlicht.h" +#include "exceptions.h" +#include "utility.h" +#include "serialization.h" + +#define GROUNDHEIGHT_NOTFOUND_SETVALUE (-10e6) +#define GROUNDHEIGHT_VALID_MINVALUE ( -9e6) + +class Heightmappish +{ +public: + virtual f32 getGroundHeight(v2s16 p, bool generate=true) = 0; + virtual void setGroundHeight(v2s16 p, f32 y, bool generate=true) = 0; + + v2f32 getSlope(v2s16 p) + { + f32 y0 = getGroundHeight(p, false); + + v2s16 dirs[] = { + v2s16(1,0), + v2s16(0,1), + }; + + v2f32 fdirs[] = { + v2f32(1,0), + v2f32(0,1), + }; + + v2f32 slopevector(0.0, 0.0); + + for(u16 i=0; i<2; i++){ + f32 y1 = 0.0; + f32 y2 = 0.0; + f32 count = 0.0; + + v2s16 p1 = p - dirs[i]; + y1 = getGroundHeight(p1, false); + if(y1 > GROUNDHEIGHT_VALID_MINVALUE){ + y1 -= y0; + count += 1.0; + } + else + y1 = 0; + + v2s16 p2 = p + dirs[i]; + y2 = getGroundHeight(p2, false); + if(y2 > GROUNDHEIGHT_VALID_MINVALUE){ + y2 -= y0; + count += 1.0; + } + else + y2 = 0; + + if(count < 0.001) + return v2f32(0.0, 0.0); + + /* + If y2 is higher than y1, slope is positive + */ + f32 slope = (y2 - y1)/count; + + slopevector += fdirs[i] * slope; + } + + return slopevector; + } + +}; + +// TODO: Get rid of this dummy wrapper +class Heightmap : public Heightmappish /*, public ReferenceCounted*/ +{ +}; + +class WrapperHeightmap : public Heightmap +{ + Heightmappish *m_target; +public: + + WrapperHeightmap(Heightmappish *target): + m_target(target) + { + if(target == NULL) + throw NullPointerException(); + } + + f32 getGroundHeight(v2s16 p, bool generate=true) + { + return m_target->getGroundHeight(p, generate); + } + void setGroundHeight(v2s16 p, f32 y, bool generate=true) + { + m_target->setGroundHeight(p, y, generate); + } +}; + +/* + Base class that defines a generator that gives out values at + positions in 2-dimensional space. + Can be given to UnlimitedHeightmap to feed stuff. + + These are always serialized as readable text ending in "\n" +*/ +class ValueGenerator +{ +public: + ValueGenerator(){} + virtual ~ValueGenerator(){} + + static ValueGenerator* deSerialize(std::string line); + + static ValueGenerator* deSerialize(std::istream &is) + { + std::string line; + std::getline(is, line, '\n'); + return deSerialize(line); + } + + void serializeBase(std::ostream &os) + { + os<= W || p.Y < 0 || p.Y >= H); + } + + bool atborder(v2s16 p) + { + if(overborder(p)) + return false; + return (p.X == 0 || p.X == W-1 || p.Y == 0 || p.Y == H-1); + } + + void setGroundHeight(v2s16 p, f32 y, bool generate=false) + { + /*dstream<<"FixedHeightmap::setGroundHeight((" + <setGroundHeight(nodepos_master, y, false);*/ + + // Try to set on master + bool master_got_it = false; + if(overborder(p) || atborder(p)) + { + try{ + // Position on master + v2s16 blockpos_nodes = m_pos_on_master * m_blocksize; + v2s16 nodepos_master = blockpos_nodes + p; + m_master->setGroundHeight(nodepos_master, y, false); + + master_got_it = true; + } + catch(InvalidPositionException &e) + { + } + } + + if(overborder(p)) + return master_got_it; + + setGroundHeight(p, y); + + return true; + } + + f32 getGroundHeight(v2s16 p, bool generate=false) + { + if(overborder(p)) + return GROUNDHEIGHT_NOTFOUND_SETVALUE; + return m_data[p.Y*W + p.X]; + } + + f32 getGroundHeightParent(v2s16 p) + { + /*v2s16 blockpos_nodes = m_pos_on_master * m_blocksize; + return m_master->getGroundHeight(blockpos_nodes + p, false);*/ + + if(overborder(p) == false){ + f32 h = getGroundHeight(p); + if(h > GROUNDHEIGHT_VALID_MINVALUE) + return h; + } + + // Position on master + v2s16 blockpos_nodes = m_pos_on_master * m_blocksize; + f32 h = m_master->getGroundHeight(blockpos_nodes + p, false); + return h; + } + + f32 avgNeighbours(v2s16 p, s16 d); + + f32 avgDiagNeighbours(v2s16 p, s16 d); + + void makeDiamond( + v2s16 center, + s16 a, + f32 randmax, + core::map &next_squares); + + void makeSquare( + v2s16 center, + s16 a, + f32 randmax, + core::map &next_diamonds); + + void DiamondSquare(f32 randmax, f32 randfactor); + + /* + corners: [i]=XY: [0]=00, [1]=10, [2]=11, [3]=10 + */ + void generateContinued(f32 randmax, f32 randfactor, f32 *corners); + + + static u32 serializedLength(u8 version, u16 blocksize); + u32 serializedLength(u8 version); + void serialize(u8 *dest, u8 version); + void deSerialize(u8 *source, u8 version); + /*static FixedHeightmap * deSerialize(u8 *source, u32 size, + u32 &usedsize, Heightmap *master, u8 version);*/ +}; + +class OneChildHeightmap : public Heightmap +{ + s16 m_blocksize; + +public: + + FixedHeightmap m_child; + + OneChildHeightmap(s16 blocksize): + m_blocksize(blocksize), + m_child(this, v2s16(0,0), blocksize) + { + } + + f32 getGroundHeight(v2s16 p, bool generate=true) + { + if(p.X < 0 || p.X > m_blocksize + || p.Y < 0 || p.Y > m_blocksize) + return GROUNDHEIGHT_NOTFOUND_SETVALUE; + return m_child.getGroundHeight(p); + } + void setGroundHeight(v2s16 p, f32 y, bool generate=true) + { + //dstream<<"OneChildHeightmap::setGroundHeight()"< m_blocksize + || p.Y < 0 || p.Y > m_blocksize) + throw InvalidPositionException(); + m_child.setGroundHeight(p, y); + } +}; + + +/* + This is a dynamic container of an arbitrary number of heightmaps + at arbitrary positions. + + It is able to redirect queries to the corresponding heightmaps and + it generates new heightmaps on-the-fly according to the relevant + parameters. + + It doesn't have a master heightmap because it is meant to be used + as such itself. + + Child heightmaps are spaced at m_blocksize distances, and are of + size (m_blocksize+1)*(m_blocksize+1) + + This is used as the master heightmap of a Map object. +*/ +class UnlimitedHeightmap: public Heightmap +{ +private: + + core::map m_heightmaps; + s16 m_blocksize; + + ValueGenerator *m_randmax_generator; + ValueGenerator *m_randfactor_generator; + ValueGenerator *m_base_generator; + +public: + + UnlimitedHeightmap( + s16 blocksize, + ValueGenerator *randmax_generator, + ValueGenerator *randfactor_generator, + ValueGenerator *base_generator + ): + m_blocksize(blocksize), + m_randmax_generator(randmax_generator), + m_randfactor_generator(randfactor_generator), + m_base_generator(base_generator) + { + assert(m_randmax_generator != NULL); + assert(m_randfactor_generator != NULL); + assert(m_base_generator != NULL); + } + + ~UnlimitedHeightmap() + { + core::map::Iterator i; + i = m_heightmaps.getIterator(); + for(; i.atEnd() == false; i++) + { + delete i.getNode()->getValue(); + } + + delete m_randmax_generator; + delete m_randfactor_generator; + delete m_base_generator; + } + + /*void setParams(f32 randmax, f32 randfactor) + { + m_randmax = randmax; + m_randfactor = randfactor; + }*/ + + void print(); + + v2s16 getNodeHeightmapPos(v2s16 p) + { + return v2s16( + (p.X>=0 ? p.X : p.X-m_blocksize+1) / m_blocksize, + (p.Y>=0 ? p.Y : p.Y-m_blocksize+1) / m_blocksize); + } + + // Can throw an InvalidPositionException + FixedHeightmap * getHeightmap(v2s16 p, bool generate=true); + + f32 getGroundHeight(v2s16 p, bool generate=true); + void setGroundHeight(v2s16 p, f32 y, bool generate=true); + + /*static UnlimitedHeightmap * deSerialize(u8 *source, u32 maxsize, + u32 &usedsize, u8 version);*/ + + //SharedBuffer serialize(u8 version); + void serialize(std::ostream &os, u8 version); + static UnlimitedHeightmap * deSerialize(std::istream &istr); +}; + +#endif + -- cgit v1.2.3