]> git.mxchange.org Git - flightgear.git/blob - src/Objects/newmat.cxx
Add a function declaration
[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 = 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 ( !defer_tex_load ) {
393         SG_LOG(SG_INPUT, SG_INFO, "    " << texture_path );
394         textured->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
395         texture_loaded = true;
396     } else {
397         texture_loaded = false;
398     }
399     textured->enable( GL_COLOR_MATERIAL );
400 #if 0
401     textured->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
402     textured->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
403     textured->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
404 #else
405     textured->setMaterial ( GL_AMBIENT,
406                             ambient[0], ambient[1],
407                             ambient[2], ambient[3] ) ;
408     textured->setMaterial ( GL_DIFFUSE,
409                             diffuse[0], diffuse[1],
410                             diffuse[2], diffuse[3] ) ;
411     textured->setMaterial ( GL_SPECULAR,
412                             specular[0], specular[1],
413                             specular[2], specular[3] ) ;
414     textured->setMaterial ( GL_EMISSION,
415                             emission[0], emission[1],
416                             emission[2], emission[3] ) ;
417     textured->setShininess ( shininess );
418 #endif
419
420     // Set up the coloured state
421     nontextured->enable( GL_LIGHTING );
422     nontextured->setShadeModel( shade_model );
423     nontextured->enable ( GL_CULL_FACE      ) ;
424     nontextured->disable( GL_TEXTURE_2D );
425     nontextured->disable( GL_BLEND );
426     nontextured->disable( GL_ALPHA_TEST );
427     nontextured->disable( GL_COLOR_MATERIAL );
428
429     nontextured->setMaterial ( GL_AMBIENT, 
430                                ambient[0], ambient[1], 
431                                ambient[2], ambient[3] ) ;
432     nontextured->setMaterial ( GL_DIFFUSE, 
433                                diffuse[0], diffuse[1], 
434                                diffuse[2], diffuse[3] ) ;
435     nontextured->setMaterial ( GL_SPECULAR, 
436                                specular[0], specular[1], 
437                                specular[2], specular[3] ) ;
438     nontextured->setMaterial ( GL_EMISSION, 
439                                emission[0], emission[1], 
440                                emission[2], emission[3] ) ;
441     nontextured->setShininess ( shininess );
442
443     state->setStep( 0, textured );    // textured
444     state->setStep( 1, nontextured ); // untextured
445
446     // Choose the appropriate starting state.
447     if ( texture_default ) {
448         state->selectStep(0);
449     } else {
450         state->selectStep(1);
451     }
452 }
453
454
455 void FGNewMat::set_ssg_state( ssgSimpleState *s )
456 {
457     GLenum shade_model =
458         (fgGetBool("/sim/rendering/shading") ? GL_SMOOTH : GL_FLAT);
459     bool texture_default = fgGetBool("/sim/rendering/textures");
460
461     state = new ssgStateSelector(2);
462     state->ref();
463
464     textured = s;
465     texture_loaded = true;
466
467     nontextured = new ssgSimpleState();
468     nontextured->ref();
469
470     // Set up the textured state
471     textured->setShadeModel( shade_model );
472
473     // Set up the coloured state
474     nontextured->enable( GL_LIGHTING );
475     nontextured->setShadeModel( shade_model );
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     nontextured->setMaterial ( GL_AMBIENT, 
483                                ambient[0], ambient[1], 
484                                ambient[2], ambient[3] ) ;
485     nontextured->setMaterial ( GL_DIFFUSE, 
486                                diffuse[0], diffuse[1], 
487                                diffuse[2], diffuse[3] ) ;
488     nontextured->setMaterial ( GL_SPECULAR, 
489                                specular[0], specular[1], 
490                                specular[2], specular[3] ) ;
491     nontextured->setMaterial ( GL_EMISSION, 
492                                emission[0], emission[1], 
493                                emission[2], emission[3] ) ;
494     nontextured->setShininess ( shininess );
495
496     state->setStep( 0, textured );    // textured
497     state->setStep( 1, nontextured ); // untextured
498
499     // Choose the appropriate starting state.
500     if ( texture_default ) {
501         state->selectStep(0);
502     } else {
503         state->selectStep(1);
504     }
505 }
506
507 // end of newmat.cxx