/* (c) 2010 Perttu Ahola */ #include "heightmap.h" bool g_heightmap_debugprint = false; f32 FixedHeightmap::avgNeighbours(v2s16 p, s16 d) { //printf("avgNeighbours((%i,%i), %i): ", p.X, p.Y, d); v2s16 dirs[4] = { v2s16(1,0), v2s16(0,1), v2s16(-1,0), v2s16(0,-1) }; f32 sum = 0.0; f32 count = 0.0; for(u16 i=0; i<4; i++){ v2s16 p2 = p + dirs[i] * d; f32 n = getGroundHeightParent(p2); if(n < GROUNDHEIGHT_VALID_MINVALUE) continue; sum += n; count += 1.0; //printf("(%i,%i)=%f ", p2.X, p2.Y, n); } //printf("\n"); assert(count > 0.001); return sum / count; } f32 FixedHeightmap::avgDiagNeighbours(v2s16 p, s16 d) { /*printf("avgDiagNeighbours((%i,%i), %i): ", p.X, p.Y, d);*/ v2s16 dirs[4] = { v2s16(1,1), v2s16(-1,-1), v2s16(-1,1), v2s16(1,-1) }; f32 sum = 0.0; f32 count = 0.0; for(u16 i=0; i<4; i++){ v2s16 p2 = p + dirs[i] * d; f32 n = getGroundHeightParent(p2); if(n < GROUNDHEIGHT_VALID_MINVALUE) continue; sum += n; count += 1.0; //printf("(%i,%i)=%f ", p2.X, p2.Y, n); } //printf("\n"); assert(count > 0.001); return sum / count; } /* Adds a point to transform into a diamond pattern a = 2, 4, 8, 16, ... */ void FixedHeightmap::makeDiamond(v2s16 center, s16 a, f32 randmax) { f32 n = avgDiagNeighbours(center, a/2); // Add (-1.0...1.0) * randmax n += ((float)rand() / (float)(RAND_MAX/2) - 1.0)*randmax; setGroundHeightParent(center, n); } /* Adds points to transform into a diamond pattern a = 2, 4, 8, 16, ... */ void FixedHeightmap::makeDiamonds(s16 a, f32 randmax) { s16 count_y = (H-1) / a; s16 count_x = (W-1) / a; for(s32 yi=0; yi= count_y - 1) break; // odd rows count_x = (W-1) / a + 1; for(s32 xi=0; xi= 2) { makeDiamonds(a, randmax); if(HEIGHTMAP_DEBUGPRINT){ printf("MakeDiamonds a=%i result:\n", a); print(); } makeSquares(a, randmax); if(HEIGHTMAP_DEBUGPRINT){ printf("MakeSquares a=%i result:\n", a); print(); } a /= 2; randmax *= randfactor; } } void UnlimitedHeightmap::print() { s16 minx = 10000; s16 miny = 10000; s16 maxx = -10000; s16 maxy = -10000; core::map::Iterator i; i = m_heightmaps.getIterator(); if(i.atEnd()){ printf("UnlimitedHeightmap::print(): empty.\n"); return; } for(; i.atEnd() == false; i++) { v2s16 p = i.getNode()->getValue()->getPosOnMaster(); if(p.X < minx) minx = p.X; if(p.Y < miny) miny = p.Y; if(p.X > maxx) maxx = p.X; if(p.Y > maxy) maxy = p.Y; } minx = minx * m_blocksize; miny = miny * m_blocksize; maxx = (maxx+1) * m_blocksize; maxy = (maxy+1) * m_blocksize; printf("UnlimitedHeightmap::print(): from (%i,%i) to (%i,%i)\n", minx, miny, maxx, maxy); for(s32 y=miny; y<=maxy; y++){ for(s32 x=minx; x<=maxx; x++){ f32 n = getGroundHeight(v2s16(x,y), false); if(n < GROUNDHEIGHT_VALID_MINVALUE) printf(" - "); else printf("% -5.1f ", getGroundHeight(v2s16(x,y), false)); } printf("\n"); } } FixedHeightmap * UnlimitedHeightmap::getHeightmap(v2s16 p, bool generate) { core::map::Node *n = m_heightmaps.find(p); if(n != NULL) { return n->getValue(); } /*std::cout<<"UnlimitedHeightmap::getHeightmap((" <generateContinued(m_randmax, m_randfactor, corners); return heightmap; } f32 UnlimitedHeightmap::getGroundHeight(v2s16 p, bool generate) { v2s16 heightmappos = getNodeHeightmapPos(p); v2s16 relpos = p - heightmappos*m_blocksize; try{ FixedHeightmap * href = getHeightmap(heightmappos, generate); f32 h = href->getGroundHeight(relpos); if(h > GROUNDHEIGHT_VALID_MINVALUE) return h; } catch(InvalidPositionException){} /* OK, wasn't there. Mercilessly try to get it somewhere. */ #if 1 if(relpos.X == 0){ try{ FixedHeightmap * href = getHeightmap( heightmappos-v2s16(1,0), false); f32 h = href->getGroundHeight(v2s16(m_blocksize, relpos.Y)); if(h > GROUNDHEIGHT_VALID_MINVALUE) return h; } catch(InvalidPositionException){} } if(relpos.Y == 0){ try{ FixedHeightmap * href = getHeightmap( heightmappos-v2s16(0,1), false); f32 h = href->getGroundHeight(v2s16(relpos.X, m_blocksize)); if(h > GROUNDHEIGHT_VALID_MINVALUE) return h; } catch(InvalidPositionException){} } if(relpos.X == 0 && relpos.Y == 0){ try{ FixedHeightmap * href = getHeightmap( heightmappos-v2s16(1,1), false); f32 h = href->getGroundHeight(v2s16(m_blocksize, m_blocksize)); if(h > GROUNDHEIGHT_VALID_MINVALUE) return h; } catch(InvalidPositionException){} } #endif return GROUNDHEIGHT_NOTFOUND_SETVALUE; } void UnlimitedHeightmap::setGroundHeight(v2s16 p, f32 y, bool generate) { v2s16 heightmappos = getNodeHeightmapPos(p); v2s16 relpos = p - heightmappos*m_blocksize; /*std::cout<<"UnlimitedHeightmap::setGroundHeight((" <setGroundHeight(relpos, y); }catch(InvalidPositionException){} // Update in neighbour heightmap if it's at border if(relpos.X == 0){ try{ FixedHeightmap * href = getHeightmap( heightmappos-v2s16(1,0), generate); href->setGroundHeight(v2s16(m_blocksize, relpos.Y), y); }catch(InvalidPositionException){} } if(relpos.Y == 0){ try{ FixedHeightmap * href = getHeightmap( heightmappos-v2s16(0,1), generate); href->setGroundHeight(v2s16(relpos.X, m_blocksize), y); }catch(InvalidPositionException){} } if(relpos.X == m_blocksize && relpos.Y == m_blocksize){ try{ FixedHeightmap * href = getHeightmap( heightmappos-v2s16(1,1), generate); href->setGroundHeight(v2s16(m_blocksize, m_blocksize), y); }catch(InvalidPositionException){} } } void FixedHeightmap::generateContinued(f32 randmax, f32 randfactor, f32 *corners) { if(HEIGHTMAP_DEBUGPRINT){ std::cout<<"FixedHeightmap("<getGroundHeight(npos, false); //std::cout<<"h="< GROUNDHEIGHT_VALID_MINVALUE) continue; setGroundHeight(dirs[i] * a, corners[i]); } if(HEIGHTMAP_DEBUGPRINT){ std::cout<<"corners filled:"<