]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/matmodel.cxx
b2a4152d8ebc5601e88d81566ea8b39a7189df1d
[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 SG_USING_STD(map);
32
33 #include <osg/AlphaFunc>
34 #include <osg/Group>
35 #include <osg/LOD>
36 #include <osg/StateSet>
37 #include <osg/Transform>
38
39 #ifdef SG_MATH_EXCEPTION_CLASH
40 #  include <math.h>
41 #endif
42
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>
48
49 #include "matmodel.hxx"
50
51 using namespace simgear;
52
53 \f
54 ////////////////////////////////////////////////////////////////////////
55 // Local static functions.
56 ////////////////////////////////////////////////////////////////////////
57
58 /**
59  * Internal method to test whether a file exists.
60  *
61  * TODO: this should be moved to a SimGear library of local file
62  * functions.
63  */
64 static inline bool
65 local_file_exists( const string& path ) {
66     sg_gzifstream in( path );
67     if ( ! in.is_open() ) {
68         return false;
69     } else {
70         return true;
71     }
72 }
73
74
75 \f
76 ////////////////////////////////////////////////////////////////////////
77 // Implementation of SGMatModel.
78 ////////////////////////////////////////////////////////////////////////
79
80 SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
81   : _models_loaded(false),
82     _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
83     _range_m(range_m)
84 {
85                                 // Sanity check
86   if (_coverage_m2 < 1000) {
87     SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
88            << " is too small, forcing, to 1000");
89     _coverage_m2 = 1000;
90   }
91
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());
96
97                                 // Note the heading type
98   string hdg = node->getStringValue("heading-type", "fixed");
99   if (hdg == "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;
105   } else {
106     _heading_type = HEADING_FIXED;
107     SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
108            << "; using 'fixed' instead.");
109   }
110
111   // uncomment to preload models
112   // load_models();
113 }
114
115 SGMatModel::~SGMatModel ()
116 {
117 }
118
119 int
120 SGMatModel::get_model_count( SGPropertyNode *prop_root )
121 {
122   load_models( prop_root );
123   return _models.size();
124 }
125
126 inline void
127 SGMatModel::load_models( SGPropertyNode *prop_root )
128 {
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);
133       if (entity != 0) {
134         // FIXME: this stuff can be handled
135         // in the XML wrapper as well (at least,
136         // the billboarding should be handled
137         // there).
138         
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);
150         } 
151         
152         _models.push_back(entity);
153         
154       } else {
155         SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
156       }
157     }
158   }
159   _models_loaded = true;
160 }
161
162 osg::Node*
163 SGMatModel::get_model( int index,
164                        SGPropertyNode *prop_root )
165 {
166   load_models( prop_root ); // comment this out if preloading models
167   return _models[index].get();
168 }
169
170 osg::Node*
171 SGMatModel::get_random_model( SGPropertyNode *prop_root )
172 {
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)
177     index = 0;
178   return _models[index].get();
179 }
180
181 double
182 SGMatModel::get_coverage_m2 () const
183 {
184   return _coverage_m2;
185 }
186
187 double SGMatModel::get_range_m() const
188 {
189   return _range_m;
190 }
191
192 double SGMatModel::get_randomized_range_m(mt* seed) const
193 {
194   double lrand = mt_rand(seed);
195   
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;
203 }
204
205 SGMatModel::HeadingType
206 SGMatModel::get_heading_type () const
207 {
208   return _heading_type;
209 }
210
211
212 \f
213 ////////////////////////////////////////////////////////////////////////
214 // Implementation of SGMatModelGroup.
215 ////////////////////////////////////////////////////////////////////////
216
217 SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node)
218   : _range_m(node->getDoubleValue("range-m", 2000))
219 {
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));
227     else
228       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
229   }
230 }
231
232 SGMatModelGroup::~SGMatModelGroup ()
233 {
234 }
235
236 double
237 SGMatModelGroup::get_range_m () const
238 {
239   return _range_m;
240 }
241
242 int
243 SGMatModelGroup::get_object_count () const
244 {
245   return _objects.size();
246 }
247
248 SGMatModel *
249 SGMatModelGroup::get_object (int index) const
250 {
251   return _objects[index];
252 }
253
254 // end of matmodel.cxx