1 // matmodel.cxx -- class to handle models tied to a material property
3 // Written by David Megginson, started May 1998.
5 // Copyright (C) 1998 - 2003 Curtis L. Olson - http://www.flightgear.org/~curt
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 # include <simgear_config.h>
28 #include <simgear/compiler.h>
33 #include <osg/AlphaFunc>
36 #include <osg/StateSet>
37 #include <osg/Transform>
39 #ifdef SG_MATH_EXCEPTION_CLASH
43 #include <simgear/debug/logstream.hxx>
44 #include <simgear/math/sg_random.h>
45 #include <simgear/misc/sg_path.hxx>
46 #include <simgear/misc/sgstream.hxx>
47 #include <simgear/scene/model/modellib.hxx>
49 #include "matmodel.hxx"
51 using namespace simgear;
54 ////////////////////////////////////////////////////////////////////////
55 // Local static functions.
56 ////////////////////////////////////////////////////////////////////////
59 * Internal method to test whether a file exists.
61 * TODO: this should be moved to a SimGear library of local file
65 local_file_exists( const string& path ) {
66 sg_gzifstream in( path );
67 if ( ! in.is_open() ) {
76 ////////////////////////////////////////////////////////////////////////
77 // Implementation of SGMatModel.
78 ////////////////////////////////////////////////////////////////////////
80 SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
81 : _models_loaded(false),
82 _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
86 if (_coverage_m2 < 1000) {
87 SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
88 << " is too small, forcing, to 1000");
92 // Note all the model paths
93 vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
94 for (unsigned int i = 0; i < path_nodes.size(); i++)
95 _paths.push_back(path_nodes[i]->getStringValue());
97 // Note the heading type
98 string hdg = node->getStringValue("heading-type", "fixed");
100 _heading_type = HEADING_FIXED;
101 } else if (hdg == "billboard") {
102 _heading_type = HEADING_BILLBOARD;
103 } else if (hdg == "random") {
104 _heading_type = HEADING_RANDOM;
106 _heading_type = HEADING_FIXED;
107 SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
108 << "; using 'fixed' instead.");
111 // uncomment to preload models
115 SGMatModel::~SGMatModel ()
120 SGMatModel::get_model_count( SGPropertyNode *prop_root )
122 load_models( prop_root );
123 return _models.size();
127 SGMatModel::load_models( SGPropertyNode *prop_root )
129 // Load model only on demand
130 if (!_models_loaded) {
131 for (unsigned int i = 0; i < _paths.size(); i++) {
132 osg::Node *entity = SGModelLib::loadModel(_paths[i], prop_root);
134 // FIXME: this stuff can be handled
135 // in the XML wrapper as well (at least,
136 // the billboarding should be handled
139 if (_heading_type == HEADING_BILLBOARD) {
140 // if the model is a billboard, it is likely :
141 // 1. a branch with only leaves,
142 // 2. a tree or a non rectangular shape faked by transparency
143 // We add alpha clamp then
144 osg::StateSet* stateSet = entity->getOrCreateStateSet();
145 osg::AlphaFunc* alphaFunc =
146 new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01f);
147 stateSet->setAttributeAndModes(alphaFunc,
148 osg::StateAttribute::OVERRIDE);
149 stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
152 _models.push_back(entity);
155 SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
159 _models_loaded = true;
163 SGMatModel::get_model( int index,
164 SGPropertyNode *prop_root )
166 load_models( prop_root ); // comment this out if preloading models
167 return _models[index].get();
171 SGMatModel::get_random_model( SGPropertyNode *prop_root )
173 load_models( prop_root ); // comment this out if preloading models
174 int nModels = _models.size();
175 int index = int(sg_random() * nModels);
176 if (index >= nModels)
178 return _models[index].get();
182 SGMatModel::get_coverage_m2 () const
187 double SGMatModel::get_range_m() const
192 double SGMatModel::get_randomized_range_m(mt* seed) const
194 double lrand = mt_rand(seed);
196 // Note that the LoD is not completely randomized.
197 // 10% at 2 * range_m
198 // 30% at 1.5 * range_m
199 // 60% at 1 * range_m
200 if (lrand < 0.1) return 2 * _range_m;
201 if (lrand < 0.4) return 1.5 * _range_m;
202 else return _range_m;
205 SGMatModel::HeadingType
206 SGMatModel::get_heading_type () const
208 return _heading_type;
213 ////////////////////////////////////////////////////////////////////////
214 // Implementation of SGMatModelGroup.
215 ////////////////////////////////////////////////////////////////////////
217 SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node)
218 : _range_m(node->getDoubleValue("range-m", 2000))
220 // Load the object subnodes
221 vector<SGPropertyNode_ptr> object_nodes =
222 ((SGPropertyNode *)node)->getChildren("object");
223 for (unsigned int i = 0; i < object_nodes.size(); i++) {
224 const SGPropertyNode * object_node = object_nodes[i];
225 if (object_node->hasChild("path"))
226 _objects.push_back(new SGMatModel(object_node, _range_m));
228 SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
232 SGMatModelGroup::~SGMatModelGroup ()
237 SGMatModelGroup::get_range_m () const
243 SGMatModelGroup::get_object_count () const
245 return _objects.size();
249 SGMatModelGroup::get_object (int index) const
251 return _objects[index];
254 // end of matmodel.cxx