]> 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   filtering = props->getDoubleValue("filtering", 1.0);
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_resistence = props->getDoubleValue("load-resistence", 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     filtering = 1.0f;
209     light_coverage = 0.0;
210
211     solid = true;
212     friction_factor = 1;
213     rolling_friction = 0.02;
214     bumpiness = 0;
215     load_resistence = 1e30;
216
217     shininess = 1.0;
218     for (int i = 0; i < 4; i++) {
219         ambient[i]  = (i < 3) ? 0.2 : 1.0;
220         specular[i] = (i < 3) ? 0.0 : 1.0;
221         diffuse[i]  = (i < 3) ? 0.8 : 1.0;
222         emission[i] = (i < 3) ? 0.0 : 1.0;
223     }
224 }
225
226 bool
227 SGMaterial::load_texture ( int n )
228 {
229     int i   = (n >= 0) ? n   : 0 ;
230     int end = (n >= 0) ? n+1 : _status.size();
231
232     for (; i < end; i++)
233     {
234         if ( !_status[i].texture_loaded ) {
235             SG_LOG( SG_GENERAL, SG_INFO, "Loading deferred texture "
236                                           << _status[i].texture_path );
237             assignTexture(_status[i].state.get(), _status[i].texture_path,
238                                          wrapu, wrapv, mipmap, filtering );
239             _status[i].texture_loaded = true;
240        }
241     }
242     return true;
243 }
244
245 osg::StateSet *
246 SGMaterial::get_state (int n) const
247 {
248     if (_status.size() == 0) {
249         SG_LOG( SG_GENERAL, SG_WARN, "No state available.");
250         return NULL;
251     }
252
253     osg::StateSet *st = (n >= 0) ? _status[n].state.get()
254                              : _status[_current_ptr].state.get();
255     _current_ptr += 1;
256     if (_current_ptr >= _status.size())
257         _current_ptr = 0;
258
259     return st;
260 }
261
262
263 void 
264 SGMaterial::build_state( bool defer_tex_load )
265 {
266     for (unsigned int i = 0; i < _status.size(); i++)
267     {
268         osg::StateSet *stateSet = new osg::StateSet;
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, 1, filtering );
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, float filtering )
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, _wrapu, _wrapv,
328                                                 mipmap ? -1 : 0);
329       texture->setMaxAnisotropy( filtering);
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
365 // end of mat.cxx