This is frustrating me. The following plugin works in the little preview window, however the program closes when I generate terrain. It doesn’t give an error or pop-up a debugger so I’m clueless as to what is causing it. I can get it to work by commenting out some code in a recurcive function…
[code]#include “stdafx.h”
#include “inverter.h”
#include “…\core\HField.h”
// You must furnish your own Maker and Killer functions. The Maker should (obviously) be unique for each device,
// while the Killer can be shared among plugins in the same DLL. The basic idea is to get around the sometimes-messy
// problem of DLL<->Client heap management. The framework will call your maker and killers as appropriate.
Device *InverterMaker() { return new Inverter; };
void InverterKiller(Device *spr) { delete spr; };
struct Point {
int x;
int y;
float z;
};
bool FindBasin(HField*, Point*);
void SetFillHeight(HField*, HField*, Point*);
bool AreaIsBasin(HField*, HField*, int, int, float);
void ClearHField(HField*);
void AddBasinToMask(HField*, HField*);
bool PointIsEdge(HField*, int, int);
// What you MUST DO in the constructor of your device:
// 1) Set the Nametag, Maker and Killer in the lifeptrs struct.
// What you SHOULD do in the constructor:
// 2) Call SetLinks() with the # of inputs and outputs your device is going to use
// …if you dont do #2, you will use the default # of inputs your parent class assigns
Inverter::Inverter(void)
{
lifeptrs.maker = InverterMaker;
lifeptrs.killer = InverterKiller;
strncpy(lifeptrs.nametag, “EX_IV”, 4);
SetLinks(1, 1);
// This is how you would add a parameter to a device that is managed by the generic dlg system
// This adds a floating point parameter. You can add floats, ints, bools, or enums.
AddParam(Parameter(“Dummy Parameter”, 0.0f, 0.0f, 1.0f));
}
// This is a convenient way to access your device parameters
// Note that accessing parameters is really quite slow due to the string searching for the param name.
// Do NOT call inside of loops if you care about performance – just retrieve the value once and cache it.
#define INV_DUMMY ParmFRef(“Dummy Parameter”)
Inverter::~Inverter(void)
{
}
// You are REQUIRED to write out and read in your 4-byte Device ID tag, as shown below. It is also recommended that your device
// have an internal version number that you keep track of to allow backwards-compatibility if you ever change your Device save layout…
// Also, make sure you call your super class’s Load and Save functions as shown here. Failure to do so will cause major problems.
bool Inverter::Load(std::istream &in) {
char tag[5];
in.read( tag, 4);
if (strncmp(tag, lifeptrs.nametag, 4) == 0) {
int ver = 0;
in.read((char*) &ver, 1);
return Filter::Load(in);
}
else
return false;
};
bool Inverter::Save(std::ostream &out) {
out.write( lifeptrs.nametag, 4);
int ver = 1;
out.write((char*) &ver, 1);
return Filter::Save(out);
};
// The Activate function is where you work your magic. You should do four things in the Activate function:
// 1) Retrieve your inputs by calling RetrieveData(input#)
// 2) Do whatever you will do on it…
// 3) Store the data to make it available to your outputs
// 4) Return true to indicate successful activation, or false if there was an error.
bool Inverter::Activate(int pstate) {
HField *hf = HF(RetrieveData(0) ); // Use the RetrieveData(),StoreData() pair to get and set your heightfields
HField *hfMask = GetNewHF(GetWorldSize());
HField *hfTemp = GetNewHF(GetWorldSize());
Point *pBasin = new Point();
// This is important! An input CAN RETURN NULL if it is not connected, or the input is turned off. So always check and bail out if its not there
if (!hf)
return false;
// ** example: if we actually DID anything with our dummy param, this is how you would get it
float dummy = INV_DUMMY;
// ** example: If you wanted to access the data by coordinate instead of by index, here’s how you would do it:
int width = hf->w();
int height = hf->h();
// Find basin low points
for (int x = width/2; x < width; x=x+width) {
for (int y = height/2; y < height; y=y+height) {
pBasin->x = x;
pBasin->y = y;
if (FindBasin(hf, pBasin)) {
// (*hf)[Coord(pBasin->x, pBasin->y)] = 1.0f; // test basin points (remove)
SetFillHeight(hf, hfTemp, pBasin);
AddBasinToMask(hfMask, hfTemp);
}
}
}
// Handoff to output(s)
StoreData(hfTemp,0); // pass the heightfield to our output stage.
// Success!
delete pBasin; // take out the trash.
return true;
}
bool FindBasin(HField* hf, Point* p) {
int lowX = p->x;
int lowY = p->y;
if (PointIsEdge(hf, p->x, p->y)) // return false if current point is on edge of map.
return FALSE;
for (int northToSouth = 1; northToSouth > -2; northToSouth–) { // Find lowest point in 3x3 grid.
for (int westToEast = -1; westToEast < 2; westToEast++) {
if ((*hf)[Coord(lowX, lowY)] > (*hf)[Coord(p->x+westToEast, p->y+northToSouth)]) { // reset lowest point if lower than current.
lowX = p->x+westToEast;
lowY = p->y+northToSouth;
}
}
}
if (lowX == p->x && lowY == p->y) { // if current point is lowest point set z and return TRUE.
p->z = (*hf)[Coord(p->x, p->y)];
return TRUE;
} else {
p->x = lowX;
p->y = lowY;
return FindBasin(hf, p); // set current point to lowest point and do it again.
}
}
void SetFillHeight(HField* hf, HField* hfT, Point* p) { // Finds and sets the basin area to the mask.
bool lastOK;
float maxZ = 1.0f;
float lastGoodZ = p->z;
if (AreaIsBasin(hf, hfT, p->x, p->y, p->z)) {
p->z = (p->z + maxZ) * 0.5f;
for (int i = 0; i < 5; ++i) {
ClearHField(hfT);
if (AreaIsBasin(hf, hfT, p->x, p->y, p->z)) {
lastGoodZ = p->z;
p->z = (p->z + maxZ) * 0.5f;
lastOK = TRUE;
} else {
maxZ = p->z;
p->z = (maxZ + lastGoodZ) * 0.5f;
lastOK = FALSE;
}
}
if (!lastOK)
ClearHField(hfT);
AreaIsBasin(hf, hfT, p->x, p->y, lastGoodZ);
}
}
bool AreaIsBasin(HField* hf, HField* hfT, int x, int y, float z) { // returns true if elevation of p->z creates a basin.
if (PointIsEdge(hf, x, y)) { // This is a border point. Basin spills.
return FALSE;
} else if ((*hf)[Coord(x,y)] > z || (*hfT)[Coord(x,y)] > 0.0f) // Dead end. So far so good.
return TRUE;
else { // If all avenues lead to deadends, we got a basin at height z.
(*hfT)[Coord(x,y)] = 1.0f;
return ( AreaIsBasin(hf, hfT, x, y+1, z) &&
AreaIsBasin(hf, hfT, x-1, y+1, z) &&
AreaIsBasin(hf, hfT, x-1, y, z) &&
AreaIsBasin(hf, hfT, x-1, y-1, z) &&
AreaIsBasin(hf, hfT, x, y-1, z) &&
AreaIsBasin(hf, hfT, x+1, y-1, z) &&
AreaIsBasin(hf, hfT, x+1, y, z) &&
AreaIsBasin(hf, hfT, x+1, y+1, z) );
}
}
void ClearHField(HField* hf) { // zeros out height of hf.
int width = hf->w();
int height = hf->h();
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y)
(*hf)[Coord(x,y)] = 0.0f;
}
}
void AddBasinToMask(HField* hfMask, HField* hfTemp) {
}
bool PointIsEdge(HField* hf, int x, int y) {
if (x-1 < 0 || x+1 > hf->w() || y-1 < 0 || y+1 > hf->h()) // return true if current point is on edge of map.
return TRUE;
else
return FALSE;
}[/code]
If I comment out as follows it works…
bool AreaIsBasin(HField* hf, HField* hfT, int x, int y, float z) { // returns true if elevation of p->z creates a basin.
if (PointIsEdge(hf, x, y)) { // This is a border point. Basin spills.
return FALSE;
} else if ((*hf)[Coord(x,y)] > z || (*hfT)[Coord(x,y)] > 0.0f) // Dead end. So far so good.
return TRUE;
else { // If all avenues lead to deadends, we got a basin at height z.
(*hfT)[Coord(x,y)] = 1.0f;
return ( AreaIsBasin(hf, hfT, x, y+1, z) &&
AreaIsBasin(hf, hfT, x-1, y+1, z) &&
// AreaIsBasin(hf, hfT, x-1, y, z) &&
// AreaIsBasin(hf, hfT, x-1, y-1, z) &&
// AreaIsBasin(hf, hfT, x, y-1, z) &&
AreaIsBasin(hf, hfT, x+1, y-1, z) &&
AreaIsBasin(hf, hfT, x+1, y, z) &&
AreaIsBasin(hf, hfT, x+1, y+1, z) );
}
}
Any ideas?