2006-04-24 01:14:18 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "rmgen.h"
|
|
|
|
#include "smoothelevationpainter.h"
|
|
|
|
#include "pointmap.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) {
|
|
|
|
// TODO: Use a 2D array instead of STL maps and sets for speed
|
|
|
|
|
|
|
|
PointMap<int> saw;
|
|
|
|
PointMap<int> dist;
|
|
|
|
queue<Point> q;
|
|
|
|
vector<Point>& pts = a->points;
|
|
|
|
vector<Point> heightPts;
|
|
|
|
PointMap<int> gotHeightPt;
|
|
|
|
PointMap<float> newHeight;
|
|
|
|
|
|
|
|
// get a list of all points
|
|
|
|
for(int i=0; i<pts.size(); i++) {
|
|
|
|
int x = pts[i].x, y = pts[i].y;
|
|
|
|
for(int dx=-1; dx<=2; dx++) {
|
|
|
|
for(int dy=-1; dy<=2; dy++) {
|
|
|
|
int nx = x+dx, ny = y+dy;
|
|
|
|
Point np(nx, ny);
|
|
|
|
if(m->validH(nx, ny) && !gotHeightPt[np]) {
|
|
|
|
gotHeightPt[np] = 1;
|
|
|
|
heightPts.push_back(np);
|
|
|
|
newHeight[np] = m->height[nx][ny];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// push edge points
|
|
|
|
for(int i=0; i<pts.size(); i++) {
|
|
|
|
int x = pts[i].x, y = pts[i].y;
|
|
|
|
for(int dx=-1; dx<=2; dx++) {
|
|
|
|
for(int dy=-1; dy<=2; dy++) {
|
|
|
|
int nx = x+dx, ny = 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] = 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(vector<Point>::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 += newHeight[Point(nx,ny)];//m->height[nx][ny];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m->height[x][y] = sum/count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// don't smooth
|
|
|
|
/*
|
|
|
|
for(int i=0; i<heightPts.size(); i++) {
|
|
|
|
int x = heightPts[i].x, y = heightPts[i].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))) {
|
|
|
|
m->height[x][y] = newHeight[p];
|
|
|
|
}
|
|
|
|
*/
|
2005-07-23 09:53:21 +02:00
|
|
|
}
|