]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/matmodel.cxx
- new FSF addresses
[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 <simgear/compiler.h>
34
35 #ifdef SG_MATH_EXCEPTION_CLASH
36 #  include <math.h>
37 #endif
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 \f
48 ////////////////////////////////////////////////////////////////////////
49 // Local static functions.
50 ////////////////////////////////////////////////////////////////////////
51
52 /**
53  * Internal method to test whether a file exists.
54  *
55  * TODO: this should be moved to a SimGear library of local file
56  * functions.
57  */
58 static inline bool
59 local_file_exists( const string& path ) {
60     sg_gzifstream in( path );
61     if ( ! in.is_open() ) {
62         return false;
63     } else {
64         return true;
65     }
66 }
67
68
69 \f
70 ////////////////////////////////////////////////////////////////////////
71 // Implementation of SGMatModel.
72 ////////////////////////////////////////////////////////////////////////
73
74 SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
75   : _models_loaded(false),
76     _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
77     _range_m(range_m)
78 {
79                                 // Sanity check
80   if (_coverage_m2 < 1000) {
81     SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
82            << " is too small, forcing, to 1000");
83     _coverage_m2 = 1000;
84   }
85
86                                 // Note all the model paths
87   vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
88   for (unsigned int i = 0; i < path_nodes.size(); i++)
89     _paths.push_back(path_nodes[i]->getStringValue());
90
91                                 // Note the heading type
92   string hdg = node->getStringValue("heading-type", "fixed");
93   if (hdg == "fixed") {
94     _heading_type = HEADING_FIXED;
95   } else if (hdg == "billboard") {
96     _heading_type = HEADING_BILLBOARD;
97   } else if (hdg == "random") {
98     _heading_type = HEADING_RANDOM;
99   } else {
100     _heading_type = HEADING_FIXED;
101     SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
102            << "; using 'fixed' instead.");
103   }
104
105   // uncomment to preload models
106   // load_models();
107 }
108
109 SGMatModel::~SGMatModel ()
110 {
111 }
112
113 int
114 SGMatModel::get_model_count( SGModelLib *modellib,
115                              const string &fg_root,
116                              SGPropertyNode *prop_root,
117                              double sim_time_sec )
118 {
119   load_models( modellib, fg_root, prop_root, sim_time_sec );
120   return _models.size();
121 }
122
123 static void
124 setAlphaClampToBranch( ssgBranch *b, float clamp )
125 {
126   int nb = b->getNumKids();
127   for (int i = 0; i<nb; i++) {
128     ssgEntity *e = b->getKid(i);
129     if (e->isAKindOf(ssgTypeLeaf())) {
130       ssgSimpleState*s = (ssgSimpleState*)((ssgLeaf*)e)->getState();
131       s->enable( GL_ALPHA_TEST );
132       s->setAlphaClamp( clamp );
133     } else if (e->isAKindOf(ssgTypeBranch())) {
134       setAlphaClampToBranch( (ssgBranch*)e, clamp );
135     }
136   }
137 }
138
139 inline void
140 SGMatModel::load_models ( SGModelLib *modellib,
141                           const string &fg_root,
142                           SGPropertyNode *prop_root,
143                           double sim_time_sec )
144 {
145                                 // Load model only on demand
146   if (!_models_loaded) {
147     for (unsigned int i = 0; i < _paths.size(); i++) {
148       ssgEntity *entity = modellib->load_model( fg_root, _paths[i],
149                                                 prop_root, sim_time_sec );
150       if (entity != 0) {
151                                 // FIXME: this stuff can be handled
152                                 // in the XML wrapper as well (at least,
153                                 // the billboarding should be handled
154                                 // there).
155         float ranges[] = {0, _range_m};
156         ssgRangeSelector * lod = new ssgRangeSelector;
157         lod->setRanges(ranges, 2);
158         if (_heading_type == HEADING_BILLBOARD) {
159           // if the model is a billboard, it is likely :
160           // 1. a branch with only leaves,
161           // 2. a tree or a non rectangular shape faked by transparency
162           // We add alpha clamp then
163           if ( entity->isAKindOf(ssgTypeBranch()) ) {
164             ssgBranch *b = (ssgBranch *)entity;
165             setAlphaClampToBranch( b, 0.01f );
166           }
167           ssgCutout * cutout = new ssgCutout(false);
168           cutout->addKid(entity);
169           lod->addKid(cutout);
170         } else {
171           lod->addKid(entity);
172         }
173         _models.push_back(lod);
174       } else {
175         SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
176       }
177     }
178   }
179   _models_loaded = true;
180 }
181
182 ssgEntity *
183 SGMatModel::get_model( int index,
184                        SGModelLib *modellib,
185                        const string &fg_root,
186                        SGPropertyNode *prop_root,
187                        double sim_time_sec )
188 {
189   load_models( modellib, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
190   return _models[index];
191 }
192
193 ssgEntity *
194 SGMatModel::get_random_model( SGModelLib *modellib,
195                               const string &fg_root,
196                               SGPropertyNode *prop_root,
197                               double sim_time_sec )
198 {
199   load_models( modellib, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
200   int nModels = _models.size();
201   int index = int(sg_random() * nModels);
202   if (index >= nModels)
203     index = 0;
204   return _models[index];
205 }
206
207 double
208 SGMatModel::get_coverage_m2 () const
209 {
210   return _coverage_m2;
211 }
212
213 SGMatModel::HeadingType
214 SGMatModel::get_heading_type () const
215 {
216   return _heading_type;
217 }
218
219
220 \f
221 ////////////////////////////////////////////////////////////////////////
222 // Implementation of SGMatModelGroup.
223 ////////////////////////////////////////////////////////////////////////
224
225 SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node)
226   : _range_m(node->getDoubleValue("range-m", 2000))
227 {
228                                 // Load the object subnodes
229   vector<SGPropertyNode_ptr> object_nodes =
230     ((SGPropertyNode *)node)->getChildren("object");
231   for (unsigned int i = 0; i < object_nodes.size(); i++) {
232     const SGPropertyNode * object_node = object_nodes[i];
233     if (object_node->hasChild("path"))
234       _objects.push_back(new SGMatModel(object_node, _range_m));
235     else
236       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
237   }
238 }
239
240 SGMatModelGroup::~SGMatModelGroup ()
241 {
242 }
243
244 double
245 SGMatModelGroup::get_range_m () const
246 {
247   return _range_m;
248 }
249
250 int
251 SGMatModelGroup::get_object_count () const
252 {
253   return _objects.size();
254 }
255
256 SGMatModel *
257 SGMatModelGroup::get_object (int index) const
258 {
259   return _objects[index];
260 }
261
262
263 // end of matmodel.cxx