1
0
forked from 0ad/0ad

Added tile class and "avoid at distance" support to RMGen.

This was SVN commit r2659.
This commit is contained in:
Matei 2005-09-03 21:53:07 +00:00
parent 436de9b0ff
commit b071585610
18 changed files with 339 additions and 64 deletions

View File

@ -27,13 +27,10 @@ JSFunctionSpec globalFunctions[] = {
{"placeObject", placeObject, 5},
{"createArea", createArea, 3},
{"createObjectGroup", createObjectGroup, 2},
{"createTileClass", createTileClass, 0},
{0, 0, 0}
};
// Some global variables used for the API
map<Area*, int> areaToId;
vector<Area*> areas;
// Helper function to validate argument types; the types string can contain the following:
// i (integers), s (strings), n (numbers), . (anything); for example ValidateArgs("iin",...)
// would check that arguments 1 and 2 are integers while the third is a number.
@ -279,10 +276,7 @@ JSBool createArea(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *
*rval = INT_TO_JSVAL(0);
}
else {
areas.push_back(area);
int id = areas.size();
areaToId[area] = id;
*rval = INT_TO_JSVAL(id);
*rval = INT_TO_JSVAL(theMap->areas.size());
}
return JS_TRUE;
}
@ -309,16 +303,24 @@ JSBool createObjectGroup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
constr = new NullConstraint();
}
vector<Object*>* ret = theMap->createObjectGroup(placer, constr);
bool ret = theMap->createObjectGroup(placer, constr);
delete placer;
delete constr;
if(!ret) {
*rval = INT_TO_JSVAL(0);
}
else {
*rval = INT_TO_JSVAL(1);
}
*rval = ret;
return JS_TRUE;
}
JSBool createTileClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
CheckInit(true, cx, __FUNCTION__);
if(argc != 0) {
JS_ReportError(cx, "createTileClass: expected 0 arguments but got %d", argc);
}
int id = theMap->createTileClass();
*rval = INT_TO_JSVAL(id);
return JS_TRUE;
}

View File

@ -30,4 +30,7 @@ JSBool placeObject(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
JSBool createArea(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
JSBool createObjectGroup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
// Tile class functions
JSBool createTileClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
#endif

View File

@ -11,6 +11,20 @@
using namespace std;
bool GetTileClassField(JSContext* cx, jsval obj, const char* name, TileClass*& ret) {
jsval val;
if(!GetJsvalField(cx, obj, name, val)) return false;
if(JSVAL_IS_NULL(val)) {
ret = 0;
return true;
}
if(!JSVAL_IS_INT(val)) return false;
int id = JSVAL_TO_INT(val);
if(id < 0 || id > theMap->tileClasses.size()) return false;
ret = (id==0? 0 : theMap->tileClasses[id-1]);
return true;
}
int GetType(JSContext* cx, jsval val) {
int ret;
if(!GetIntField(cx, val, "TYPE", ret)) return 0;
@ -87,6 +101,7 @@ AreaPainter* ParseAreaPainter(JSContext* cx, jsval val) {
float elevation;
int type;
int blendRadius;
TileClass* tileClass;
vector<Terrain*> terrains;
vector<int> widths;
@ -111,6 +126,10 @@ AreaPainter* ParseAreaPainter(JSContext* cx, jsval val) {
if(!GetFloatField(cx, val, "elevation", elevation)) return 0;
return new ElevationPainter(elevation);
case TYPE_TILE_CLASS_PAINTER:
if(!GetTileClassField(cx, val, "tileClass", tileClass)) return 0;
return new TileClassPainter(tileClass);
case TYPE_SMOOTH_ELEVATION_PAINTER:
if(!GetIntField(cx, val, "type", type)) return 0;
if(!GetFloatField(cx, val, "elevation", elevation)) return 0;
@ -168,6 +187,7 @@ ObjectGroupPlacer* ParseObjectGroupPlacer(JSContext* cx, jsval val) {
jsval jsv;
vector<jsval> array;
int x, y;
TileClass* tileClass;
vector<SimpleGroup::Element*> elements;
switch(GetType(cx, val)) {
@ -175,6 +195,7 @@ ObjectGroupPlacer* ParseObjectGroupPlacer(JSContext* cx, jsval val) {
// convert x and y
if(!GetIntField(cx, val, "x", x)) return 0;
if(!GetIntField(cx, val, "y", y)) return 0;
if(!GetTileClassField(cx, val, "tileClass", tileClass)) return 0;
// convert the elements (which will be JS SimpleElement objects)
if(!GetJsvalField(cx, val, "elements", jsv)) return 0;
if(!ParseArray(cx, jsv, array)) return 0;
@ -188,7 +209,7 @@ ObjectGroupPlacer* ParseObjectGroupPlacer(JSContext* cx, jsval val) {
if(!GetFloatField(cx, array[i], "distance", distance)) return 0;
elements[i] = new SimpleGroup::Element(type, count, distance);
}
return new SimpleGroup(elements, x, y);
return new SimpleGroup(elements, tileClass, x, y);
default:
return 0;
@ -198,6 +219,8 @@ ObjectGroupPlacer* ParseObjectGroupPlacer(JSContext* cx, jsval val) {
Constraint* ParseConstraint(JSContext* cx, jsval val) {
vector<jsval> array;
int areaId;
TileClass* tileClass;
float distance;
string texture;
jsval jsv, jsv2;
@ -229,6 +252,11 @@ Constraint* ParseConstraint(JSContext* cx, jsval val) {
if(!GetStringField(cx, val, "texture", texture)) return 0;
return new AvoidTextureConstraint(theMap->getId(texture));
case TYPE_AVOID_TILE_CLASS_CONSTRAINT:
if(!GetFloatField(cx, val, "distance", distance)) return 0;
if(!GetTileClassField(cx, val, "tileClass", tileClass)) return 0;
return new AvoidTileClassConstraint(tileClass, distance);
default:
return 0;
}

View File

@ -20,7 +20,9 @@ const int
TYPE_AVOID_TEXTURE_CONSTRAINT = 7,
TYPE_ELEVATION_PAINTER = 8,
TYPE_SMOOTH_ELEVATION_PAINTER = 9,
TYPE_SIMPLE_GROUP = 10;
TYPE_SIMPLE_GROUP = 10,
TYPE_AVOID_TILE_CLASS_CONSTRAINT = 11,
TYPE_TILE_CLASS_PAINTER = 12;
// Helper functions to convert objects from JS versions

View File

@ -4,7 +4,6 @@
#include "object.h"
#include "pmp_file.h"
using namespace std;
Map::Map(int size, Terrain* baseTerrain, float baseHeight) {
@ -280,13 +279,12 @@ Area* Map::createArea(AreaPlacer* placer, AreaPainter* painter, Constraint* cons
return a;
}
vector<Object*>* Map::createObjectGroup(ObjectGroupPlacer* placer, Constraint* constr) {
vector<Object*>* objects = new vector<Object*>;
if(!placer->place(this, constr, *objects)) {
return 0;
}
for(int i=0; i<objects->size(); i++) {
addObject((*objects)[i]);
}
return objects;
bool Map::createObjectGroup(ObjectGroupPlacer* placer, Constraint* constr) {
return placer->place(this, constr);
}
int Map::createTileClass() {
tileClasses.push_back(new TileClass(size));
return tileClasses.size();
}

View File

@ -8,6 +8,7 @@
#include "object.h"
#include "terrain.h"
#include "objectgroupplacer.h"
#include "tileclass.h"
class Map {
public:
@ -20,6 +21,7 @@ public:
std::map<int, std::string> idToName;
std::vector<Object*> objects;
std::vector<Area*> areas;
std::vector<TileClass*> tileClasses;
Map(int size, Terrain* baseTerrain, float baseHeight);
Map(std::string fileName, int loadLevel);
@ -44,7 +46,9 @@ public:
void addObject(class Object* ent);
Area* createArea(AreaPlacer* placer, AreaPainter* painter, Constraint* constr);
std::vector<Object*>* createObjectGroup(ObjectGroupPlacer* placer, Constraint* constr);
bool createObjectGroup(ObjectGroupPlacer* placer, Constraint* constr);
int createTileClass(); // returns ID of the new class
};
#endif

View File

@ -7,7 +7,7 @@
class ObjectGroupPlacer
{
public:
virtual bool place(class Map* m, Constraint* constr, std::vector<Object*>& ret) = 0;
virtual bool place(class Map* m, Constraint* constr) = 0;
ObjectGroupPlacer(void);
virtual ~ObjectGroupPlacer(void);

View File

@ -0,0 +1,49 @@
#include "stdafx.h"
#include "rangecount.h"
RangeCount::RangeCount(int size) {
nn = 1;
while(nn < size) {
nn *= 2;
}
vals = new int[2*nn];
memset(vals, 0, 2*nn*sizeof(int));
}
RangeCount::~RangeCount() {
delete[] vals;
}
int RangeCount::get(int pos) {
return vals[nn + pos];
}
void RangeCount::set(int pos, int amt) {
add(pos, amt-get(pos));
}
void RangeCount::add(int pos, int amt) {
for(int s=nn; s>0; s/=2) {
vals[s + pos] += amt;
pos /= 2;
}
}
int RangeCount::get(int start, int end) {
int ret = 0;
int i;
for(i=1; start+i<=end; i*=2) {
if(start & i) {
ret += vals[nn/i + start/i];
start += i;
}
}
while(i) {
if(start+i <= end) {
ret += vals[nn/i + start/i];
start += i;
}
i /= 2;
}
return ret;
}

View File

@ -0,0 +1,17 @@
#ifndef __RANGECOUNT_H__
#define __RANGECOUNT_H__
class RangeCount {
private:
int* vals; // has size 2*nn
int nn; // smallest power of 2 >= size
public:
RangeCount(int size);
~RangeCount();
void set(int pos, int amt);
void add(int pos, int amt);
int get(int pos);
int get(int start, int end);
};
#endif

View File

@ -156,6 +156,9 @@
<File
RelativePath=".\random.cpp">
</File>
<File
RelativePath=".\rangecount.cpp">
</File>
<File
RelativePath=".\rectplacer.cpp">
</File>
@ -192,6 +195,9 @@
<File
RelativePath=".\terrain.cpp">
</File>
<File
RelativePath=".\tileclass.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
@ -242,6 +248,9 @@
<File
RelativePath=".\random.h">
</File>
<File
RelativePath=".\rangecount.h">
</File>
<File
RelativePath=".\rectplacer.h">
</File>
@ -266,6 +275,9 @@
<File
RelativePath=".\terrain.h">
</File>
<File
RelativePath=".\tileclass.h">
</File>
</Filter>
<Filter
Name="Resource Files"

View File

@ -3,36 +3,16 @@
using namespace std;
// NullConstraint
// NullConstraint /////////////////////////////////////////////////////////////////////////
bool NullConstraint::allows(Map* m, int x, int y)
{
return true;
}
// AvoidAreaConstraint
AvoidAreaConstraint::AvoidAreaConstraint(Area* area) {
this->area = area;
}
bool AvoidAreaConstraint::allows(Map* m, int x, int y)
{
return m->area[x][y] != area;
}
// AvoidTextureConstraint
AvoidTextureConstraint::AvoidTextureConstraint(int textureId) {
this->textureId = textureId;
}
bool AvoidTextureConstraint::allows(Map* m, int x, int y)
{
return m->texture[x][y] != textureId;
}
// AndConstraint
// AndConstraint /////////////////////////////////////////////////////////////////////////
AndConstraint::AndConstraint(const vector<Constraint*>& constraints) {
this->constraints = constraints;
@ -53,3 +33,46 @@ bool AndConstraint::allows(Map* m, int x, int y)
}
return true;
}
// AvoidAreaConstraint //////////////////////////////////////////////////////////////////
AvoidAreaConstraint::AvoidAreaConstraint(Area* area) {
this->area = area;
}
bool AvoidAreaConstraint::allows(Map* m, int x, int y)
{
return m->area[x][y] != area;
}
// AvoidTextureConstraint ///////////////////////////////////////////////////////////////
AvoidTextureConstraint::AvoidTextureConstraint(int textureId) {
this->textureId = textureId;
}
bool AvoidTextureConstraint::allows(Map* m, int x, int y)
{
return m->texture[x][y] != textureId;
}
// AvoidTileClassConstraint /////////////////////////////////////////////////////////////
AvoidTileClassConstraint::AvoidTileClassConstraint(TileClass* tileClass, float distance) {
this->tileClass = tileClass;
this->distance = distance;
}
bool AvoidTileClassConstraint::allows(Map* m, int x, int y)
{
return !tileClass->hasTilesInRadius(x, y, distance);
}

View File

@ -4,12 +4,22 @@
#include "constraint.h"
#include "map.h"
#include "area.h"
#include "tileclass.h"
class NullConstraint : public Constraint {
public:
virtual bool allows(Map* m, int x, int y);
};
class AndConstraint : public Constraint {
private:
std::vector<Constraint*> constraints;
public:
AndConstraint(const std::vector<Constraint*>& constraints);
~AndConstraint();
virtual bool allows(Map* m, int x, int y);
};
class AvoidAreaConstraint : public Constraint {
private:
Area* area;
@ -26,13 +36,14 @@ public:
virtual bool allows(Map* m, int x, int y);
};
class AndConstraint : public Constraint {
class AvoidTileClassConstraint : public Constraint {
private:
std::vector<Constraint*> constraints;
TileClass* tileClass;
float distance;
public:
AndConstraint(const std::vector<Constraint*>& constraints);
~AndConstraint();
AvoidTileClassConstraint(TileClass* tileClass, float distance);
virtual bool allows(Map* m, int x, int y);
};
#endif

View File

@ -22,8 +22,8 @@ bool SimpleGroup::Element::place(int cx, int cy, Map* m, Constraint* constr, vec
for(int i=0; i<count; i++) {
while(true) {
float ang = RandFloat()*2*PI;
float x = cx + distance*cos(ang);
float y = cy + distance*sin(ang);
float x = cx + distance*cos(ang) + 0.5f;
float y = cy + distance*sin(ang) + 0.5f;
int ix = (int) x;
int iy = (int) y;
if(m->validT(ix, iy) && constr->allows(m, ix, iy)) {
@ -41,17 +41,24 @@ bool SimpleGroup::Element::place(int cx, int cy, Map* m, Constraint* constr, vec
return true;
}
bool SimpleGroup::place(Map* m, Constraint* constr, vector<Object*>& ret) {
bool SimpleGroup::place(Map* m, Constraint* constr) {
vector<Object*> ret;
for(int i=0; i<elements.size(); i++) {
if(!elements[i]->place(x, y, m, constr, ret)) {
return false;
}
}
for(int i=0; i<ret.size(); i++) {
m->addObject(ret[i]);
if(tileClass != 0) {
tileClass->add((int) ret[i]->x, (int) ret[i]->y);
}
}
return true;
}
SimpleGroup::SimpleGroup(vector<SimpleGroup::Element*>& e, int _x, int _y):
elements(e), x(_x), y(_y)
SimpleGroup::SimpleGroup(vector<SimpleGroup::Element*>& e, TileClass* tc, int _x, int _y):
elements(e), x(_x), y(_y), tileClass(tc)
{
}

View File

@ -2,6 +2,7 @@
#define __SIMPLEGROUP_H__
#include "objectgroupplacer.h"
#include "tileclass.h"
class SimpleGroup : public ObjectGroupPlacer
{
@ -21,10 +22,11 @@ public:
std::vector<Element*> elements;
int x, y;
TileClass* tileClass;
virtual bool place(class Map* m, Constraint* constr, std::vector<Object*>& ret);
virtual bool place(class Map* m, Constraint* constr);
SimpleGroup(std::vector<Element*>& elements, int x, int y);
SimpleGroup(std::vector<Element*>& elements, TileClass* tileClass, int x, int y);
virtual ~SimpleGroup(void);
};

View File

@ -52,3 +52,19 @@ void MultiPainter::paint(Map* m, Area* a)
painters[i]->paint(m, a);
}
}
// TileClassPainter
TileClassPainter::TileClassPainter(TileClass* tc)
{
this->tileClass = tc;
}
void TileClassPainter::paint(Map* m, Area* a)
{
for (int i=0; i<a->points.size(); i++) {
Point p = a->points[i];
tileClass->add(p.x, p.y);
}
}

View File

@ -5,6 +5,7 @@
#include "map.h"
#include "area.h"
#include "terrain.h"
#include "tileclass.h"
class TerrainPainter : public AreaPainter {
Terrain* terrain;
@ -20,6 +21,13 @@ public:
virtual void paint(Map* m, Area* a);
};
class TileClassPainter : public AreaPainter {
TileClass* tileClass;
public:
TileClassPainter(TileClass* tc);
virtual void paint(Map* m, Area* a);
};
class MultiPainter : public AreaPainter {
std::vector<AreaPainter*> painters;
public:

View File

@ -0,0 +1,66 @@
#include "stdafx.h"
#include "tileclass.h"
using namespace std;
TileClass::TileClass(int mapSize) {
this->mapSize = mapSize;
for(int i=0; i<mapSize; i++) {
rc.push_back(new RangeCount(mapSize));
}
}
TileClass::~TileClass() {
for(int i=0; i<mapSize; i++) {
delete rc[i];
}
}
void TileClass::add(int x, int y) {
rc[y]->add(x, 1);
tiles.insert(Point(x, y));
}
void TileClass::remove(int x, int y) {
rc[y]->add(x, -1);
if(rc[y]->get(x) == 0) {
tiles.erase(Point(x, y));
}
}
bool TileClass::hasTilesInRadius(float cx, float cy, float r) {
// special check for really small classes
if(tiles.size() < 4*r) {
for(set<Point>::iterator it = tiles.begin(); it != tiles.end(); it++) {
Point p = *it;
float dx = p.x - cx;
float dy = p.y - cy;
if(dx*dx + dy*dy <= r*r) {
return true;
}
}
return false;
}
for(float y = cy-r; y <= cy+r; y++) {
int iy = (int) y;
if(iy < 0 || iy >= mapSize) {
continue;
}
float dy = y - cy;
float dx = sqrt(r*r - dy*dy);
float x1 = cx - dx;
float x2 = cx + dx;
int minX = max(0, (int) x1);
int maxX = min(mapSize-1, (int) x2);
if(rc[iy]->get(minX, maxX+1) > 0) {
return true;
}
}
return false;
}

View File

@ -0,0 +1,27 @@
#ifndef __TILECLASS_H__
#define __TILECLASS_H__
#include "point.h"
#include "rangecount.h"
// Represents a multiset of tiles, used for constraints. That is, each tile
// can be in the class one or more times. Provides operations to add/remove a tile
// (if a tile is added N times it has to be removed N times to be cleared), and to
// efficiently find whether any tiles in the class are within distance D of a point
// (this will take O(D log D) time).
class TileClass {
private:
int mapSize;
std::vector<RangeCount*> rc; // range count on each row
std::set<Point> tiles; // the distinct tiles in the class
public:
TileClass(int mapSize);
~TileClass();
void add(int x, int y);
void remove(int x, int y);
bool hasTilesInRadius(float cx, float cy, float r);
};
#endif