]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/matlib.cxx
07a20b11ddf70834c441e3d4008c24b35a8ba56d
[simgear.git] / simgear / scene / material / matlib.cxx
1 // materialmgr.cxx -- class to handle material properties
2 //
3 // Written by Curtis Olson, started May 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson  - http://www.flightgear.org/~curt
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <simgear_config.h>
26 #endif
27
28 #ifdef SG_MATH_EXCEPTION_CLASH
29 #  include <math.h>
30 #endif
31
32 #ifdef HAVE_WINDOWS_H
33 #  include <windows.h>
34 #endif
35
36 #include <simgear/compiler.h>
37 #include <simgear/constants.h>
38 #include <simgear/structure/exception.hxx>
39
40 #include SG_GL_H
41
42 #include <string.h>
43 #include STL_STRING
44
45 #include <osg/AlphaFunc>
46 #include <osg/BlendFunc>
47 #include <osg/CullFace>
48 #include <osg/Material>
49 // #include <osg/Multisample>
50 #include <osg/Point>
51 #include <osg/PointSprite>
52 #include <osg/PolygonMode>
53 #include <osg/PolygonOffset>
54 #include <osg/StateSet>
55 #include <osg/TexEnv>
56 #include <osg/TexGen>
57 #include <osg/Texture2D>
58
59 #include <simgear/debug/logstream.hxx>
60 #include <simgear/misc/sg_path.hxx>
61 #include <simgear/misc/sgstream.hxx>
62 #include <simgear/props/props_io.hxx>
63 #include <simgear/scene/tgdb/userdata.hxx>
64
65 #include "mat.hxx"
66
67 #include "matlib.hxx"
68
69 SG_USING_NAMESPACE(std);
70 SG_USING_STD(string);
71
72 extern bool SGPointLightsUseSprites;
73 extern bool SGPointLightsEnhancedLighting;
74 extern bool SGPointLightsDistanceAttenuation;
75
76 // FIXME: should make this configurable
77 static const bool sprite_lighting = true;
78
79 // Constructor
80 SGMaterialLib::SGMaterialLib ( void ) {
81 }
82
83 // generate standard colored directional light environment texture map
84 static osg::Texture2D*
85 gen_standard_dir_light_map( int r, int g, int b, int alpha ) {
86     const int env_tex_res = 32;
87     int half_res = env_tex_res / 2;
88
89     osg::Image* image = new osg::Image;
90     image->allocateImage(env_tex_res, env_tex_res, 1,
91                          GL_RGBA, GL_UNSIGNED_BYTE);
92     for ( int i = 0; i < env_tex_res; ++i ) {
93         for ( int j = 0; j < env_tex_res; ++j ) {
94             double x = (i - half_res) / (double)half_res;
95             double y = (j - half_res) / (double)half_res;
96             double dist = sqrt(x*x + y*y);
97             if ( dist > 1.0 ) { dist = 1.0; }
98             double bright = cos( dist * SGD_PI_2 );
99             if ( bright < 0.3 ) { bright = 0.3; }
100             unsigned char* env_map = image->data(i, j);
101             env_map[0] = r;
102             env_map[1] = g;
103             env_map[2] = b;
104             env_map[3] = (int)(bright * alpha);
105         }
106     }
107
108     osg::Texture2D* texture = new osg::Texture2D;
109     texture->setImage(image);
110
111     return texture;
112 }
113
114
115 // generate standard colored directional light environment texture map
116 static osg::Texture2D*
117 gen_taxiway_dir_light_map( int r, int g, int b, int alpha ) {
118     const int env_tex_res = 32;
119     int half_res = env_tex_res / 2;
120
121     osg::Image* image = new osg::Image;
122     image->allocateImage(env_tex_res, env_tex_res, 1,
123                          GL_RGBA, GL_UNSIGNED_BYTE);
124
125     for ( int i = 0; i < env_tex_res; ++i ) {
126         for ( int j = 0; j < env_tex_res; ++j ) {
127             double x = (i - half_res) / (double)half_res;
128             double y = (j - half_res) / (double)half_res;
129             double tmp = sqrt(x*x + y*y);
130             double dist = tmp * tmp;
131             if ( dist > 1.0 ) { dist = 1.0; }
132             double bright = sin( dist * SGD_PI_2 );
133             if ( bright < 0.2 ) { bright = 0.2; }
134             unsigned char* env_map = image->data(i, j);
135             env_map[0] = r;
136             env_map[1] = g;
137             env_map[2] = b;
138             env_map[3] = (int)(bright * alpha);
139         }
140     }
141
142     osg::Texture2D* texture = new osg::Texture2D;
143     texture->setImage(image);
144
145     return texture;
146 }
147
148 static osg::Texture2D*
149 gen_standard_light_sprite( int r, int g, int b, int alpha ) {
150     const int env_tex_res = 32;
151     int half_res = env_tex_res / 2;
152
153     osg::Image* image = new osg::Image;
154     image->allocateImage(env_tex_res, env_tex_res, 1,
155                          GL_RGBA, GL_UNSIGNED_BYTE);
156
157     for ( int i = 0; i < env_tex_res; ++i ) {
158         for ( int j = 0; j < env_tex_res; ++j ) {
159             double x = (i - half_res) / (double)half_res;
160             double y = (j - half_res) / (double)half_res;
161             double dist = sqrt(x*x + y*y);
162             if ( dist > 1.0 ) { dist = 1.0; }
163             double bright = cos( dist * SGD_PI_2 );
164             if ( bright < 0.01 ) { bright = 0.0; }
165             unsigned char* env_map = image->data(i, j);
166             env_map[0] = r;
167             env_map[1] = g;
168             env_map[2] = b;
169             env_map[3] = (int)(bright * alpha);
170         }
171     }
172
173     osg::Texture2D* texture = new osg::Texture2D;
174     texture->setImage(image);
175
176     return texture;
177 }
178
179
180 // Load a library of material properties
181 bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char *season ) {
182
183     SGPropertyNode materials;
184
185     SG_LOG( SG_INPUT, SG_INFO, "Reading materials from " << mpath );
186     try {
187         readProperties( mpath, &materials );
188     } catch (const sg_exception &ex) {
189         SG_LOG( SG_INPUT, SG_ALERT, "Error reading materials: "
190                 << ex.getMessage() );
191         throw;
192     }
193
194     SGSharedPtr<SGMaterial> m;
195
196     int nMaterials = materials.nChildren();
197     for (int i = 0; i < nMaterials; i++) {
198         const SGPropertyNode * node = materials.getChild(i);
199         if (!strcmp(node->getName(), "material")) {
200             m = new SGMaterial( fg_root, node, season );
201
202             vector<SGPropertyNode_ptr>names = node->getChildren("name");
203             for ( unsigned int j = 0; j < names.size(); j++ ) {
204                 string name = names[j]->getStringValue();
205                 // cerr << "Material " << name << endl;
206                 matlib[name] = m;
207                 m->add_name(name);
208                 SG_LOG( SG_TERRAIN, SG_INFO, "  Loading material "
209                         << names[j]->getStringValue() );
210             }
211         } else {
212             SG_LOG(SG_INPUT, SG_WARN,
213                    "Skipping bad material entry " << node->getName());
214         }
215     }
216
217     osg::ref_ptr<osg::StateSet> lightStateSet = new osg::StateSet;
218     {
219 //       lightStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
220 //       lightStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
221       lightStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
222 //       lightStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
223
224       lightStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
225 //       lightStateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0));
226 //       lightStateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
227
228       osg::CullFace* cullFace = new osg::CullFace;
229       cullFace->setMode(osg::CullFace::BACK);
230       lightStateSet->setAttributeAndModes(cullFace, osg::StateAttribute::ON);
231
232       osg::BlendFunc* blendFunc = new osg::BlendFunc;
233       blendFunc->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
234       lightStateSet->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
235
236       osg::PolygonMode* polygonMode = new osg::PolygonMode;
237       polygonMode->setMode(osg::PolygonMode::FRONT, osg::PolygonMode::POINT);
238       lightStateSet->setAttribute(polygonMode);
239
240 //       if (SGPointLightsUseSprites) {
241         osg::PointSprite* pointSprite = new osg::PointSprite;
242         lightStateSet->setTextureAttributeAndModes(0, pointSprite, osg::StateAttribute::ON);
243 //       }
244
245 //       if (SGPointLightsDistanceAttenuation) {
246         osg::Point* point = new osg::Point;
247         point->setMinSize(2);
248         point->setSize(8);
249         point->setDistanceAttenuation(osg::Vec3(1.0, 0.001, 0.000001));
250         lightStateSet->setAttribute(point);
251 //       }
252
253       osg::PolygonOffset* polygonOffset = new osg::PolygonOffset;
254       polygonOffset->setFactor(-1);
255       polygonOffset->setUnits(-1);
256       lightStateSet->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON);
257       
258       osg::TexGen* texGen = new osg::TexGen;
259       texGen->setMode(osg::TexGen::SPHERE_MAP);
260       lightStateSet->setTextureAttribute(0, texGen);
261       lightStateSet->setTextureMode(0, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
262       lightStateSet->setTextureMode(0, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
263       osg::TexEnv* texEnv = new osg::TexEnv;
264       texEnv->setMode(osg::TexEnv::MODULATE);
265       lightStateSet->setTextureAttribute(0, texEnv);
266
267       osg::Material* material = new osg::Material;
268       lightStateSet->setAttribute(material);
269 //       lightStateSet->setMode(GL_COLOR_MATERIAL, osg::StateAttribute::OFF);
270     }
271     
272
273     // hard coded ground light state
274     osg::StateSet *gnd_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
275 //     if (SGPointLightsDistanceAttenuation) {
276     osg::Point* point = new osg::Point;
277       point->setMinSize(1);
278       point->setSize(2);
279       point->setMaxSize(4);
280       point->setDistanceAttenuation(osg::Vec3(1.0, 0.01, 0.0001));
281       while (gnd_lights->getAttribute(osg::StateAttribute::POINT)) {
282         gnd_lights->removeAttribute(osg::StateAttribute::POINT);
283       }
284       gnd_lights->setAttribute(point);
285 //     }
286     m = new SGMaterial( gnd_lights );
287     m->add_name("GROUND_LIGHTS");
288     matlib["GROUND_LIGHTS"] = m;
289
290     // hard coded runway white light state
291     osg::Texture2D* texture;
292     if ( sprite_lighting ) {
293       texture = gen_standard_light_sprite(235, 235, 195, 255);
294     } else {
295       texture = gen_standard_dir_light_map(235, 235, 195, 255);
296     }
297     osg::StateSet *rwy_white_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
298     rwy_white_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
299
300     m = new SGMaterial( rwy_white_lights );
301     m->add_name("RWY_WHITE_LIGHTS");
302     matlib["RWY_WHITE_LIGHTS"] = m;
303     // For backwards compatibility ... remove someday
304     m->add_name("RUNWAY_LIGHTS");
305     matlib["RUNWAY_LIGHTS"] = m;
306     m->add_name("RWY_LIGHTS");
307     matlib["RWY_LIGHTS"] = m;
308     // end of backwards compatitibilty
309
310     // hard coded runway medium intensity white light state
311     if ( sprite_lighting ) {
312       texture = gen_standard_light_sprite( 235, 235, 195, 205 );
313     } else {
314       texture = gen_standard_dir_light_map( 235, 235, 195, 205 );
315     }
316     osg::StateSet *rwy_white_medium_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
317     rwy_white_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
318
319     m = new SGMaterial( rwy_white_medium_lights );
320     m->add_name("RWY_WHITE_MEDIUM_LIGHTS");
321     matlib["RWY_WHITE_MEDIUM_LIGHTS"] = m;
322
323     // hard coded runway low intensity white light state
324     if ( sprite_lighting ) {
325       texture = gen_standard_light_sprite( 235, 235, 195, 155 );
326     } else {
327       texture = gen_standard_dir_light_map( 235, 235, 195, 155 );
328     }
329     osg::StateSet *rwy_white_low_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
330     rwy_white_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
331     m = new SGMaterial( rwy_white_low_lights );
332     m->add_name("RWY_WHITE_LOW_LIGHTS");
333     matlib["RWY_WHITE_LOW_LIGHTS"] = m;
334
335     // hard coded runway yellow light state
336     if ( sprite_lighting ) {
337       texture = gen_standard_light_sprite( 235, 215, 20, 255 );
338     } else {
339       texture = gen_standard_dir_light_map( 235, 215, 20, 255 );
340     }
341     osg::StateSet *rwy_yellow_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
342     rwy_yellow_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
343     m = new SGMaterial( rwy_yellow_lights );
344     m->add_name("RWY_YELLOW_LIGHTS");
345     matlib["RWY_YELLOW_LIGHTS"] = m;
346
347     // hard coded runway medium intensity yellow light state
348     if ( sprite_lighting ) {
349       texture = gen_standard_light_sprite( 235, 215, 20, 205 );
350     } else {
351       texture = gen_standard_dir_light_map( 235, 215, 20, 205 );
352     }
353     osg::StateSet *rwy_yellow_medium_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
354     rwy_yellow_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
355     m = new SGMaterial( rwy_yellow_medium_lights );
356     m->add_name("RWY_YELLOW_MEDIUM_LIGHTS");
357     matlib["RWY_YELLOW_MEDIUM_LIGHTS"] = m;
358
359     // hard coded runway low intensity yellow light state
360     if ( sprite_lighting ) {
361       texture = gen_standard_light_sprite( 235, 215, 20, 155 );
362     } else {
363       texture = gen_standard_dir_light_map( 235, 215, 20, 155 );
364     }
365     osg::StateSet *rwy_yellow_low_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
366     rwy_yellow_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
367     m = new SGMaterial( rwy_yellow_low_lights );
368     m->add_name("RWY_YELLOW_LOW_LIGHTS");
369     matlib["RWY_YELLOW_LOW_LIGHTS"] = m;
370
371     // hard coded runway red light state
372     if ( sprite_lighting ) {
373       texture = gen_standard_light_sprite( 235, 90, 90, 255 );
374     } else {
375       texture = gen_standard_dir_light_map( 235, 90, 90, 255 );
376     }
377     osg::StateSet *rwy_red_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
378     rwy_red_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
379     m = new SGMaterial( rwy_red_lights );
380     m->add_name("RWY_RED_LIGHTS");
381     matlib["RWY_RED_LIGHTS"] = m;
382
383     // hard coded medium intensity runway red light state
384     if ( sprite_lighting ) {
385       texture = gen_standard_light_sprite( 235, 90, 90, 205 );
386     } else {
387       texture = gen_standard_dir_light_map( 235, 90, 90, 205 );
388     }
389     osg::StateSet *rwy_red_medium_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
390     rwy_red_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
391     m = new SGMaterial( rwy_red_medium_lights );
392     m->add_name("RWY_RED_MEDIUM_LIGHTS");
393     matlib["RWY_RED_MEDIUM_LIGHTS"] = m;
394
395     // hard coded low intensity runway red light state
396     if ( sprite_lighting ) {
397       texture = gen_standard_light_sprite( 235, 90, 90, 155 );
398     } else {
399       texture = gen_standard_dir_light_map( 235, 90, 90, 155 );
400     }
401     osg::StateSet *rwy_red_low_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
402     rwy_red_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
403     m = new SGMaterial( rwy_red_low_lights );
404     m->add_name("RWY_RED_LOW_LIGHTS");
405     matlib["RWY_RED_LOW_LIGHTS"] = m;
406
407     // hard coded runway green light state
408     if ( sprite_lighting ) {
409       texture = gen_standard_light_sprite( 20, 235, 20, 255 );
410     } else {
411       texture = gen_standard_dir_light_map( 20, 235, 20, 255 );
412     }
413     osg::StateSet *rwy_green_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
414     rwy_green_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
415     m = new SGMaterial( rwy_green_lights );
416     m->add_name("RWY_GREEN_LIGHTS");
417     matlib["RWY_GREEN_LIGHTS"] = m;
418
419     // hard coded medium intensity runway green light state
420     if ( sprite_lighting ) {
421       texture = gen_standard_light_sprite( 20, 235, 20, 205 );
422     } else {
423       texture = gen_standard_dir_light_map( 20, 235, 20, 205 );
424     }
425     osg::StateSet *rwy_green_medium_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
426     rwy_green_medium_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
427     m = new SGMaterial( rwy_green_medium_lights );
428     m->add_name("RWY_GREEN_MEDIUM_LIGHTS");
429     matlib["RWY_GREEN_MEDIUM_LIGHTS"] = m;
430
431     // hard coded low intensity runway green light state
432     if ( sprite_lighting ) {
433       texture = gen_standard_light_sprite( 20, 235, 20, 155 );
434     } else {
435       texture = gen_standard_dir_light_map( 20, 235, 20, 155 );
436     }
437     osg::StateSet *rwy_green_low_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
438     rwy_green_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
439     m = new SGMaterial( rwy_green_low_lights );
440     m->add_name("RWY_GREEN_LOW_LIGHTS");
441     matlib["RWY_GREEN_LOW_LIGHTS"] = m;
442     m->add_name("RWY_GREEN_TAXIWAY_LIGHTS");
443     matlib["RWY_GREEN_TAXIWAY_LIGHTS"] = m;
444
445     // hard coded low intensity taxiway blue light state
446     if ( sprite_lighting ) {
447       texture = gen_standard_light_sprite( 90, 90, 235, 205 );
448     } else {
449       texture = gen_taxiway_dir_light_map( 90, 90, 235, 205 );
450     }
451     osg::StateSet *taxiway_blue_low_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
452     taxiway_blue_low_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
453     m = new SGMaterial( taxiway_blue_low_lights );
454     m->add_name("RWY_BLUE_TAXIWAY_LIGHTS");
455     matlib["RWY_BLUE_TAXIWAY_LIGHTS"] = m;
456
457     // hard coded runway vasi light state
458     if ( sprite_lighting ) {
459       texture = gen_standard_light_sprite( 235, 235, 195, 255 );
460     } else {
461       texture = gen_standard_dir_light_map( 235, 235, 195, 255 );
462     }
463     osg::StateSet *rwy_vasi_lights = static_cast<osg::StateSet*>(lightStateSet->clone(osg::CopyOp::DEEP_COPY_ALL));
464 //     if (SGPointLightsDistanceAttenuation) {
465       point = new osg::Point;
466       point->setMinSize(4);
467       point->setSize(10);
468       point->setDistanceAttenuation(osg::Vec3(1.0, 0.01, 0.0001));
469       while (rwy_vasi_lights->getAttribute(osg::StateAttribute::POINT)) {
470         rwy_vasi_lights->removeAttribute(osg::StateAttribute::POINT);
471       }
472       rwy_vasi_lights->setAttribute(point);
473 //     }
474     rwy_vasi_lights->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
475     m = new SGMaterial( rwy_vasi_lights );
476     m->add_name("RWY_VASI_LIGHTS");
477     matlib["RWY_VASI_LIGHTS"] = m;
478
479     return true;
480 }
481
482
483 // Load a library of material properties
484 bool SGMaterialLib::add_item ( const string &tex_path )
485 {
486     string material_name = tex_path;
487     int pos = tex_path.rfind( "/" );
488     material_name = material_name.substr( pos + 1 );
489
490     return add_item( material_name, tex_path );
491 }
492
493
494 // Load a library of material properties
495 bool SGMaterialLib::add_item ( const string &mat_name, const string &full_path )
496 {
497     int pos = full_path.rfind( "/" );
498     string tex_name = full_path.substr( pos + 1 );
499     string tex_path = full_path.substr( 0, pos );
500
501     SG_LOG( SG_TERRAIN, SG_INFO, "  Loading material " 
502             << mat_name << " (" << full_path << ")");
503
504     matlib[mat_name] = new SGMaterial( full_path );
505     matlib[mat_name]->add_name(mat_name);
506
507     return true;
508 }
509
510
511 // Load a library of material properties
512 bool SGMaterialLib::add_item ( const string &mat_name, osg::StateSet *state )
513 {
514     matlib[mat_name] = new SGMaterial( state );
515     matlib[mat_name]->add_name(mat_name);
516
517     SG_LOG( SG_TERRAIN, SG_INFO, "  Loading material given a premade "
518             << "osg::StateSet = " << mat_name );
519
520     return true;
521 }
522
523
524 // find a material record by material name
525 SGMaterial *SGMaterialLib::find( const string& material ) {
526     SGMaterial *result = NULL;
527     material_map_iterator it = matlib.find( material );
528     if ( it != end() ) {
529         result = it->second;
530         return result;
531     }
532
533     return NULL;
534 }
535
536
537 // Destructor
538 SGMaterialLib::~SGMaterialLib ( void ) {
539 }
540
541
542 // Load one pending "deferred" texture.  Return true if a texture
543 // loaded successfully, false if no pending, or error.
544 void SGMaterialLib::load_next_deferred() {
545     // container::iterator it = begin();
546     for ( material_map_iterator it = begin(); it != end(); it++ ) {
547         /* we don't need the key, but here's how we'd get it if we wanted it. */
548         // const string &key = it->first;
549         SGMaterial *slot = it->second;
550         if (slot->load_texture())
551           return;
552     }
553 }
554
555 // Return the material from that given leaf
556 const SGMaterial* SGMaterialLib::findMaterial(const osg::Node* leaf) const
557 {
558   if (!leaf)
559     return 0;
560   
561   const osg::Referenced* base = leaf->getUserData();
562   if (!base)
563     return 0;
564
565   const SGMaterialUserData* matUserData
566     = dynamic_cast<const SGMaterialUserData*>(base);
567   if (!matUserData)
568     return 0;
569
570   return matUserData->getMaterial();
571 }