the property name from coverage to coverage_m2.
}
+\f
+////////////////////////////////////////////////////////////////////////
+// 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;
+}
+
+
\f
////////////////////////////////////////////////////////////////////////
// Constructors and destructor.
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;
+ }
}
((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");
- }
}
}
public:
+\f
+ //////////////////////////////////////////////////////////////////////
+ // 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;
+ };
+
+
\f
////////////////////////////////////////////////////////////////////
// Public Constructors.
/**
- * 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]; }
/**
// 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
void build_ssg_state(bool defer_tex_load = false);
void set_ssg_state( ssgSimpleState *s );
+
};
#endif // _NEWMAT_HXX
*/
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;
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);
}
float * p1;
float * p2;
float * p3;
- FGNewMat * mat;
- int object_index;
+ FGNewMat::Object * object;
ssgBranch * branch;
sgMat4 ROT;
};
* 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,
(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
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);
}
}
}
{
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;
*/
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;
// 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);
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);