]> git.mxchange.org Git - flightgear.git/blob - src/Objects/newmat.cxx
This is step "1" of probably "many" in the process of separating out the
[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 (unsigned int i = 0; i < _paths.size(); i++) {
135       ssgEntity * entity
136         = globals->get_model_loader()->load_model( globals->get_fg_root(),
137                                                    _paths[i],
138                                                    globals->get_props(),
139                                                    globals->get_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 FGNewMat::Object::get_model (int index) const
167 {
168   load_models();                // comment this out if preloading models
169   return _models[index];
170 }
171
172 ssgEntity *
173 FGNewMat::Object::get_random_model () const
174 {
175   load_models();                // comment this out if preloading models
176   int nModels = _models.size();
177   int index = int(sg_random() * nModels);
178   if (index >= nModels)
179     index = 0;
180   return _models[index];
181 }
182
183 double
184 FGNewMat::Object::get_coverage_m2 () const
185 {
186   return _coverage_m2;
187 }
188
189 FGNewMat::Object::HeadingType
190 FGNewMat::Object::get_heading_type () const
191 {
192   return _heading_type;
193 }
194
195
196 \f
197 ////////////////////////////////////////////////////////////////////////
198 // Implementation of FGNewMat::ObjectGroup.
199 ////////////////////////////////////////////////////////////////////////
200
201 FGNewMat::ObjectGroup::ObjectGroup (SGPropertyNode * node)
202   : _range_m(node->getDoubleValue("range-m", 2000))
203 {
204                                 // Load the object subnodes
205   vector<SGPropertyNode_ptr> object_nodes =
206     ((SGPropertyNode *)node)->getChildren("object");
207   for (unsigned int i = 0; i < object_nodes.size(); i++) {
208     const SGPropertyNode * object_node = object_nodes[i];
209     if (object_node->hasChild("path"))
210       _objects.push_back(new Object(object_node, _range_m));
211     else
212       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
213   }
214 }
215
216 FGNewMat::ObjectGroup::~ObjectGroup ()
217 {
218   for (unsigned int i = 0; i < _objects.size(); i++) {
219     delete _objects[i];
220     _objects[i] = 0;
221   }
222 }
223
224 double
225 FGNewMat::ObjectGroup::get_range_m () const
226 {
227   return _range_m;
228 }
229
230 int
231 FGNewMat::ObjectGroup::get_object_count () const
232 {
233   return _objects.size();
234 }
235
236 FGNewMat::Object *
237 FGNewMat::ObjectGroup::get_object (int index) const
238 {
239   return _objects[index];
240 }
241
242
243 \f
244 ////////////////////////////////////////////////////////////////////////
245 // Constructors and destructor.
246 ////////////////////////////////////////////////////////////////////////
247
248
249 FGNewMat::FGNewMat (const SGPropertyNode * props)
250 {
251     init();
252     read_properties(props);
253     build_ssg_state(false);
254 }
255
256 FGNewMat::FGNewMat (const string &texpath)
257 {
258     init();
259     texture_path = texpath;
260     build_ssg_state(true);
261 }
262
263 FGNewMat::FGNewMat (ssgSimpleState *s)
264 {
265     init();
266     set_ssg_state(s);
267 }
268
269 FGNewMat::~FGNewMat (void)
270 {
271   for (unsigned int i = 0; i < object_groups.size(); i++) {
272     delete object_groups[i];
273     object_groups[i] = 0;
274   }
275 }
276
277
278 \f
279 ////////////////////////////////////////////////////////////////////////
280 // Public methods.
281 ////////////////////////////////////////////////////////////////////////
282
283 void
284 FGNewMat::read_properties (const SGPropertyNode * props)
285 {
286                                 // Get the path to the texture
287   string tname = props->getStringValue("texture", "unknown.rgb");
288   SGPath tpath(globals->get_fg_root());
289   tpath.append("Textures.high");
290   tpath.append(tname);
291   if (!local_file_exists(tpath.str())) {
292     tpath = SGPath(globals->get_fg_root());
293     tpath.append("Textures");
294     tpath.append(tname);
295   }
296   texture_path = tpath.str();
297
298   xsize = props->getDoubleValue("xsize", 0.0);
299   ysize = props->getDoubleValue("ysize", 0.0);
300   wrapu = props->getBoolValue("wrapu", true);
301   wrapv = props->getBoolValue("wrapv", true);
302   mipmap = props->getBoolValue("mipmap", true);
303   light_coverage = props->getDoubleValue("light-coverage", 0.0);
304
305   ambient[0] = props->getDoubleValue("ambient/r", 0.0);
306   ambient[1] = props->getDoubleValue("ambient/g", 0.0);
307   ambient[2] = props->getDoubleValue("ambient/b", 0.0);
308   ambient[3] = props->getDoubleValue("ambient/a", 0.0);
309
310   diffuse[0] = props->getDoubleValue("diffuse/r", 0.0);
311   diffuse[1] = props->getDoubleValue("diffuse/g", 0.0);
312   diffuse[2] = props->getDoubleValue("diffuse/b", 0.0);
313   diffuse[3] = props->getDoubleValue("diffuse/a", 0.0);
314
315   specular[0] = props->getDoubleValue("specular/r", 0.0);
316   specular[1] = props->getDoubleValue("specular/g", 0.0);
317   specular[2] = props->getDoubleValue("specular/b", 0.0);
318   specular[3] = props->getDoubleValue("specular/a", 0.0);
319
320   emission[0] = props->getDoubleValue("emissive/r", 0.0);
321   emission[1] = props->getDoubleValue("emissive/g", 0.0);
322   emission[2] = props->getDoubleValue("emissive/b", 0.0);
323   emission[3] = props->getDoubleValue("emissive/a", 0.0);
324
325   shininess = props->getDoubleValue("shininess", 0.0);
326
327   vector<SGPropertyNode_ptr> object_group_nodes =
328     ((SGPropertyNode *)props)->getChildren("object-group");
329   for (unsigned int i = 0; i < object_group_nodes.size(); i++)
330     object_groups.push_back(new ObjectGroup(object_group_nodes[i]));
331 }
332
333
334 \f
335 ////////////////////////////////////////////////////////////////////////
336 // Private methods.
337 ////////////////////////////////////////////////////////////////////////
338
339 void 
340 FGNewMat::init ()
341 {
342   texture_path = "";
343   state = 0;
344   textured = 0;
345   nontextured = 0;
346   xsize = 0;
347   ysize = 0;
348   wrapu = true;
349   wrapv = true;
350   mipmap = true;
351   light_coverage = 0.0;
352   texture_loaded = false;
353   refcount = 0;
354   shininess = 0.0;
355   for (int i = 0; i < 4; i++)
356     ambient[i] = diffuse[i] = specular[i] = emission[i] = 0.0;
357 }
358
359 bool
360 FGNewMat::load_texture ()
361 {
362   if (texture_loaded) {
363     return false;
364   } else {
365     SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture " << texture_path );
366     textured->setTexture((char *)texture_path.c_str(), wrapu, wrapv, mipmap );
367     texture_loaded = true;
368     return true;
369   }
370 }
371
372
373 void 
374 FGNewMat::build_ssg_state (bool defer_tex_load)
375 {
376     GLenum shade_model =
377         (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
378     bool texture_default = fgGetBool("/sim/rendering/textures");
379     
380     state = new ssgStateSelector(2);
381     state->ref();
382
383     textured = new ssgSimpleState();
384     textured->ref();
385
386     nontextured = new ssgSimpleState();
387     nontextured->ref();
388
389     // Set up the textured state
390     textured->setShadeModel( shade_model );
391     textured->enable( GL_LIGHTING );
392     textured->enable ( GL_CULL_FACE ) ;
393     textured->enable( GL_TEXTURE_2D );
394     textured->disable( GL_BLEND );
395     textured->disable( GL_ALPHA_TEST );
396     if ( !defer_tex_load ) {
397         SG_LOG(SG_INPUT, SG_INFO, "    " << texture_path );
398         textured->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
399         texture_loaded = true;
400     } else {
401         texture_loaded = false;
402     }
403     textured->enable( GL_COLOR_MATERIAL );
404 #if 0
405     textured->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
406     textured->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
407     textured->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
408 #else
409     textured->setMaterial ( GL_AMBIENT,
410                             ambient[0], ambient[1],
411                             ambient[2], ambient[3] ) ;
412     textured->setMaterial ( GL_DIFFUSE,
413                             diffuse[0], diffuse[1],
414                             diffuse[2], diffuse[3] ) ;
415     textured->setMaterial ( GL_SPECULAR,
416                             specular[0], specular[1],
417                             specular[2], specular[3] ) ;
418     textured->setMaterial ( GL_EMISSION,
419                             emission[0], emission[1],
420                             emission[2], emission[3] ) ;
421     textured->setShininess ( shininess );
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     nontextured->setShininess ( shininess );
446
447     state->setStep( 0, textured );    // textured
448     state->setStep( 1, nontextured ); // untextured
449
450     // Choose the appropriate starting state.
451     if ( texture_default ) {
452         state->selectStep(0);
453     } else {
454         state->selectStep(1);
455     }
456 }
457
458
459 void FGNewMat::set_ssg_state( ssgSimpleState *s )
460 {
461     GLenum shade_model =
462         (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
463     bool texture_default = fgGetBool("/sim/rendering/textures");
464
465     state = new ssgStateSelector(2);
466     state->ref();
467
468     textured = s;
469     texture_loaded = true;
470
471     nontextured = new ssgSimpleState();
472     nontextured->ref();
473
474     // Set up the textured state
475     textured->setShadeModel( shade_model );
476
477     // Set up the coloured state
478     nontextured->enable( GL_LIGHTING );
479     nontextured->setShadeModel( shade_model );
480     nontextured->enable ( GL_CULL_FACE      ) ;
481     nontextured->disable( GL_TEXTURE_2D );
482     nontextured->disable( GL_BLEND );
483     nontextured->disable( GL_ALPHA_TEST );
484     nontextured->disable( GL_COLOR_MATERIAL );
485
486     nontextured->setMaterial ( GL_AMBIENT, 
487                                ambient[0], ambient[1], 
488                                ambient[2], ambient[3] ) ;
489     nontextured->setMaterial ( GL_DIFFUSE, 
490                                diffuse[0], diffuse[1], 
491                                diffuse[2], diffuse[3] ) ;
492     nontextured->setMaterial ( GL_SPECULAR, 
493                                specular[0], specular[1], 
494                                specular[2], specular[3] ) ;
495     nontextured->setMaterial ( GL_EMISSION, 
496                                emission[0], emission[1], 
497                                emission[2], emission[3] ) ;
498     nontextured->setShininess ( shininess );
499
500     state->setStep( 0, textured );    // textured
501     state->setStep( 1, nontextured ); // untextured
502
503     // Choose the appropriate starting state.
504     if ( texture_default ) {
505         state->selectStep(0);
506     } else {
507         state->selectStep(1);
508     }
509 }
510
511 // end of newmat.cxx