]> git.mxchange.org Git - flightgear.git/blob - src/Objects/newmat.cxx
96288fe87a6b781ab5cd943d8796e1c4bbeb373a
[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   vector<SGPropertyNode_ptr> object_group_nodes =
322     ((SGPropertyNode *)props)->getChildren("object-group");
323   for (unsigned int i = 0; i < object_group_nodes.size(); i++)
324     object_groups.push_back(new ObjectGroup(object_group_nodes[i]));
325 }
326
327
328 \f
329 ////////////////////////////////////////////////////////////////////////
330 // Private methods.
331 ////////////////////////////////////////////////////////////////////////
332
333 void 
334 FGNewMat::init ()
335 {
336   texture_path = "";
337   state = 0;
338   textured = 0;
339   nontextured = 0;
340   xsize = 0;
341   ysize = 0;
342   wrapu = true;
343   wrapv = true;
344   mipmap = true;
345   light_coverage = 0.0;
346   texture_loaded = false;
347   refcount = 0;
348   for (int i = 0; i < 4; i++)
349     ambient[i] = diffuse[i] = specular[i] = emission[i] = 0.0;
350 }
351
352 bool
353 FGNewMat::load_texture ()
354 {
355   if (texture_loaded) {
356     return false;
357   } else {
358     SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture " << texture_path );
359     textured->setTexture((char *)texture_path.c_str(), wrapu, wrapv, mipmap );
360     texture_loaded = true;
361     return true;
362   }
363 }
364
365
366 void 
367 FGNewMat::build_ssg_state (bool defer_tex_load)
368 {
369     GLenum shade_model =
370       (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
371     bool texture_default = fgGetBool("/sim/rendering/textures");
372
373     state = new ssgStateSelector(2);
374     state->ref();
375
376     textured = new ssgSimpleState();
377     textured->ref();
378
379     nontextured = new ssgSimpleState();
380     nontextured->ref();
381
382     // Set up the textured state
383     textured->setShadeModel( shade_model );
384     textured->enable( GL_LIGHTING );
385     textured->enable ( GL_CULL_FACE ) ;
386     textured->enable( GL_TEXTURE_2D );
387     textured->disable( GL_BLEND );
388     textured->disable( GL_ALPHA_TEST );
389 #if 0
390 #  ifdef GL_EXT_texture_filter_anisotropic
391     float max_anisotropy;
392     glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy );
393     glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
394                      max_anisotropy );
395     cout << "Max anisotropy = " << max_anisotropy << endl;
396 #  endif
397 #endif
398     if ( !defer_tex_load ) {
399         textured->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
400         texture_loaded = true;
401     } else {
402         texture_loaded = false;
403     }
404     textured->enable( GL_COLOR_MATERIAL );
405 #if 0
406     textured->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
407     textured->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
408     textured->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
409 #else
410     textured->setMaterial ( GL_AMBIENT,
411                             ambient[0], ambient[1],
412                             ambient[2], ambient[3] ) ;
413     textured->setMaterial ( GL_DIFFUSE,
414                             diffuse[0], diffuse[1],
415                             diffuse[2], diffuse[3] ) ;
416     textured->setMaterial ( GL_SPECULAR,
417                             specular[0], specular[1],
418                             specular[2], specular[3] ) ;
419     textured->setMaterial ( GL_EMISSION,
420                             emission[0], emission[1],
421                             emission[2], emission[3] ) ;
422 #endif
423
424     // Set up the coloured state
425     nontextured->enable( GL_LIGHTING );
426     nontextured->setShadeModel( shade_model );
427     nontextured->enable ( GL_CULL_FACE      ) ;
428     nontextured->disable( GL_TEXTURE_2D );
429     nontextured->disable( GL_BLEND );
430     nontextured->disable( GL_ALPHA_TEST );
431     nontextured->disable( GL_COLOR_MATERIAL );
432
433     nontextured->setMaterial ( GL_AMBIENT, 
434                                ambient[0], ambient[1], 
435                                ambient[2], ambient[3] ) ;
436     nontextured->setMaterial ( GL_DIFFUSE, 
437                                diffuse[0], diffuse[1], 
438                                diffuse[2], diffuse[3] ) ;
439     nontextured->setMaterial ( GL_SPECULAR, 
440                                specular[0], specular[1], 
441                                specular[2], specular[3] ) ;
442     nontextured->setMaterial ( GL_EMISSION, 
443                                emission[0], emission[1], 
444                                emission[2], emission[3] ) ;
445
446     state->setStep( 0, textured );    // textured
447     state->setStep( 1, nontextured ); // untextured
448
449     // Choose the appropriate starting state.
450     if ( texture_default ) {
451         state->selectStep(0);
452     } else {
453         state->selectStep(1);
454     }
455 }
456
457
458 void FGNewMat::set_ssg_state( ssgSimpleState *s )
459 {
460     state = new ssgStateSelector(2);
461     state->ref();
462
463     textured = s;
464
465     nontextured = new ssgSimpleState();
466     nontextured->ref();
467
468     // Set up the coloured state
469     nontextured->enable( GL_LIGHTING );
470     nontextured->setShadeModel( GL_FLAT );
471     nontextured->enable ( GL_CULL_FACE      ) ;
472     nontextured->disable( GL_TEXTURE_2D );
473     nontextured->disable( GL_BLEND );
474     nontextured->disable( GL_ALPHA_TEST );
475     nontextured->disable( GL_COLOR_MATERIAL );
476
477     /* cout << "ambient = " << ambient[0] << "," << ambient[1] 
478        << "," << ambient[2] << endl; */
479     nontextured->setMaterial ( GL_AMBIENT, 
480                                ambient[0], ambient[1], 
481                                ambient[2], ambient[3] ) ;
482     nontextured->setMaterial ( GL_DIFFUSE, 
483                                diffuse[0], diffuse[1], 
484                                diffuse[2], diffuse[3] ) ;
485     nontextured->setMaterial ( GL_SPECULAR, 
486                                specular[0], specular[1], 
487                                specular[2], specular[3] ) ;
488     nontextured->setMaterial ( GL_EMISSION, 
489                                emission[0], emission[1], 
490                                emission[2], emission[3] ) ;
491
492     state->setStep( 0, textured );    // textured
493     state->setStep( 1, nontextured ); // untextured
494
495     // Choose the appropriate starting state.
496     state->selectStep(0);
497 }
498
499 // end of newmat.cxx