]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/matmodel.cxx
24f8c8637b1690e0539beee1e8127fdbc79ec346
[simgear.git] / simgear / scene / material / matmodel.cxx
1 // matmodel.cxx -- class to handle models tied to a material property
2 //
3 // Written by Curtis Olson, started May 1998.
4 //
5 // Copyright (C) 1998 - 2003  Curtis L. Olson  - curt@flightgear.org
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., 675 Mass Ave, Cambridge, MA 02139, 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/loader.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   for (unsigned int i = 0; i < _models.size(); i++) {
112     if (_models[i] != 0) {
113       _models[i]->deRef();
114       _models[i] = 0;
115     }
116   }
117 }
118
119 int
120 SGMatModel::get_model_count( SGModelLoader *loader,
121                                    const string &fg_root,
122                                    SGPropertyNode *prop_root,
123                                    double sim_time_sec )
124 {
125   load_models( loader, fg_root, prop_root, sim_time_sec );
126   return _models.size();
127 }
128
129 inline void
130 SGMatModel::load_models ( SGModelLoader *loader,
131                                 const string &fg_root,
132                                 SGPropertyNode *prop_root,
133                                 double sim_time_sec )
134 {
135                                 // Load model only on demand
136   if (!_models_loaded) {
137     for (unsigned int i = 0; i < _paths.size(); i++) {
138       ssgEntity *entity = loader->load_model( fg_root, _paths[i],
139                                               prop_root, sim_time_sec );
140       if (entity != 0) {
141                                 // FIXME: this stuff can be handled
142                                 // in the XML wrapper as well (at least,
143                                 // the billboarding should be handled
144                                 // there).
145         float ranges[] = {0, _range_m};
146         ssgRangeSelector * lod = new ssgRangeSelector;
147         lod->ref();
148         lod->setRanges(ranges, 2);
149         if (_heading_type == HEADING_BILLBOARD) {
150           ssgCutout * cutout = new ssgCutout(false);
151           cutout->addKid(entity);
152           lod->addKid(cutout);
153         } else {
154           lod->addKid(entity);
155         }
156         _models.push_back(lod);
157       } else {
158         SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << _paths[i]);
159       }
160     }
161   }
162   _models_loaded = true;
163 }
164
165 ssgEntity *
166 SGMatModel::get_model( int index,
167                                SGModelLoader *loader,
168                                const string &fg_root,
169                                SGPropertyNode *prop_root,
170                                double sim_time_sec )
171 {
172   load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
173   return _models[index];
174 }
175
176 ssgEntity *
177 SGMatModel::get_random_model( SGModelLoader *loader,
178                                       const string &fg_root,
179                                       SGPropertyNode *prop_root,
180                                       double sim_time_sec )
181 {
182   load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
183   int nModels = _models.size();
184   int index = int(sg_random() * nModels);
185   if (index >= nModels)
186     index = 0;
187   return _models[index];
188 }
189
190 double
191 SGMatModel::get_coverage_m2 () const
192 {
193   return _coverage_m2;
194 }
195
196 SGMatModel::HeadingType
197 SGMatModel::get_heading_type () const
198 {
199   return _heading_type;
200 }
201
202
203 \f
204 ////////////////////////////////////////////////////////////////////////
205 // Implementation of SGMatModelGroup.
206 ////////////////////////////////////////////////////////////////////////
207
208 SGMatModelGroup::SGMatModelGroup (SGPropertyNode * node)
209   : _range_m(node->getDoubleValue("range-m", 2000))
210 {
211                                 // Load the object subnodes
212   vector<SGPropertyNode_ptr> object_nodes =
213     ((SGPropertyNode *)node)->getChildren("object");
214   for (unsigned int i = 0; i < object_nodes.size(); i++) {
215     const SGPropertyNode * object_node = object_nodes[i];
216     if (object_node->hasChild("path"))
217       _objects.push_back(new SGMatModel(object_node, _range_m));
218     else
219       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
220   }
221 }
222
223 SGMatModelGroup::~SGMatModelGroup ()
224 {
225   for (unsigned int i = 0; i < _objects.size(); i++) {
226     delete _objects[i];
227     _objects[i] = 0;
228   }
229 }
230
231 double
232 SGMatModelGroup::get_range_m () const
233 {
234   return _range_m;
235 }
236
237 int
238 SGMatModelGroup::get_object_count () const
239 {
240   return _objects.size();
241 }
242
243 SGMatModel *
244 SGMatModelGroup::get_object (int index) const
245 {
246   return _objects[index];
247 }
248
249
250 // end of matmodel.cxx