From bb238c4106be86698d83712429069f5db4654998 Mon Sep 17 00:00:00 2001 From: curt Date: Thu, 15 May 2003 15:08:39 +0000 Subject: [PATCH] Separate out the SGMaterial::Object{,Group} code into it's own source file. --- simgear/scene/material/Makefile.am | 6 +- simgear/scene/material/mat.cxx | 185 +-------------------- simgear/scene/material/mat.hxx | 169 +------------------ simgear/scene/material/matobj.cxx | 250 +++++++++++++++++++++++++++++ simgear/scene/material/matobj.hxx | 205 +++++++++++++++++++++++ 5 files changed, 465 insertions(+), 350 deletions(-) create mode 100644 simgear/scene/material/matobj.cxx create mode 100644 simgear/scene/material/matobj.hxx diff --git a/simgear/scene/material/Makefile.am b/simgear/scene/material/Makefile.am index 2ad6e66f..f781c001 100644 --- a/simgear/scene/material/Makefile.am +++ b/simgear/scene/material/Makefile.am @@ -6,10 +6,12 @@ noinst_HEADERS = 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) diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 77f74969..d81947e7 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -66,187 +66,6 @@ local_file_exists( const string& path ) { } - -//////////////////////////////////////////////////////////////////////// -// 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 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; -} - - - -//////////////////////////////////////////////////////////////////////// -// Implementation of SGMaterial::ObjectGroup. -//////////////////////////////////////////////////////////////////////// - -SGMaterial::ObjectGroup::ObjectGroup (SGPropertyNode * node) - : _range_m(node->getDoubleValue("range-m", 2000)) -{ - // Load the object subnodes - vector 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]; -} - - //////////////////////////////////////////////////////////////////////// // Constructors and destructor. @@ -334,7 +153,7 @@ SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props vector 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])); } @@ -429,4 +248,4 @@ void SGMaterial::set_ssg_state( ssgSimpleState *s ) texture_loaded = true; } -// end of newmat.cxx +// end of mat.cxx diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index 66bf19e9..12e54545 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -40,6 +40,8 @@ #include #include +#include "matobj.hxx" + SG_USING_STD(string); @@ -56,169 +58,6 @@ class SGMaterial { public: - - ////////////////////////////////////////////////////////////////////// - // 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 _paths; - mutable vector _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 _objects; - - }; - - - //////////////////////////////////////////////////////////////////// // Public Constructors. @@ -311,7 +150,7 @@ public: /** * 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]; } @@ -383,7 +222,7 @@ private: // true if texture loading deferred, and not yet loaded bool texture_loaded; - vector object_groups; + vector object_groups; // ref count so we can properly delete if we have multiple // pointers to this record diff --git a/simgear/scene/material/matobj.cxx b/simgear/scene/material/matobj.cxx new file mode 100644 index 00000000..9f581d60 --- /dev/null +++ b/simgear/scene/material/matobj.cxx @@ -0,0 +1,250 @@ +// 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 +#endif + +#include + +#include +SG_USING_STD(map); + +#include + +#ifdef SG_MATH_EXCEPTION_CLASH +# include +#endif + +#include +#include +#include +#include +#include + +#include "matobj.hxx" + + +//////////////////////////////////////////////////////////////////////// +// 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; + } +} + + + +//////////////////////////////////////////////////////////////////////// +// 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 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; +} + + + +//////////////////////////////////////////////////////////////////////// +// Implementation of SGMatObjectGroup. +//////////////////////////////////////////////////////////////////////// + +SGMatObjectGroup::SGMatObjectGroup (SGPropertyNode * node) + : _range_m(node->getDoubleValue("range-m", 2000)) +{ + // Load the object subnodes + vector 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 diff --git a/simgear/scene/material/matobj.hxx b/simgear/scene/material/matobj.hxx new file mode 100644 index 00000000..8d92b5fd --- /dev/null +++ b/simgear/scene/material/matobj.hxx @@ -0,0 +1,205 @@ +// 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 + +#include STL_STRING // Standard C++ string library + +#include +#include + +#include +#include + +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 _paths; + mutable vector _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 _objects; + +}; + + + +#endif // _SG_MAT_OBJ_HXX -- 2.39.5