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