]> git.mxchange.org Git - flightgear.git/blob - src/Objects/newmat.cxx
Fixed some signed vs. unsigned warnings.
[flightgear.git] / src / Objects / newmat.cxx
1 // newmat.cxx -- class to handle material properties
2 //
3 // Written by Curtis Olson, started May 1998.
4 //
5 // Copyright (C) 1998 - 2000  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 <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
44 #include <Main/globals.hxx>
45 #include <Main/fg_props.hxx>
46
47 #include "newmat.hxx"
48
49 \f
50 ////////////////////////////////////////////////////////////////////////
51 // Local static variables.
52 // FIXME: write a proper manager.
53 ////////////////////////////////////////////////////////////////////////
54
55 // Objects already loaded (that can be reused).
56 map<string,ssgEntity *> object_map;
57
58
59 \f
60 ////////////////////////////////////////////////////////////////////////
61 // Local static functions.
62 ////////////////////////////////////////////////////////////////////////
63
64 // FIXME: this is totally evil and non-robust: it assumes that
65 // entities will never be refcounted to 0 (which is safe for now).
66 static ssgEntity *
67 load_object (char * path)
68 {
69   ssgEntity * object = object_map[path];
70   if (object == 0) {
71     object = ssgLoad(path);
72     object_map[path] = object;
73   }
74   return object;
75 }
76
77 /**
78  * Internal method to test whether a file exists.
79  *
80  * TODO: this should be moved to a SimGear library of local file
81  * functions.
82  */
83 static inline bool
84 local_file_exists( const string& path ) {
85     sg_gzifstream in( path );
86     if ( ! in.is_open() ) {
87         return false;
88     } else {
89         return true;
90     }
91 }
92
93
94 \f
95 ////////////////////////////////////////////////////////////////////////
96 // Implementation of FGNewMat::Object.
97 ////////////////////////////////////////////////////////////////////////
98
99 FGNewMat::Object::Object (const SGPropertyNode * node, double range_m)
100   : _models_loaded(false),
101     _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
102     _range_m(range_m)
103 {
104                                 // Sanity check
105   if (_coverage_m2 < 1000) {
106     SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
107            << " is too small, forcing, to 1000");
108     _coverage_m2 = 1000;
109   }
110
111                                 // Note all the model paths
112   vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
113   for (unsigned int i = 0; i < path_nodes.size(); i++)
114     _paths.push_back(path_nodes[i]->getStringValue());
115
116                                 // Note the heading type
117   string hdg = node->getStringValue("heading-type", "fixed");
118   if (hdg == "fixed") {
119     _heading_type = HEADING_FIXED;
120   } else if (hdg == "billboard") {
121     _heading_type = HEADING_BILLBOARD;
122   } else if (hdg == "random") {
123     _heading_type = HEADING_RANDOM;
124   } else {
125     _heading_type = HEADING_FIXED;
126     SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
127            << "; using 'fixed' instead.");
128   }
129
130   // uncomment to preload models
131   // load_models();
132 }
133
134 FGNewMat::Object::~Object ()
135 {
136   for (unsigned int i = 0; i < _models.size(); i++) {
137     if (_models[i] != 0) {
138       _models[i]->deRef();
139       _models[i] = 0;
140     }
141   }
142 }
143
144 int
145 FGNewMat::Object::get_model_count () const
146 {
147   return _models.size();
148 }
149
150 inline void
151 FGNewMat::Object::load_models () const
152 {
153   cout << "loading ground cover objects:" << endl;
154
155                                 // Load model only on demand
156   if (!_models_loaded) {
157     for (unsigned int i = 0; i < _paths.size(); i++) {
158       SGPath path = globals->get_fg_root();
159       path.append(_paths[i]);
160       ssgTexturePath((char *)path.dir().c_str());
161       ssgEntity * entity = load_object((char *)path.c_str());
162       cout << "  " << path.str() << endl;
163       if (entity != 0) {
164         float ranges[] = {0, _range_m};
165         ssgRangeSelector * lod = new ssgRangeSelector;
166         lod->setRanges(ranges, 2);
167         if (_heading_type == HEADING_BILLBOARD) {
168           ssgCutout * cutout = new ssgCutout(false);
169           cutout->addKid(entity);
170           lod->addKid(cutout);
171         } else {
172           lod->addKid(entity);
173         }
174         lod->ref();
175         _models.push_back(lod);
176       } else {
177         SG_LOG(SG_INPUT, SG_ALERT, "Failed to load object " << path.str());
178       }
179     }
180   }
181   _models_loaded = true;
182 }
183
184 ssgEntity *
185 FGNewMat::Object::get_model (int index) const
186 {
187   load_models();                // comment this out if preloading models
188   return _models[index];
189 }
190
191 ssgEntity *
192 FGNewMat::Object::get_random_model () const
193 {
194   load_models();                // comment this out if preloading models
195   int nModels = _models.size();
196   int index = int(sg_random() * nModels);
197   if (index >= nModels)
198     index = 0;
199   return _models[index];
200 }
201
202 double
203 FGNewMat::Object::get_coverage_m2 () const
204 {
205   return _coverage_m2;
206 }
207
208 FGNewMat::Object::HeadingType
209 FGNewMat::Object::get_heading_type () const
210 {
211   return _heading_type;
212 }
213
214
215 \f
216 ////////////////////////////////////////////////////////////////////////
217 // Implementation of FGNewMat::ObjectGroup.
218 ////////////////////////////////////////////////////////////////////////
219
220 FGNewMat::ObjectGroup::ObjectGroup (SGPropertyNode * node)
221   : _range_m(node->getDoubleValue("range-m", 2000))
222 {
223                                 // Load the object subnodes
224   vector<SGPropertyNode_ptr> object_nodes =
225     ((SGPropertyNode *)node)->getChildren("object");
226   for (unsigned int i = 0; i < object_nodes.size(); i++) {
227     const SGPropertyNode * object_node = object_nodes[i];
228     if (object_node->hasChild("path"))
229       _objects.push_back(new Object(object_node, _range_m));
230     else
231       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
232   }
233 }
234
235 FGNewMat::ObjectGroup::~ObjectGroup ()
236 {
237   for (unsigned int i = 0; i < _objects.size(); i++) {
238     delete _objects[i];
239     _objects[i] = 0;
240   }
241 }
242
243 double
244 FGNewMat::ObjectGroup::get_range_m () const
245 {
246   return _range_m;
247 }
248
249 int
250 FGNewMat::ObjectGroup::get_object_count () const
251 {
252   return _objects.size();
253 }
254
255 FGNewMat::Object *
256 FGNewMat::ObjectGroup::get_object (int index) const
257 {
258   return _objects[index];
259 }
260
261
262 \f
263 ////////////////////////////////////////////////////////////////////////
264 // Constructors and destructor.
265 ////////////////////////////////////////////////////////////////////////
266
267
268 FGNewMat::FGNewMat (const SGPropertyNode * props)
269 {
270     init();
271     read_properties(props);
272     build_ssg_state(false);
273 }
274
275 FGNewMat::FGNewMat (const string &texpath)
276 {
277     init();
278     texture_path = texpath;
279     build_ssg_state(true);
280 }
281
282 FGNewMat::FGNewMat (ssgSimpleState * s)
283 {
284     init();
285     set_ssg_state(s);
286 }
287
288 FGNewMat::~FGNewMat (void)
289 {
290   for (unsigned int i = 0; i < object_groups.size(); i++) {
291     delete object_groups[i];
292     object_groups[i] = 0;
293   }
294 }
295
296
297 \f
298 ////////////////////////////////////////////////////////////////////////
299 // Public methods.
300 ////////////////////////////////////////////////////////////////////////
301
302 void
303 FGNewMat::read_properties (const SGPropertyNode * props)
304 {
305                                 // Get the path to the texture
306   string tname = props->getStringValue("texture", "unknown.rgb");
307   SGPath tpath(globals->get_fg_root());
308   tpath.append("Textures.high");
309   tpath.append(tname);
310   if (!local_file_exists(tpath.str())) {
311     tpath = SGPath(globals->get_fg_root());
312     tpath.append("Textures");
313     tpath.append(tname);
314   }
315   texture_path = tpath.str();
316
317   xsize = props->getDoubleValue("xsize", 0.0);
318   ysize = props->getDoubleValue("ysize", 0.0);
319   wrapu = props->getBoolValue("wrapu", true);
320   wrapv = props->getBoolValue("wrapv", true);
321   mipmap = props->getBoolValue("mipmap", true);
322   light_coverage = props->getDoubleValue("light-coverage", 0.0);
323
324   ambient[0] = props->getDoubleValue("ambient/r", 0.0);
325   ambient[1] = props->getDoubleValue("ambient/g", 0.0);
326   ambient[2] = props->getDoubleValue("ambient/b", 0.0);
327   ambient[3] = props->getDoubleValue("ambient/a", 0.0);
328
329   diffuse[0] = props->getDoubleValue("diffuse/r", 0.0);
330   diffuse[1] = props->getDoubleValue("diffuse/g", 0.0);
331   diffuse[2] = props->getDoubleValue("diffuse/b", 0.0);
332   diffuse[3] = props->getDoubleValue("diffuse/a", 0.0);
333
334   specular[0] = props->getDoubleValue("specular/r", 0.0);
335   specular[1] = props->getDoubleValue("specular/g", 0.0);
336   specular[2] = props->getDoubleValue("specular/b", 0.0);
337   specular[3] = props->getDoubleValue("specular/a", 0.0);
338
339   emission[0] = props->getDoubleValue("emissive/r", 0.0);
340   emission[1] = props->getDoubleValue("emissive/g", 0.0);
341   emission[2] = props->getDoubleValue("emissive/b", 0.0);
342   emission[3] = props->getDoubleValue("emissive/a", 0.0);
343
344   vector<SGPropertyNode_ptr> object_group_nodes =
345     ((SGPropertyNode *)props)->getChildren("object-group");
346   for (unsigned int i = 0; i < object_group_nodes.size(); i++)
347     object_groups.push_back(new ObjectGroup(object_group_nodes[i]));
348 }
349
350
351 \f
352 ////////////////////////////////////////////////////////////////////////
353 // Private methods.
354 ////////////////////////////////////////////////////////////////////////
355
356 void 
357 FGNewMat::init ()
358 {
359   texture_path = "";
360   state = 0;
361   textured = 0;
362   nontextured = 0;
363   xsize = 0;
364   ysize = 0;
365   wrapu = true;
366   wrapv = true;
367   mipmap = true;
368   light_coverage = 0.0;
369   texture_loaded = false;
370   refcount = 0;
371   for (int i = 0; i < 4; i++)
372     ambient[i] = diffuse[i] = specular[i] = emission[i] = 0.0;
373 }
374
375 bool
376 FGNewMat::load_texture ()
377 {
378   if (texture_loaded) {
379     return false;
380   } else {
381     SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture " << texture_path );
382     textured->setTexture((char *)texture_path.c_str(), wrapu, wrapv, mipmap );
383     texture_loaded = true;
384     return true;
385   }
386 }
387
388
389 void 
390 FGNewMat::build_ssg_state (bool defer_tex_load)
391 {
392     GLenum shade_model =
393       (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
394     bool texture_default = fgGetBool("/sim/rendering/textures");
395
396     state = new ssgStateSelector(2);
397     state->ref();
398
399     textured = new ssgSimpleState();
400     textured->ref();
401
402     nontextured = new ssgSimpleState();
403     nontextured->ref();
404
405     // Set up the textured state
406     textured->setShadeModel( shade_model );
407     textured->enable( GL_LIGHTING );
408     textured->enable ( GL_CULL_FACE ) ;
409     textured->enable( GL_TEXTURE_2D );
410     textured->disable( GL_BLEND );
411     textured->disable( GL_ALPHA_TEST );
412 #if 0
413 #  ifdef GL_EXT_texture_filter_anisotropic
414     float max_anisotropy;
415     glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy );
416     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
417                      max_anisotropy );
418     cout << "Max anisotropy = " << max_anisotropy << endl;
419 #  endif
420 #endif
421     if ( !defer_tex_load ) {
422         textured->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
423         texture_loaded = true;
424     } else {
425         texture_loaded = false;
426     }
427     textured->enable( GL_COLOR_MATERIAL );
428     textured->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
429     textured->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
430     textured->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
431
432     // Set up the coloured state
433     nontextured->enable( GL_LIGHTING );
434     nontextured->setShadeModel( shade_model );
435     nontextured->enable ( GL_CULL_FACE      ) ;
436     nontextured->disable( GL_TEXTURE_2D );
437     nontextured->disable( GL_BLEND );
438     nontextured->disable( GL_ALPHA_TEST );
439     nontextured->disable( GL_COLOR_MATERIAL );
440
441     nontextured->setMaterial ( GL_AMBIENT, 
442                                ambient[0], ambient[1], 
443                                ambient[2], ambient[3] ) ;
444     nontextured->setMaterial ( GL_DIFFUSE, 
445                                diffuse[0], diffuse[1], 
446                                diffuse[2], diffuse[3] ) ;
447     nontextured->setMaterial ( GL_SPECULAR, 
448                                specular[0], specular[1], 
449                                specular[2], specular[3] ) ;
450     nontextured->setMaterial ( GL_EMISSION, 
451                                emission[0], emission[1], 
452                                emission[2], emission[3] ) ;
453
454     state->setStep( 0, textured );    // textured
455     state->setStep( 1, nontextured ); // untextured
456
457     // Choose the appropriate starting state.
458     if ( texture_default ) {
459         state->selectStep(0);
460     } else {
461         state->selectStep(1);
462     }
463 }
464
465
466 void FGNewMat::set_ssg_state( ssgSimpleState *s )
467 {
468     state = new ssgStateSelector(2);
469     state->ref();
470
471     textured = s;
472
473     nontextured = new ssgSimpleState();
474     nontextured->ref();
475
476     // Set up the coloured state
477     nontextured->enable( GL_LIGHTING );
478     nontextured->setShadeModel( GL_FLAT );
479     nontextured->enable ( GL_CULL_FACE      ) ;
480     nontextured->disable( GL_TEXTURE_2D );
481     nontextured->disable( GL_BLEND );
482     nontextured->disable( GL_ALPHA_TEST );
483     nontextured->disable( GL_COLOR_MATERIAL );
484
485     /* cout << "ambient = " << ambient[0] << "," << ambient[1] 
486        << "," << ambient[2] << endl; */
487     nontextured->setMaterial ( GL_AMBIENT, 
488                                ambient[0], ambient[1], 
489                                ambient[2], ambient[3] ) ;
490     nontextured->setMaterial ( GL_DIFFUSE, 
491                                diffuse[0], diffuse[1], 
492                                diffuse[2], diffuse[3] ) ;
493     nontextured->setMaterial ( GL_SPECULAR, 
494                                specular[0], specular[1], 
495                                specular[2], specular[3] ) ;
496     nontextured->setMaterial ( GL_EMISSION, 
497                                emission[0], emission[1], 
498                                emission[2], emission[3] ) ;
499
500     state->setStep( 0, textured );    // textured
501     state->setStep( 1, nontextured ); // untextured
502
503     // Choose the appropriate starting state.
504     state->selectStep(0);
505 }
506
507 // end of newmat.cxx