include_HEADERS = \
mat.hxx \
- matlib.hxx
+ matlib.hxx \
+ matobj.hxx
libsgmaterial_a_SOURCES = \
mat.cxx \
- matlib.cxx
+ matlib.cxx \
+ matobj.cxx
INCLUDES = -I$(top_srcdir)
}
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of SGMaterial::Object.
-////////////////////////////////////////////////////////////////////////
-
-SGMaterial::Object::Object (const SGPropertyNode * node, double range_m)
- : _models_loaded(false),
- _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
- _range_m(range_m)
-{
- // Sanity check
- if (_coverage_m2 < 1000) {
- SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
- << " is too small, forcing, to 1000");
- _coverage_m2 = 1000;
- }
-
- // Note all the model paths
- vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
- for (unsigned int i = 0; i < path_nodes.size(); i++)
- _paths.push_back(path_nodes[i]->getStringValue());
-
- // Note the heading type
- 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.");
- }
-
- // uncomment to preload models
- // load_models();
-}
-
-SGMaterial::Object::~Object ()
-{
- for (unsigned int i = 0; i < _models.size(); i++) {
- if (_models[i] != 0) {
- _models[i]->deRef();
- _models[i] = 0;
- }
- }
-}
-
-int
-SGMaterial::Object::get_model_count( SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec )
-{
- load_models( loader, fg_root, prop_root, sim_time_sec );
- return _models.size();
-}
-
-inline void
-SGMaterial::Object::load_models ( SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec )
-{
- // Load model only on demand
- if (!_models_loaded) {
- for (unsigned int i = 0; i < _paths.size(); i++) {
- ssgEntity *entity = loader->load_model( fg_root, _paths[i],
- prop_root, sim_time_sec );
- if (entity != 0) {
- // FIXME: this stuff can be handled
- // in the XML wrapper as well (at least,
- // the billboarding should be handled
- // there).
- float ranges[] = {0, _range_m};
- ssgRangeSelector * lod = new ssgRangeSelector;
- lod->ref();
- lod->setRanges(ranges, 2);
- if (_heading_type == HEADING_BILLBOARD) {
- ssgCutout * cutout = new ssgCutout(false);
- cutout->addKid(entity);
- lod->addKid(cutout);
- } else {
- lod->addKid(entity);
- }
- _models.push_back(lod);
- } else {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
- }
- }
- }
- _models_loaded = true;
-}
-
-ssgEntity *
-SGMaterial::Object::get_model( int index,
- SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec )
-{
- load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
- return _models[index];
-}
-
-ssgEntity *
-SGMaterial::Object::get_random_model( SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec )
-{
- load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
- int nModels = _models.size();
- int index = int(sg_random() * nModels);
- if (index >= nModels)
- index = 0;
- return _models[index];
-}
-
-double
-SGMaterial::Object::get_coverage_m2 () const
-{
- return _coverage_m2;
-}
-
-SGMaterial::Object::HeadingType
-SGMaterial::Object::get_heading_type () const
-{
- return _heading_type;
-}
-
-
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of SGMaterial::ObjectGroup.
-////////////////////////////////////////////////////////////////////////
-
-SGMaterial::ObjectGroup::ObjectGroup (SGPropertyNode * node)
- : _range_m(node->getDoubleValue("range-m", 2000))
-{
- // Load the object subnodes
- vector<SGPropertyNode_ptr> object_nodes =
- ((SGPropertyNode *)node)->getChildren("object");
- for (unsigned int i = 0; i < object_nodes.size(); i++) {
- const SGPropertyNode * object_node = object_nodes[i];
- if (object_node->hasChild("path"))
- _objects.push_back(new Object(object_node, _range_m));
- else
- SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
- }
-}
-
-SGMaterial::ObjectGroup::~ObjectGroup ()
-{
- for (unsigned int i = 0; i < _objects.size(); i++) {
- delete _objects[i];
- _objects[i] = 0;
- }
-}
-
-double
-SGMaterial::ObjectGroup::get_range_m () const
-{
- return _range_m;
-}
-
-int
-SGMaterial::ObjectGroup::get_object_count () const
-{
- return _objects.size();
-}
-
-SGMaterial::Object *
-SGMaterial::ObjectGroup::get_object (int index) const
-{
- return _objects[index];
-}
-
-
\f
////////////////////////////////////////////////////////////////////////
// Constructors and destructor.
vector<SGPropertyNode_ptr> object_group_nodes =
((SGPropertyNode *)props)->getChildren("object-group");
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
- object_groups.push_back(new ObjectGroup(object_group_nodes[i]));
+ object_groups.push_back(new SGMatObjectGroup(object_group_nodes[i]));
}
texture_loaded = true;
}
-// end of newmat.cxx
+// end of mat.cxx
#include <simgear/props/props.hxx>
#include <simgear/scene/model/loader.hxx>
+#include "matobj.hxx"
+
SG_USING_STD(string);
public:
-\f
- //////////////////////////////////////////////////////////////////////
- // Inner classes.
- //////////////////////////////////////////////////////////////////////
-
- class ObjectGroup;
-
- /**
- * A randomly-placeable object.
- *
- * SGMaterial uses this class to keep track of the model(s) and
- * parameters for a single instance of a randomly-placeable object.
- * The object can have more than one variant model (i.e. slightly
- * different shapes of trees), but they are considered equivalent
- * and interchangeable.
- */
- class Object
- {
- public:
-
- /**
- * The heading type for a randomly-placed object.
- */
- enum HeadingType {
- HEADING_FIXED,
- HEADING_BILLBOARD,
- HEADING_RANDOM
- };
-
-
- /**
- * Get the number of variant models available for the object.
- *
- * @return The number of variant models.
- */
- int get_model_count( SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec );
-
-
- /**
- * Get a specific variant model for the object.
- *
- * @param index The index of the model.
- * @return The model.
- */
- ssgEntity *get_model( int index,
- SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec );
-
-
- /**
- * Get a randomly-selected variant model for the object.
- *
- * @return A randomly select model from the variants.
- */
- ssgEntity *get_random_model( SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec );
-
-
- /**
- * Get the average number of meters^2 occupied by each instance.
- *
- * @return The coverage in meters^2.
- */
- double get_coverage_m2 () const;
-
-
- /**
- * Get the heading type for the object.
- *
- * @return The heading type.
- */
- HeadingType get_heading_type () const;
-
- protected:
-
- friend class ObjectGroup;
-
- Object (const SGPropertyNode * node, double range_m);
-
- virtual ~Object ();
-
- private:
-
- /**
- * Actually load the models.
- *
- * This class uses lazy loading so that models won't be held
- * in memory for materials that are never referenced.
- */
- void load_models( SGModelLoader *loader,
- const string &fg_root,
- SGPropertyNode *prop_root,
- double sim_time_sec );
-
- vector<string> _paths;
- mutable vector<ssgEntity *> _models;
- mutable bool _models_loaded;
- double _coverage_m2;
- double _range_m;
- HeadingType _heading_type;
- };
-
-
- /**
- * A collection of related objects with the same visual range.
- *
- * Grouping objects with the same range together significantly
- * reduces the memory requirements of randomly-placed objects.
- * Each SGMaterial instance keeps a (possibly-empty) list of
- * object groups for placing randomly on the scenery.
- */
- class ObjectGroup
- {
- public:
- virtual ~ObjectGroup ();
-
-
- /**
- * Get the visual range of the object in meters.
- *
- * @return The visual range.
- */
- double get_range_m () const;
-
-
- /**
- * Get the number of objects in the group.
- *
- * @return The number of objects.
- */
- int get_object_count () const;
-
-
- /**
- * Get a specific object.
- *
- * @param index The object's index, zero-based.
- * @return The object selected.
- */
- Object * get_object (int index) const;
-
- protected:
-
- friend class SGMaterial;
-
- ObjectGroup (SGPropertyNode * node);
-
- private:
-
- double _range_m;
- vector<Object *> _objects;
-
- };
-
-
-
\f
////////////////////////////////////////////////////////////////////
// Public Constructors.
/**
* Get a randomly-placed object for this material.
*/
- virtual ObjectGroup * get_object_group (int index) const {
+ virtual SGMatObjectGroup * get_object_group (int index) const {
return object_groups[index];
}
// true if texture loading deferred, and not yet loaded
bool texture_loaded;
- vector<ObjectGroup *> object_groups;
+ vector<SGMatObjectGroup *> object_groups;
// ref count so we can properly delete if we have multiple
// pointers to this record
--- /dev/null
+// matobj.cxx -- class to handle material properties
+//
+// Written by Curtis Olson, started May 1998.
+//
+// Copyright (C) 1998 - 2003 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+# include <simgear_config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include <map>
+SG_USING_STD(map);
+
+#include <simgear/compiler.h>
+
+#ifdef SG_MATH_EXCEPTION_CLASH
+# include <math.h>
+#endif
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/scene/model/loader.hxx>
+
+#include "matobj.hxx"
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Local static functions.
+////////////////////////////////////////////////////////////////////////
+
+/**
+ * Internal method to test whether a file exists.
+ *
+ * TODO: this should be moved to a SimGear library of local file
+ * functions.
+ */
+static inline bool
+local_file_exists( const string& path ) {
+ sg_gzifstream in( path );
+ if ( ! in.is_open() ) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGMatObject.
+////////////////////////////////////////////////////////////////////////
+
+SGMatObject::SGMatObject (const SGPropertyNode * node, double range_m)
+ : _models_loaded(false),
+ _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
+ _range_m(range_m)
+{
+ // Sanity check
+ if (_coverage_m2 < 1000) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
+ << " is too small, forcing, to 1000");
+ _coverage_m2 = 1000;
+ }
+
+ // Note all the model paths
+ vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
+ for (unsigned int i = 0; i < path_nodes.size(); i++)
+ _paths.push_back(path_nodes[i]->getStringValue());
+
+ // Note the heading type
+ 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.");
+ }
+
+ // uncomment to preload models
+ // load_models();
+}
+
+SGMatObject::~SGMatObject ()
+{
+ for (unsigned int i = 0; i < _models.size(); i++) {
+ if (_models[i] != 0) {
+ _models[i]->deRef();
+ _models[i] = 0;
+ }
+ }
+}
+
+int
+SGMatObject::get_model_count( SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec )
+{
+ load_models( loader, fg_root, prop_root, sim_time_sec );
+ return _models.size();
+}
+
+inline void
+SGMatObject::load_models ( SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec )
+{
+ // Load model only on demand
+ if (!_models_loaded) {
+ for (unsigned int i = 0; i < _paths.size(); i++) {
+ ssgEntity *entity = loader->load_model( fg_root, _paths[i],
+ prop_root, sim_time_sec );
+ if (entity != 0) {
+ // FIXME: this stuff can be handled
+ // in the XML wrapper as well (at least,
+ // the billboarding should be handled
+ // there).
+ float ranges[] = {0, _range_m};
+ ssgRangeSelector * lod = new ssgRangeSelector;
+ lod->ref();
+ lod->setRanges(ranges, 2);
+ if (_heading_type == HEADING_BILLBOARD) {
+ ssgCutout * cutout = new ssgCutout(false);
+ cutout->addKid(entity);
+ lod->addKid(cutout);
+ } else {
+ lod->addKid(entity);
+ }
+ _models.push_back(lod);
+ } else {
+ SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
+ }
+ }
+ }
+ _models_loaded = true;
+}
+
+ssgEntity *
+SGMatObject::get_model( int index,
+ SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec )
+{
+ load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
+ return _models[index];
+}
+
+ssgEntity *
+SGMatObject::get_random_model( SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec )
+{
+ load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
+ int nModels = _models.size();
+ int index = int(sg_random() * nModels);
+ if (index >= nModels)
+ index = 0;
+ return _models[index];
+}
+
+double
+SGMatObject::get_coverage_m2 () const
+{
+ return _coverage_m2;
+}
+
+SGMatObject::HeadingType
+SGMatObject::get_heading_type () const
+{
+ return _heading_type;
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of SGMatObjectGroup.
+////////////////////////////////////////////////////////////////////////
+
+SGMatObjectGroup::SGMatObjectGroup (SGPropertyNode * node)
+ : _range_m(node->getDoubleValue("range-m", 2000))
+{
+ // Load the object subnodes
+ vector<SGPropertyNode_ptr> object_nodes =
+ ((SGPropertyNode *)node)->getChildren("object");
+ for (unsigned int i = 0; i < object_nodes.size(); i++) {
+ const SGPropertyNode * object_node = object_nodes[i];
+ if (object_node->hasChild("path"))
+ _objects.push_back(new SGMatObject(object_node, _range_m));
+ else
+ SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
+ }
+}
+
+SGMatObjectGroup::~SGMatObjectGroup ()
+{
+ for (unsigned int i = 0; i < _objects.size(); i++) {
+ delete _objects[i];
+ _objects[i] = 0;
+ }
+}
+
+double
+SGMatObjectGroup::get_range_m () const
+{
+ return _range_m;
+}
+
+int
+SGMatObjectGroup::get_object_count () const
+{
+ return _objects.size();
+}
+
+SGMatObject *
+SGMatObjectGroup::get_object (int index) const
+{
+ return _objects[index];
+}
+
+
+// end of matobj.cxx
--- /dev/null
+// matobj.hxx -- a material in the scene graph.
+// TODO: this class needs to be renamed.
+//
+// Written by Curtis Olson, started May 1998.
+// Overhauled by David Megginson, December 2001
+//
+// Copyright (C) 1998 - 2003 Curtis L. Olson - curt@flightgear.org
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+// $Id$
+
+
+#ifndef _SG_MAT_OBJ_HXX
+#define _SG_MAT_OBJ_HXX
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+#include <simgear/compiler.h>
+
+#include STL_STRING // Standard C++ string library
+
+#include <plib/sg.h>
+#include <plib/ssg.h>
+
+#include <simgear/props/props.hxx>
+#include <simgear/scene/model/loader.hxx>
+
+SG_USING_STD(string);
+
+
+class SGMatObjectGroup;
+
+
+/**
+ * A randomly-placeable object.
+ *
+ * SGMaterial uses this class to keep track of the model(s) and
+ * parameters for a single instance of a randomly-placeable object.
+ * The object can have more than one variant model (i.e. slightly
+ * different shapes of trees), but they are considered equivalent
+ * and interchangeable.
+ */
+class SGMatObject {
+
+public:
+
+ /**
+ * The heading type for a randomly-placed object.
+ */
+ enum HeadingType {
+ HEADING_FIXED,
+ HEADING_BILLBOARD,
+ HEADING_RANDOM
+ };
+
+ /**
+ * Get the number of variant models available for the object.
+ *
+ * @return The number of variant models.
+ */
+ int get_model_count( SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec );
+
+
+ /**
+ * Get a specific variant model for the object.
+ *
+ * @param index The index of the model.
+ * @return The model.
+ */
+ ssgEntity *get_model( int index,
+ SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec );
+
+
+ /**
+ * Get a randomly-selected variant model for the object.
+ *
+ * @return A randomly select model from the variants.
+ */
+ ssgEntity *get_random_model( SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec );
+
+
+ /**
+ * Get the average number of meters^2 occupied by each instance.
+ *
+ * @return The coverage in meters^2.
+ */
+ double get_coverage_m2 () const;
+
+
+ /**
+ * Get the heading type for the object.
+ *
+ * @return The heading type.
+ */
+ HeadingType get_heading_type () const;
+
+protected:
+
+ friend class SGMatObjectGroup;
+
+ SGMatObject (const SGPropertyNode * node, double range_m);
+
+ virtual ~SGMatObject ();
+
+private:
+
+ /**
+ * Actually load the models.
+ *
+ * This class uses lazy loading so that models won't be held
+ * in memory for materials that are never referenced.
+ */
+ void load_models( SGModelLoader *loader,
+ const string &fg_root,
+ SGPropertyNode *prop_root,
+ double sim_time_sec );
+
+ vector<string> _paths;
+ mutable vector<ssgEntity *> _models;
+ mutable bool _models_loaded;
+ double _coverage_m2;
+ double _range_m;
+ HeadingType _heading_type;
+};
+
+
+/**
+ * A collection of related objects with the same visual range.
+ *
+ * Grouping objects with the same range together significantly
+ * reduces the memory requirements of randomly-placed objects.
+ * Each SGMaterial instance keeps a (possibly-empty) list of
+ * object groups for placing randomly on the scenery.
+ */
+class SGMatObjectGroup {
+
+public:
+
+ virtual ~SGMatObjectGroup ();
+
+
+ /**
+ * Get the visual range of the object in meters.
+ *
+ * @return The visual range.
+ */
+ double get_range_m () const;
+
+
+ /**
+ * Get the number of objects in the group.
+ *
+ * @return The number of objects.
+ */
+ int get_object_count () const;
+
+
+ /**
+ * Get a specific object.
+ *
+ * @param index The object's index, zero-based.
+ * @return The object selected.
+ */
+ SGMatObject * get_object (int index) const;
+
+protected:
+
+ friend class SGMaterial;
+
+ SGMatObjectGroup (SGPropertyNode * node);
+
+private:
+
+ double _range_m;
+ vector<SGMatObject *> _objects;
+
+};
+
+
+
+#endif // _SG_MAT_OBJ_HXX