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