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