Moved object information into a new subclass of FGNewMat, and changed
the property name from coverage to coverage_m2.
This commit is contained in:
parent
e5f4da0e9a
commit
cecedd302b
3 changed files with 141 additions and 72 deletions
|
@ -90,6 +90,83 @@ local_file_exists( const string& path ) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGNewMat::Object.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FGNewMat::Object::Object (const SGPropertyNode * node)
|
||||
: _path(node->getStringValue("path")),
|
||||
_model(0),
|
||||
_coverage_m2(node->getDoubleValue("coverage-m2", 100000)),
|
||||
_range_m(node->getDoubleValue("range-m", 2000))
|
||||
{
|
||||
string hdg = node->getStringValue("heading-type", "fixed");
|
||||
if (hdg == "fixed") {
|
||||
_heading_type = HEADING_FIXED;
|
||||
} else if (hdg == "billboard") {
|
||||
_heading_type = HEADING_BILLBOARD;
|
||||
} else if (hdg == "random") {
|
||||
_heading_type = HEADING_RANDOM;
|
||||
} else {
|
||||
_heading_type = HEADING_FIXED;
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
|
||||
<< "; using 'fixed' instead.");
|
||||
}
|
||||
}
|
||||
|
||||
FGNewMat::Object::~Object ()
|
||||
{
|
||||
_model->deRef();
|
||||
}
|
||||
|
||||
const string &
|
||||
FGNewMat::Object::get_path () const
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
|
||||
ssgEntity *
|
||||
FGNewMat::Object::get_model () const
|
||||
{
|
||||
// Load model only on demand
|
||||
if (_model == 0) {
|
||||
SGPath path = globals->get_fg_root();
|
||||
path.append(_path);
|
||||
ssgTexturePath((char *)path.dir().c_str());
|
||||
ssgEntity * entity = load_object((char *)path.c_str());
|
||||
if (entity != 0) {
|
||||
float ranges[] = {0, _range_m};
|
||||
_model = new ssgRangeSelector;
|
||||
((ssgRangeSelector *)_model)->setRanges(ranges, 2);
|
||||
if (_heading_type == HEADING_BILLBOARD) {
|
||||
ssgCutout * cutout = new ssgCutout(false);
|
||||
cutout->addKid(entity);
|
||||
((ssgBranch *)_model)->addKid(cutout);
|
||||
} else {
|
||||
((ssgBranch *)_model)->addKid(entity);
|
||||
}
|
||||
_model->ref();
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << path.str());
|
||||
}
|
||||
}
|
||||
return _model;
|
||||
}
|
||||
|
||||
double
|
||||
FGNewMat::Object::get_coverage_m2 () const
|
||||
{
|
||||
return _coverage_m2;
|
||||
}
|
||||
|
||||
double
|
||||
FGNewMat::Object::get_range_m () const
|
||||
{
|
||||
return _range_m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constructors and destructor.
|
||||
|
@ -118,8 +195,10 @@ FGNewMat::FGNewMat (ssgSimpleState * s)
|
|||
|
||||
FGNewMat::~FGNewMat (void)
|
||||
{
|
||||
for (unsigned int i = 0; i < objects.size(); i++)
|
||||
objects[i].model->deRef();
|
||||
for (unsigned int i = 0; i < objects.size(); i++) {
|
||||
delete objects[i];
|
||||
objects[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,33 +253,10 @@ FGNewMat::read_properties (const SGPropertyNode * props)
|
|||
((SGPropertyNode *)props)->getChildren("object");
|
||||
for (unsigned int i = 0; i < object_nodes.size(); i++) {
|
||||
const SGPropertyNode * object_node = object_nodes[i];
|
||||
if (object_node->hasChild("path")) {
|
||||
Object object;
|
||||
SGPath path = globals->get_fg_root();
|
||||
path.append(object_node->getStringValue("path"));
|
||||
ssgTexturePath((char *)path.dir().c_str());
|
||||
ssgEntity * model = load_object((char *)path.c_str());
|
||||
if (model != 0) {
|
||||
float ranges[] = {0, object_node->getDoubleValue("range-m", 2000)};
|
||||
object.model = new ssgRangeSelector;
|
||||
((ssgRangeSelector *)object.model)->setRanges(ranges, 2);
|
||||
if (object_node->getBoolValue("billboard", false)) {
|
||||
ssgCutout * cutout = new ssgCutout(false);
|
||||
cutout->addKid(model);
|
||||
((ssgBranch *)object.model)->addKid(cutout);
|
||||
} else {
|
||||
((ssgBranch *)object.model)->addKid(model);
|
||||
}
|
||||
object.model->ref();
|
||||
object.coverage = object_node->getDoubleValue("coverage", 100000);
|
||||
object.lod = object_node->getDoubleValue("range-m", 2000);
|
||||
objects.push_back(object);
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << path.str());
|
||||
}
|
||||
} else {
|
||||
if (object_node->hasChild("path"))
|
||||
objects.push_back(new Object(object_node));
|
||||
else
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,43 @@ class FGNewMat {
|
|||
|
||||
public:
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Inner class.
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A randomly-placeable object.
|
||||
*/
|
||||
class Object
|
||||
{
|
||||
public:
|
||||
|
||||
enum HeadingType {
|
||||
HEADING_FIXED,
|
||||
HEADING_BILLBOARD,
|
||||
HEADING_RANDOM
|
||||
};
|
||||
|
||||
const string &get_path () const;
|
||||
ssgEntity * get_model () const;
|
||||
double get_coverage_m2 () const;
|
||||
double get_range_m () const;
|
||||
HeadingType get_heading_type () const;
|
||||
protected:
|
||||
friend class FGNewMat;
|
||||
Object (const SGPropertyNode * node);
|
||||
virtual ~Object ();
|
||||
private:
|
||||
string _path;
|
||||
mutable ssgEntity * _model;
|
||||
double _coverage_m2;
|
||||
double _range_m;
|
||||
HeadingType _heading_type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Public Constructors.
|
||||
|
@ -148,31 +185,15 @@ public:
|
|||
|
||||
|
||||
/**
|
||||
* Get the number of dynamic objects defined for this material.
|
||||
* Get the number of randomly-placed objects defined for this material.
|
||||
*/
|
||||
virtual int get_object_count () const { return objects.size(); }
|
||||
|
||||
|
||||
/**
|
||||
* Get a dynamic object for this material.
|
||||
* Get a randomly-placed object for this material.
|
||||
*/
|
||||
virtual ssgEntity * get_object (int i) const { return objects[i].model; }
|
||||
|
||||
|
||||
/**
|
||||
* Get the average space for a dynamic object for this material.
|
||||
*/
|
||||
virtual double get_object_coverage (int i) const {
|
||||
return objects[i].coverage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the target LOD range for a dynamic object for this material.
|
||||
*/
|
||||
virtual double get_object_lod (int i) const {
|
||||
return objects[i].lod;
|
||||
}
|
||||
virtual Object * get_object (int index) const { return objects[index]; }
|
||||
|
||||
|
||||
/**
|
||||
|
@ -249,14 +270,7 @@ private:
|
|||
// true if texture loading deferred, and not yet loaded
|
||||
bool texture_loaded;
|
||||
|
||||
struct Object
|
||||
{
|
||||
ssgEntity * model;
|
||||
double coverage;
|
||||
double lod;
|
||||
};
|
||||
|
||||
vector<Object> objects;
|
||||
vector<Object *> objects;
|
||||
|
||||
// ref count so we can properly delete if we have multiple
|
||||
// pointers to this record
|
||||
|
@ -274,6 +288,7 @@ private:
|
|||
void build_ssg_state(bool defer_tex_load = false);
|
||||
void set_ssg_state( ssgSimpleState *s );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // _NEWMAT_HXX
|
||||
|
|
|
@ -329,7 +329,7 @@ static void gen_random_surface_points( ssgLeaf *leaf, ssgVertexArray *lights,
|
|||
*/
|
||||
static void
|
||||
add_object_to_triangle (sgVec3 p1, sgVec3 p2, sgVec3 p3, sgVec3 center,
|
||||
sgMat4 ROT, FGNewMat * mat, int object_index,
|
||||
sgMat4 ROT, FGNewMat::Object * object,
|
||||
ssgBranch * branch)
|
||||
{
|
||||
sgVec3 result;
|
||||
|
@ -342,7 +342,7 @@ add_object_to_triangle (sgVec3 p1, sgVec3 p2, sgVec3 p3, sgVec3 center,
|
|||
sgPostMultMat4(OBJ, OBJ_pos);
|
||||
ssgTransform * pos = new ssgTransform;
|
||||
pos->setTransform(OBJ);
|
||||
pos->addKid(mat->get_object(object_index));
|
||||
pos->addKid(object->get_model());
|
||||
branch->addKid(pos);
|
||||
}
|
||||
|
||||
|
@ -353,8 +353,7 @@ public:
|
|||
float * p1;
|
||||
float * p2;
|
||||
float * p3;
|
||||
FGNewMat * mat;
|
||||
int object_index;
|
||||
FGNewMat::Object * object;
|
||||
ssgBranch * branch;
|
||||
sgMat4 ROT;
|
||||
};
|
||||
|
@ -376,8 +375,8 @@ public:
|
|||
* surface.
|
||||
*/
|
||||
static void
|
||||
fill_in_triangle (float * p1, float * p2, float * p3, FGNewMat * mat,
|
||||
int object_index, ssgBranch * branch, sgMat4 ROT)
|
||||
fill_in_triangle (float * p1, float * p2, float * p3,
|
||||
FGNewMat::Object *object, ssgBranch * branch, sgMat4 ROT)
|
||||
{
|
||||
sgVec3 center;
|
||||
sgSetVec3(center,
|
||||
|
@ -385,12 +384,11 @@ fill_in_triangle (float * p1, float * p2, float * p3, FGNewMat * mat,
|
|||
(p1[1] + p2[1] + p3[1]) / 3.0,
|
||||
(p1[2] + p2[2] + p3[2]) / 3.0);
|
||||
double area = sgTriArea(p1, p2, p3);
|
||||
double num = area / mat->get_object_coverage(object_index);
|
||||
double num = area / object->get_coverage_m2();
|
||||
|
||||
// place an object each unit of area
|
||||
while ( num > 1.0 ) {
|
||||
add_object_to_triangle(p1, p2, p3, center,
|
||||
ROT, mat, object_index, branch);
|
||||
add_object_to_triangle(p1, p2, p3, center, ROT, object, branch);
|
||||
num -= 1.0;
|
||||
}
|
||||
// for partial units of area, use a zombie door method to
|
||||
|
@ -399,8 +397,7 @@ fill_in_triangle (float * p1, float * p2, float * p3, FGNewMat * mat,
|
|||
if ( num > 0.0 ) {
|
||||
if ( sg_random() <= num ) {
|
||||
// a zombie made it through our door
|
||||
add_object_to_triangle(p1, p2, p3, center,
|
||||
ROT, mat, object_index, branch);
|
||||
add_object_to_triangle(p1, p2, p3, center, ROT, object, branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -423,8 +420,8 @@ in_range_callback (ssgEntity * entity, int mask)
|
|||
{
|
||||
RandomObjectUserData * data = (RandomObjectUserData *)entity->getUserData();
|
||||
if (!data->is_filled_in) {
|
||||
fill_in_triangle(data->p1, data->p2, data->p3, data->mat,
|
||||
data->object_index, data->branch, data->ROT);
|
||||
fill_in_triangle(data->p1, data->p2, data->p3, data->object,
|
||||
data->branch, data->ROT);
|
||||
data->is_filled_in = true;
|
||||
}
|
||||
return 1;
|
||||
|
@ -540,7 +537,7 @@ get_bounding_radius (sgVec3 center, float *p1, float *p2, float *p3)
|
|||
*/
|
||||
static void
|
||||
setup_triangle (float * p1, float * p2, float * p3,
|
||||
FGNewMat * mat, ssgBranch * branch, sgMat4 ROT)
|
||||
FGNewMat * mat, ssgBranch * branch, sgMat4 ROT)
|
||||
{
|
||||
// Set up a single center point for LOD
|
||||
sgVec3 center;
|
||||
|
@ -564,13 +561,15 @@ setup_triangle (float * p1, float * p2, float * p3,
|
|||
// Iterate through all the object types.
|
||||
int num_objects = mat->get_object_count();
|
||||
for (int i = 0; i < num_objects; i++) {
|
||||
// Look up the random object.
|
||||
FGNewMat::Object * object = mat->get_object(i);
|
||||
|
||||
// Set up the range selector for the entire
|
||||
// triangle; note that we use the object
|
||||
// range plus the bounding radius here, to
|
||||
// allow for objects far from the center.
|
||||
float ranges[] = {0,
|
||||
mat->get_object_lod(i) + bounding_radius,
|
||||
object->get_range_m() + bounding_radius,
|
||||
500000};
|
||||
ssgRangeSelector * lod = new ssgRangeSelector;
|
||||
lod->setRanges(ranges, 3);
|
||||
|
@ -589,8 +588,7 @@ setup_triangle (float * p1, float * p2, float * p3,
|
|||
data->p1 = p1;
|
||||
data->p2 = p2;
|
||||
data->p3 = p3;
|
||||
data->mat = mat;
|
||||
data->object_index = i;
|
||||
data->object = object;
|
||||
data->branch = in_range;
|
||||
sgCopyMat4(data->ROT, ROT);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue