]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/mat.cxx
Modified Files:
[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  - 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 #include <simgear/compiler.h>
29
30 #include <string.h>
31 #include <map>
32 SG_USING_STD(map);
33
34 #include <plib/ul.h>
35
36 #ifdef SG_MATH_EXCEPTION_CLASH
37 #  include <math.h>
38 #endif
39
40 #include <osg/CullFace>
41 #include <osg/Material>
42 #include <osg/ShadeModel>
43 #include <osg/TexEnv>
44 #include <osg/Texture2D>
45 #include <osgDB/ReadFile>
46
47 #include <simgear/debug/logstream.hxx>
48 #include <simgear/misc/sg_path.hxx>
49 #include <simgear/misc/sgstream.hxx>
50
51 #include <simgear/scene/model/model.hxx>
52 #include "mat.hxx"
53
54 static map<string, osg::ref_ptr<osg::Texture2D> > _tex_cache;
55
56 \f
57 ////////////////////////////////////////////////////////////////////////
58 // Constructors and destructor.
59 ////////////////////////////////////////////////////////////////////////
60
61
62 SGMaterial::SGMaterial( const string &fg_root, const SGPropertyNode *props, const char *season )
63 {
64     init();
65     read_properties( fg_root, props, season );
66     build_state( false );
67 }
68
69 SGMaterial::SGMaterial( const string &texpath )
70 {
71     init();
72
73     _internal_state st( NULL, texpath, false );
74     _status.push_back( st );
75
76     build_state( true );
77 }
78
79 SGMaterial::SGMaterial( osg::StateSet *s )
80 {
81     init();
82     set_state( s );
83 }
84
85 SGMaterial::~SGMaterial (void)
86 {
87 }
88
89
90 \f
91 ////////////////////////////////////////////////////////////////////////
92 // Public methods.
93 ////////////////////////////////////////////////////////////////////////
94
95 void
96 SGMaterial::read_properties( const string &fg_root, const SGPropertyNode * props, const char *season )
97 {
98                                 // Gather the path(s) to the texture(s)
99   vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
100   for (unsigned int i = 0; i < textures.size(); i++)
101   {
102     string tname = textures[i]->getStringValue();
103     string otname = tname;
104     if (season && strncmp(season, "summer", 6))
105     {
106         if (tname.substr(0,7) == "Terrain")
107             tname.insert(7,"."+string(season));
108     }
109
110     if (tname == "") {
111         tname = "unknown.rgb";
112     }
113
114     SGPath tpath( fg_root );
115     tpath.append("Textures.high");
116     tpath.append(tname);
117     if ( !ulFileExists(tpath.c_str()) ) {
118       tpath = SGPath( fg_root );
119       tpath.append("Textures");
120       tpath.append(tname);
121     }
122
123     if ( ulFileExists(tpath.c_str()) ) {
124       _internal_state st( NULL, tpath.str(), false );
125       _status.push_back( st );
126     }
127   }
128
129   if (textures.size() == 0) {
130     string tname = "unknown.rgb";
131     SGPath tpath( fg_root );
132     tpath.append("Textures");
133     tpath.append("Terrain");
134     tpath.append(tname);
135     _internal_state st( NULL, tpath.str(), true );
136     _status.push_back( st );
137   }
138
139   xsize = props->getDoubleValue("xsize", 0.0);
140   ysize = props->getDoubleValue("ysize", 0.0);
141   wrapu = props->getBoolValue("wrapu", true);
142   wrapv = props->getBoolValue("wrapv", true);
143   mipmap = props->getBoolValue("mipmap", true);
144   light_coverage = props->getDoubleValue("light-coverage", 0.0);
145
146   // surface values for use with ground reactions
147   solid = props->getBoolValue("solid", true);
148   friction_factor = props->getDoubleValue("friction-factor", 1.0);
149   rolling_friction = props->getDoubleValue("rolling-friction", 0.02);
150   bumpiness = props->getDoubleValue("bumpiness", 0.0);
151   load_resistence = props->getDoubleValue("load-resistence", 1e30);
152
153   // Taken from default values as used in ac3d
154   ambient[0] = props->getDoubleValue("ambient/r", 0.2);
155   ambient[1] = props->getDoubleValue("ambient/g", 0.2);
156   ambient[2] = props->getDoubleValue("ambient/b", 0.2);
157   ambient[3] = props->getDoubleValue("ambient/a", 1.0);
158
159   diffuse[0] = props->getDoubleValue("diffuse/r", 0.8);
160   diffuse[1] = props->getDoubleValue("diffuse/g", 0.8);
161   diffuse[2] = props->getDoubleValue("diffuse/b", 0.8);
162   diffuse[3] = props->getDoubleValue("diffuse/a", 1.0);
163
164   specular[0] = props->getDoubleValue("specular/r", 0.0);
165   specular[1] = props->getDoubleValue("specular/g", 0.0);
166   specular[2] = props->getDoubleValue("specular/b", 0.0);
167   specular[3] = props->getDoubleValue("specular/a", 1.0);
168
169   emission[0] = props->getDoubleValue("emissive/r", 0.0);
170   emission[1] = props->getDoubleValue("emissive/g", 0.0);
171   emission[2] = props->getDoubleValue("emissive/b", 0.0);
172   emission[3] = props->getDoubleValue("emissive/a", 1.0);
173
174   shininess = props->getDoubleValue("shininess", 1.0);
175
176   vector<SGPropertyNode_ptr> object_group_nodes =
177     ((SGPropertyNode *)props)->getChildren("object-group");
178   for (unsigned int i = 0; i < object_group_nodes.size(); i++)
179     object_groups.push_back(new SGMatModelGroup(object_group_nodes[i]));
180
181   // read glyph table for taxi-/runway-signs
182   vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
183   for (unsigned int i = 0; i < glyph_nodes.size(); i++) {
184     const char *name = glyph_nodes[i]->getStringValue("name");
185     if (name)
186       glyphs[name] = new SGMaterialGlyph(glyph_nodes[i]);
187   }
188 }
189
190
191 \f
192 ////////////////////////////////////////////////////////////////////////
193 // Private methods.
194 ////////////////////////////////////////////////////////////////////////
195
196 void 
197 SGMaterial::init ()
198 {
199     _status.clear();
200     _current_ptr = 0;
201     xsize = 0;
202     ysize = 0;
203     wrapu = true;
204     wrapv = true;
205
206     mipmap = true;
207     light_coverage = 0.0;
208
209     solid = true;
210     friction_factor = 1;
211     rolling_friction = 0.02;
212     bumpiness = 0;
213     load_resistence = 1e30;
214
215     shininess = 1.0;
216     for (int i = 0; i < 4; i++) {
217         ambient[i]  = (i < 3) ? 0.2 : 1.0;
218         specular[i] = (i < 3) ? 0.0 : 1.0;
219         diffuse[i]  = (i < 3) ? 0.8 : 1.0;
220         emission[i] = (i < 3) ? 0.0 : 1.0;
221     }
222 }
223
224 bool
225 SGMaterial::load_texture ( int n )
226 {
227     int i   = (n >= 0) ? n   : 0 ;
228     int end = (n >= 0) ? n+1 : _status.size();
229
230     for (; i < end; i++)
231     {
232         if ( !_status[i].texture_loaded ) {
233             SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
234                                           << _status[i].texture_path );
235             assignTexture(_status[i].state.get(), _status[i].texture_path,
236                                          wrapu, wrapv, mipmap );
237             _status[i].texture_loaded = true;
238        }
239     }
240     return true;
241 }
242
243 osg::StateSet *
244 SGMaterial::get_state (int n) const
245 {
246     if (_status.size() == 0) {
247         SG_LOG( SG_GENERAL, SG_WARN, "No state available.");
248         return NULL;
249     }
250
251     osg::StateSet *st = (n >= 0) ? _status[n].state.get()
252                              : _status[_current_ptr].state.get();
253     _current_ptr += 1;
254     if (_current_ptr >= _status.size())
255         _current_ptr = 0;
256
257     return st;
258 }
259
260
261 void 
262 SGMaterial::build_state( bool defer_tex_load )
263 {
264     for (unsigned int i = 0; i < _status.size(); i++)
265     {
266         osg::StateSet *stateSet = new osg::StateSet;
267
268         // Set up the textured state
269         osg::ShadeModel* shadeModel = new osg::ShadeModel;
270         shadeModel->setMode(osg::ShadeModel::SMOOTH);
271         stateSet->setAttributeAndModes(shadeModel, osg::StateAttribute::ON);
272
273         osg::CullFace* cullFace = new osg::CullFace;
274         cullFace->setMode(osg::CullFace::BACK);
275         stateSet->setAttributeAndModes(cullFace, osg::StateAttribute::ON);
276
277         stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
278
279         if ( !defer_tex_load ) {
280             SG_LOG(SG_INPUT, SG_INFO, "    " << _status[i].texture_path );
281             assignTexture( stateSet, _status[i].texture_path, wrapu, wrapv );
282             _status[i].texture_loaded = true;
283         } else {
284             _status[i].texture_loaded = false;
285         }
286
287         osg::Material* material = new osg::Material;
288         material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
289         material->setAmbient(osg::Material::FRONT_AND_BACK, ambient.osg());
290         material->setDiffuse(osg::Material::FRONT_AND_BACK, diffuse.osg());
291         material->setSpecular(osg::Material::FRONT_AND_BACK, specular.osg());
292         material->setEmission(osg::Material::FRONT_AND_BACK, emission.osg());
293         material->setShininess(osg::Material::FRONT_AND_BACK, shininess );
294         stateSet->setAttribute(material);
295
296         if (ambient[3] < 1 || diffuse[3] < 1 ||
297             specular[3] < 1 || emission[3] < 1) {
298           stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
299           stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
300         } else {
301           stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
302           stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
303         }
304
305         _status[i].state = stateSet;
306     }
307 }
308
309
310 void SGMaterial::set_state( osg::StateSet *s )
311 {
312     _status.push_back( _internal_state( s, "", true ) );
313 }
314
315 void SGMaterial::assignTexture( osg::StateSet *state, const std::string &fname,
316                  int _wrapu, int _wrapv, int _mipmap )
317 {
318    map<string, osg::ref_ptr<osg::Texture2D> >::iterator _tex_cache_iter;
319    _tex_cache_iter = _tex_cache.find(fname);
320    if (_tex_cache_iter == _tex_cache.end())
321    {
322       osg::Texture2D* texture = SGLoadTexture2D(fname, _wrapu, _wrapv,
323                                                 mipmap ? -1 : 0);
324       state->setTextureAttributeAndModes(0, texture);
325       _tex_cache[fname] = texture;
326    }
327    else
328    {
329       state->setTextureAttributeAndModes(0, _tex_cache_iter->second.get());
330       // cout << "Cache hit: " << fname << endl;
331    }
332    osg::TexEnv* texEnv = new osg::TexEnv;
333    texEnv->setMode(osg::TexEnv::MODULATE);
334    state->setTextureAttributeAndModes(0, texEnv);
335 }
336
337 SGMaterialGlyph* SGMaterial::get_glyph (const string& name) const
338 {
339   map<string, SGSharedPtr<SGMaterialGlyph> >::const_iterator it;
340   it = glyphs.find(name);
341   if (it == glyphs.end())
342     return 0;
343
344   return it->second;
345 }
346
347 \f
348 ////////////////////////////////////////////////////////////////////////
349 // SGMaterialGlyph.
350 ////////////////////////////////////////////////////////////////////////
351
352 SGMaterialGlyph::SGMaterialGlyph(SGPropertyNode *p) :
353     _left(p->getDoubleValue("left", 0.0)),
354     _right(p->getDoubleValue("right", 1.0))
355 {
356 }
357
358
359 // end of mat.cxx