]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/mat.cxx
Removed non-textured and flat shaded support because it really clutters up
[simgear.git] / simgear / scene / material / mat.cxx
1 // mat.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 <simgear_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 #include <simgear/scene/model/loader.hxx>
44
45 #include "mat.hxx"
46
47 \f
48 ////////////////////////////////////////////////////////////////////////
49 // Local static functions.
50 ////////////////////////////////////////////////////////////////////////
51
52 /**
53  * Internal method to test whether a file exists.
54  *
55  * TODO: this should be moved to a SimGear library of local file
56  * functions.
57  */
58 static inline bool
59 local_file_exists( const string& path ) {
60     sg_gzifstream in( path );
61     if ( ! in.is_open() ) {
62         return false;
63     } else {
64         return true;
65     }
66 }
67
68
69 \f
70 ////////////////////////////////////////////////////////////////////////
71 // Implementation of SGMaterial::Object.
72 ////////////////////////////////////////////////////////////////////////
73
74 SGMaterial::Object::Object (const SGPropertyNode * node, double range_m)
75   : _models_loaded(false),
76     _coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
77     _range_m(range_m)
78 {
79                                 // Sanity check
80   if (_coverage_m2 < 1000) {
81     SG_LOG(SG_INPUT, SG_ALERT, "Random object coverage " << _coverage_m2
82            << " is too small, forcing, to 1000");
83     _coverage_m2 = 1000;
84   }
85
86                                 // Note all the model paths
87   vector <SGPropertyNode_ptr> path_nodes = node->getChildren("path");
88   for (unsigned int i = 0; i < path_nodes.size(); i++)
89     _paths.push_back(path_nodes[i]->getStringValue());
90
91                                 // Note the heading type
92   string hdg = node->getStringValue("heading-type", "fixed");
93   if (hdg == "fixed") {
94     _heading_type = HEADING_FIXED;
95   } else if (hdg == "billboard") {
96     _heading_type = HEADING_BILLBOARD;
97   } else if (hdg == "random") {
98     _heading_type = HEADING_RANDOM;
99   } else {
100     _heading_type = HEADING_FIXED;
101     SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
102            << "; using 'fixed' instead.");
103   }
104
105   // uncomment to preload models
106   // load_models();
107 }
108
109 SGMaterial::Object::~Object ()
110 {
111   for (unsigned int i = 0; i < _models.size(); i++) {
112     if (_models[i] != 0) {
113       _models[i]->deRef();
114       _models[i] = 0;
115     }
116   }
117 }
118
119 int
120 SGMaterial::Object::get_model_count( SGModelLoader *loader,
121                                    const string &fg_root,
122                                    SGPropertyNode *prop_root,
123                                    double sim_time_sec )
124 {
125   load_models( loader, fg_root, prop_root, sim_time_sec );
126   return _models.size();
127 }
128
129 inline void
130 SGMaterial::Object::load_models ( SGModelLoader *loader,
131                                 const string &fg_root,
132                                 SGPropertyNode *prop_root,
133                                 double sim_time_sec )
134 {
135                                 // Load model only on demand
136   if (!_models_loaded) {
137     for (unsigned int i = 0; i < _paths.size(); i++) {
138       ssgEntity *entity = loader->load_model( fg_root, _paths[i],
139                                               prop_root, 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 SGMaterial::Object::get_model( int index,
167                              SGModelLoader *loader,
168                              const string &fg_root,
169                              SGPropertyNode *prop_root,
170                              double sim_time_sec )
171 {
172   load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
173   return _models[index];
174 }
175
176 ssgEntity *
177 SGMaterial::Object::get_random_model( SGModelLoader *loader,
178                                     const string &fg_root,
179                                     SGPropertyNode *prop_root,
180                                     double sim_time_sec )
181 {
182   load_models( loader, fg_root, prop_root, sim_time_sec ); // comment this out if preloading models
183   int nModels = _models.size();
184   int index = int(sg_random() * nModels);
185   if (index >= nModels)
186     index = 0;
187   return _models[index];
188 }
189
190 double
191 SGMaterial::Object::get_coverage_m2 () const
192 {
193   return _coverage_m2;
194 }
195
196 SGMaterial::Object::HeadingType
197 SGMaterial::Object::get_heading_type () const
198 {
199   return _heading_type;
200 }
201
202
203 \f
204 ////////////////////////////////////////////////////////////////////////
205 // Implementation of SGMaterial::ObjectGroup.
206 ////////////////////////////////////////////////////////////////////////
207
208 SGMaterial::ObjectGroup::ObjectGroup (SGPropertyNode * node)
209   : _range_m(node->getDoubleValue("range-m", 2000))
210 {
211                                 // Load the object subnodes
212   vector<SGPropertyNode_ptr> object_nodes =
213     ((SGPropertyNode *)node)->getChildren("object");
214   for (unsigned int i = 0; i < object_nodes.size(); i++) {
215     const SGPropertyNode * object_node = object_nodes[i];
216     if (object_node->hasChild("path"))
217       _objects.push_back(new Object(object_node, _range_m));
218     else
219       SG_LOG(SG_INPUT, SG_ALERT, "No path supplied for object");
220   }
221 }
222
223 SGMaterial::ObjectGroup::~ObjectGroup ()
224 {
225   for (unsigned int i = 0; i < _objects.size(); i++) {
226     delete _objects[i];
227     _objects[i] = 0;
228   }
229 }
230
231 double
232 SGMaterial::ObjectGroup::get_range_m () const
233 {
234   return _range_m;
235 }
236
237 int
238 SGMaterial::ObjectGroup::get_object_count () const
239 {
240   return _objects.size();
241 }
242
243 SGMaterial::Object *
244 SGMaterial::ObjectGroup::get_object (int index) const
245 {
246   return _objects[index];
247 }
248
249
250 \f
251 ////////////////////////////////////////////////////////////////////////
252 // Constructors and destructor.
253 ////////////////////////////////////////////////////////////////////////
254
255
256 SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props )
257 {
258     init();
259     read_properties( fg_root, props );
260     build_ssg_state( false );
261 }
262
263 SGMaterial::SGMaterial( const string &texpath )
264 {
265     init();
266     texture_path = texpath;
267     build_ssg_state( true );
268 }
269
270 SGMaterial::SGMaterial( ssgSimpleState *s )
271 {
272     init();
273     set_ssg_state( s );
274 }
275
276 SGMaterial::~SGMaterial (void)
277 {
278   for (unsigned int i = 0; i < object_groups.size(); i++) {
279     delete object_groups[i];
280     object_groups[i] = 0;
281   }
282 }
283
284
285 \f
286 ////////////////////////////////////////////////////////////////////////
287 // Public methods.
288 ////////////////////////////////////////////////////////////////////////
289
290 void
291 SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props )
292 {
293                                 // Get the path to the texture
294   string tname = props->getStringValue("texture", "unknown.rgb");
295   SGPath tpath( fg_root );
296   tpath.append("Textures.high");
297   tpath.append(tname);
298   if (!local_file_exists(tpath.str())) {
299     tpath = SGPath( fg_root );
300     tpath.append("Textures");
301     tpath.append(tname);
302   }
303   texture_path = tpath.str();
304
305   xsize = props->getDoubleValue("xsize", 0.0);
306   ysize = props->getDoubleValue("ysize", 0.0);
307   wrapu = props->getBoolValue("wrapu", true);
308   wrapv = props->getBoolValue("wrapv", true);
309   mipmap = props->getBoolValue("mipmap", true);
310   light_coverage = props->getDoubleValue("light-coverage", 0.0);
311
312   ambient[0] = props->getDoubleValue("ambient/r", 0.0);
313   ambient[1] = props->getDoubleValue("ambient/g", 0.0);
314   ambient[2] = props->getDoubleValue("ambient/b", 0.0);
315   ambient[3] = props->getDoubleValue("ambient/a", 0.0);
316
317   diffuse[0] = props->getDoubleValue("diffuse/r", 0.0);
318   diffuse[1] = props->getDoubleValue("diffuse/g", 0.0);
319   diffuse[2] = props->getDoubleValue("diffuse/b", 0.0);
320   diffuse[3] = props->getDoubleValue("diffuse/a", 0.0);
321
322   specular[0] = props->getDoubleValue("specular/r", 0.0);
323   specular[1] = props->getDoubleValue("specular/g", 0.0);
324   specular[2] = props->getDoubleValue("specular/b", 0.0);
325   specular[3] = props->getDoubleValue("specular/a", 0.0);
326
327   emission[0] = props->getDoubleValue("emissive/r", 0.0);
328   emission[1] = props->getDoubleValue("emissive/g", 0.0);
329   emission[2] = props->getDoubleValue("emissive/b", 0.0);
330   emission[3] = props->getDoubleValue("emissive/a", 0.0);
331
332   shininess = props->getDoubleValue("shininess", 0.0);
333
334   vector<SGPropertyNode_ptr> object_group_nodes =
335     ((SGPropertyNode *)props)->getChildren("object-group");
336   for (unsigned int i = 0; i < object_group_nodes.size(); i++)
337     object_groups.push_back(new ObjectGroup(object_group_nodes[i]));
338 }
339
340
341 \f
342 ////////////////////////////////////////////////////////////////////////
343 // Private methods.
344 ////////////////////////////////////////////////////////////////////////
345
346 void 
347 SGMaterial::init ()
348 {
349     texture_path = "";
350     state = NULL;
351     xsize = 0;
352     ysize = 0;
353     wrapu = true;
354     wrapv = true;
355     mipmap = true;
356     light_coverage = 0.0;
357     texture_loaded = false;
358     refcount = 0;
359     shininess = 0.0;
360     for (int i = 0; i < 4; i++) {
361         ambient[i] = diffuse[i] = specular[i] = emission[i] = 0.0;
362     }
363 }
364
365 bool
366 SGMaterial::load_texture ()
367 {
368     if ( texture_loaded ) {
369         return false;
370     } else {
371         SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
372                 << texture_path );
373         state->setTexture( (char *)texture_path.c_str(), wrapu, wrapv, mipmap );
374         texture_loaded = true;
375         return true;
376     }
377 }
378
379
380 void 
381 SGMaterial::build_ssg_state( bool defer_tex_load )
382 {
383     GLenum shade_model = GL_SMOOTH;
384     
385     state = new ssgSimpleState();
386     state->ref();
387
388     // Set up the textured state
389     state->setShadeModel( shade_model );
390     state->enable( GL_LIGHTING );
391     state->enable ( GL_CULL_FACE ) ;
392     state->enable( GL_TEXTURE_2D );
393     state->disable( GL_BLEND );
394     state->disable( GL_ALPHA_TEST );
395     if ( !defer_tex_load ) {
396         SG_LOG(SG_INPUT, SG_INFO, "    " << texture_path );
397         state->setTexture( (char *)texture_path.c_str(), wrapu, wrapv );
398         texture_loaded = true;
399     } else {
400         texture_loaded = false;
401     }
402     state->enable( GL_COLOR_MATERIAL );
403 #if 0
404     state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
405     state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
406     state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
407 #else
408     state->setMaterial ( GL_AMBIENT,
409                             ambient[0], ambient[1],
410                             ambient[2], ambient[3] ) ;
411     state->setMaterial ( GL_DIFFUSE,
412                             diffuse[0], diffuse[1],
413                             diffuse[2], diffuse[3] ) ;
414     state->setMaterial ( GL_SPECULAR,
415                             specular[0], specular[1],
416                             specular[2], specular[3] ) ;
417     state->setMaterial ( GL_EMISSION,
418                             emission[0], emission[1],
419                             emission[2], emission[3] ) ;
420     state->setShininess ( shininess );
421 #endif
422 }
423
424
425 void SGMaterial::set_ssg_state( ssgSimpleState *s )
426 {
427     state = s;
428     state->ref();
429     texture_loaded = true;
430 }
431
432 // end of newmat.cxx