]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/matmodel.cxx
Display random objects independently of buildings
[simgear.git] / simgear / scene / material / matmodel.cxx
1 // matmodel.cxx -- class to handle models tied to a material property
2 //
3 // Written by David Megginson, started May 1998.
4 //
5 // Copyright (C) 1998 - 2003  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <simgear_config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29
30 #include <map>
31
32
33 #include <osg/AlphaFunc>
34 #include <osg/Group>
35 #include <osg/LOD>
36 #include <osg/StateSet>
37 #include <osg/Transform>
38
39 #include <simgear/debug/logstream.hxx>
40 #include <simgear/math/sg_random.h>
41 #include <simgear/misc/sg_path.hxx>
42 #include <simgear/misc/sgstream.hxx>
43 #include <simgear/scene/model/modellib.hxx>
44
45 #include "matmodel.hxx"
46
47 using namespace simgear;
48 using std::string;
49 using std::map;\f
50 ////////////////////////////////////////////////////////////////////////
51 // Implementation of SGMatModel.
52 ////////////////////////////////////////////////////////////////////////
53
54 SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
55   : _models_loaded(false),
56     _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
57     _spacing_m(node->getDoubleValue("spacing-m", 20)),
58     _range_m(range_m)
59 {
60                                 // Sanity check
61   if (_coverage_m2 < 1000) {
62     SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
63            << " is too small, forcing, to 1000");
64     _coverage_m2 = 1000;
65   }
66
67                                 // Note all the model paths
68   std::vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
69   for (unsigned int i = 0; i < path_nodes.size(); i++)
70     _paths.push_back(path_nodes[i]->getStringValue());
71
72                                 // Note the heading type
73   string hdg = node->getStringValue("heading-type", "fixed");
74   if (hdg == "fixed") {
75     _heading_type = HEADING_FIXED;
76   } else if (hdg == "billboard") {
77     _heading_type = HEADING_BILLBOARD;
78   } else if (hdg == "random") {
79     _heading_type = HEADING_RANDOM;
80   } else if (hdg == "mask") {
81     _heading_type = HEADING_MASK;
82   } else {
83     _heading_type = HEADING_FIXED;
84     SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
85            << "; using 'fixed' instead.");
86   }
87
88   // uncomment to preload models
89   // load_models();
90 }
91
92 SGMatModel::~SGMatModel ()
93 {
94 }
95
96 int
97 SGMatModel::get_model_count( SGPropertyNode *prop_root )
98 {
99   load_models( prop_root );
100   return _models.size();
101 }
102
103 inline void
104 SGMatModel::load_models( SGPropertyNode *prop_root )
105 {
106                                 // Load model only on demand
107   if (!_models_loaded) {
108     for (unsigned int i = 0; i < _paths.size(); i++) {
109       osg::Node *entity = SGModelLib::loadModel(_paths[i], prop_root);
110       if (entity != 0) {
111         // FIXME: this stuff can be handled
112         // in the XML wrapper as well (at least,
113         // the billboarding should be handled
114         // there).
115         
116         if (_heading_type == HEADING_BILLBOARD) {
117           // if the model is a billboard, it is likely :
118           // 1. a branch with only leaves,
119           // 2. a tree or a non rectangular shape faked by transparency
120           // We add alpha clamp then
121           osg::StateSet* stateSet = entity->getOrCreateStateSet();
122           osg::AlphaFunc* alphaFunc =
123             new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01f);
124           stateSet->setAttributeAndModes(alphaFunc,
125                                          osg::StateAttribute::OVERRIDE);
126           stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
127         } 
128         
129         _models.push_back(entity);
130         
131       } else {
132         SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
133         // Ensure the vector contains something, otherwise get_random_model below fails
134         _models.push_back(new osg::Node());
135       }
136     }
137   }
138   _models_loaded = true;
139 }
140
141 osg::Node*
142 SGMatModel::get_random_model( SGPropertyNode *prop_root, mt* seed )
143 {
144   load_models( prop_root ); // comment this out if preloading models
145   int nModels = _models.size();
146   return _models[mt_rand(seed) * nModels].get();
147 }
148
149 double
150 SGMatModel::get_coverage_m2 () const
151 {
152   return _coverage_m2;
153 }
154
155 double SGMatModel::get_range_m() const
156 {
157   return _range_m;
158 }
159
160 double SGMatModel::get_spacing_m() const
161 {
162   return _spacing_m;
163 }
164
165 double SGMatModel::get_randomized_range_m(mt* seed) const
166 {
167   double lrand = mt_rand(seed);
168   
169   // Note that the LoD is not completely randomized.
170   // 10% at 2   * range_m
171   // 30% at 1.5 * range_m
172   // 60% at 1   * range_m
173   if (lrand < 0.1) return 2   * _range_m;
174   if (lrand < 0.4) return 1.5 * _range_m;
175   else return _range_m;
176 }
177
178 SGMatModel::HeadingType
179 SGMatModel::get_heading_type () const
180 {
181   return _heading_type;
182 }
183
184
185 \f
186 ////////////////////////////////////////////////////////////////////////
187 // Implementation of SGMatModelGroup.
188 ////////////////////////////////////////////////////////////////////////
189
190 SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node, float default_object_range)
191   : _range_m(node->getDoubleValue("range-m", default_object_range))
192 {
193                                 // Load the object subnodes
194   std::vector<SGPropertyNode_ptr> object_nodes =
195     ((SGPropertyNode *)node)->getChildren("object");
196   for (unsigned int i = 0; i < object_nodes.size(); i++) {
197     const SGPropertyNode * object_node = object_nodes[i];
198     if (object_node->hasChild("path"))
199       _objects.push_back(new SGMatModel(object_node, _range_m));
200     else
201       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
202   }
203 }
204
205 SGMatModelGroup::~SGMatModelGroup ()
206 {
207 }
208
209 double
210 SGMatModelGroup::get_range_m () const
211 {
212   return _range_m;
213 }
214
215 int
216 SGMatModelGroup::get_object_count () const
217 {
218   return _objects.size();
219 }
220
221 SGMatModel *
222 SGMatModelGroup::get_object (int index) const
223 {
224   return _objects[index];
225 }
226
227 // end of matmodel.cxx