diff --git a/src/Objects/newmat.cxx b/src/Objects/newmat.cxx index 919039293..8a3da39e4 100644 --- a/src/Objects/newmat.cxx +++ b/src/Objects/newmat.cxx @@ -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"); - } } } diff --git a/src/Objects/newmat.hxx b/src/Objects/newmat.hxx index 3e9f05a66..506051788 100644 --- a/src/Objects/newmat.hxx +++ b/src/Objects/newmat.hxx @@ -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 objects; + vector 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 diff --git a/src/Objects/obj.cxx b/src/Objects/obj.cxx index 40302f92b..f0b2e6e24 100644 --- a/src/Objects/obj.cxx +++ b/src/Objects/obj.cxx @@ -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);