diff --git a/source/tools/rmgen/smoothelevationpainter.cpp b/source/tools/rmgen/smoothelevationpainter.cpp new file mode 100644 index 0000000000..2d2dabebb3 --- /dev/null +++ b/source/tools/rmgen/smoothelevationpainter.cpp @@ -0,0 +1,153 @@ +#include "stdafx.h" +#include "rmgen.h" +#include "smoothelevationpainter.h" + +using namespace std; + +SmoothElevationPainter::SmoothElevationPainter(int t, float e, int b) +{ + type = t; + elevation = e; + blendRadius = b; + if(type!=SET && type!=MODIFY) { + JS_ReportError(cx, "SmoothElevationPainter: type must be either SET or MODIFY"); + } +} + +SmoothElevationPainter::~SmoothElevationPainter(void) +{ +} + +bool SmoothElevationPainter::checkInArea(Map* m, Area* a, int x, int y) { + if(m->validT(x, y)) { + return m->area[x][y] == a; + } + else { + return false; + } +} + +void SmoothElevationPainter::paint(Map* m, Area* a) { + map saw; + map dist; + + queue q; + + vector& pts = a->points; + + set heightPts; + map newHeight; + + // get a list of all points + for(int i=0; ivalidH(nx, ny)) { + heightPts.insert(np); + newHeight[np] = m->height[nx][ny]; + } + } + } + } + + // push edge points + for(int i=0; ivalidH(nx, ny) + && !checkInArea(m, a, nx, ny) + && !checkInArea(m, a, nx-1, ny) + && !checkInArea(m, a, nx, ny-1) + && !checkInArea(m, a, nx-1, ny-1) + && !saw[np]) { + saw[np] = 1; + dist[np] = 0; + q.push(np); + } + } + } + } + + // do BFS inwards to find distances to edge + while(!q.empty()) { + Point p = q.front(); + q.pop(); + + int d = dist[p]; + + // paint if in area + if(m->validH(p.x, p.y) + && (checkInArea(m, a, p.x, p.y) || checkInArea(m, a, p.x-1, p.y) + || checkInArea(m, a, p.x, p.y-1) || checkInArea(m, a, p.x-1, p.y-1))) { + if(d <= blendRadius) { + float a = ((float)(d-1)) / blendRadius; + if(type == SET) { + newHeight[p] = a*elevation + (1-a)*m->height[p.x][p.y]; + } + else { // type == MODIFY + newHeight[p] += a*elevation; + } + } + else { // also happens when blendRadius == 0 + if(type == SET) { + newHeight[p] = elevation; + } + else { // type == MODIFY + newHeight[p] += elevation; + } + } + } + + // enqueue neighbours + for(int dx=-1; dx<=1; dx++) { + for(int dy=-1; dy<=1; dy++) { + int nx = p.x+dx, ny = p.y+dy; + Point np(nx, ny); + if(m->validH(nx, ny) + && (checkInArea(m, a, nx, ny) || checkInArea(m, a, nx-1, ny) + || checkInArea(m, a, nx, ny-1) || checkInArea(m, a, nx-1, ny-1)) + && !saw[np]) { + saw[np] = 1; + dist[np] = d+1; + q.push(np); + } + } + } + } + + // smooth everything out + for(set::iterator it = heightPts.begin(); it != heightPts.end(); it++) { + Point p = *it; + int x = p.x, y = p.y; + if((checkInArea(m, a, x, y) || checkInArea(m, a, x-1, y) + || checkInArea(m, a, x, y-1) || checkInArea(m, a, x-1, y-1))) { + float sum = 8 * newHeight[p]; + int count = 8; + for(int dx=-1; dx<=1; dx++) { + for(int dy=-1; dy<=1; dy++) { + int nx = x+dx, ny = y+dy; + if(m->validH(nx, ny)) { + sum += m->height[nx][ny]; + count++; + } + } + } + m->height[x][y] = sum/count; + } + } + // don't smooth + /* + for(int i=0; iheight[x][y] = newHeight[p]; + } + */ +} \ No newline at end of file diff --git a/source/tools/rmgen/smoothelevationpainter.h b/source/tools/rmgen/smoothelevationpainter.h new file mode 100644 index 0000000000..effc38790b --- /dev/null +++ b/source/tools/rmgen/smoothelevationpainter.h @@ -0,0 +1,29 @@ +#ifndef __SMOOTHELEVATIONPAINTER_H__ +#define __SMOOTHELEVATIONPAINTER_H__ + +#include "areapainter.h" +#include "terrain.h" +#include "map.h" +#include "area.h" + +class SmoothElevationPainter : + public AreaPainter +{ +public: + static const int SET = 0, MODIFY = 1; + +private: + int type; // one of the constants above + float elevation; // target or delta + int blendRadius; // how many tiles to do blending for + + bool checkInArea(Map* m, Area* a, int x, int y); + +public: + SmoothElevationPainter(int type, float elevation, int blendRadius); + ~SmoothElevationPainter(void); + + virtual void paint(Map* m, Area* a); +}; + +#endif \ No newline at end of file