]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/TextureBuilder.cxx
Merge branch 'ehofman/model'
[simgear.git] / simgear / scene / material / TextureBuilder.cxx
1 // Copyright (C) 2009  Tim Moore timoore@redhat.com
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
17 #ifdef HAVE_CONFIG_H
18 #  include <simgear_config.h>
19 #endif
20
21 #include "TextureBuilder.hxx"
22
23 #include "Pass.hxx"
24
25 #include <osg/TexEnv>
26 #include <osg/TexEnvCombine>
27 #include <osg/TexGen>
28 #include <osg/Texture1D>
29 #include <osg/Texture2D>
30 #include <osg/Texture3D>
31 #include <osg/TextureRectangle>
32 #include <osg/TextureCubeMap>
33 #include <osgDB/FileUtils>
34
35 #include <boost/lexical_cast.hpp>
36 #include <boost/tuple/tuple.hpp>
37 #include <boost/tuple/tuple_comparison.hpp>
38
39 #include <simgear/scene/model/SGReaderWriterXMLOptions.hxx>
40 #include <simgear/scene/util/SGSceneFeatures.hxx>
41 #include <simgear/scene/util/StateAttributeFactory.hxx>
42 #include <simgear/math/SGMath.hxx>
43 #include <simgear/structure/OSGUtils.hxx>
44
45 #include "Noise.hxx"
46
47 namespace simgear
48 {
49 using namespace std;
50 using namespace osg;
51
52 using namespace effect;
53
54 TexEnvCombine* buildTexEnvCombine(Effect* effect,
55                                   const SGPropertyNode* envProp,
56                                   const SGReaderWriterXMLOptions* options);
57 TexGen* buildTexGen(Effect* Effect, const SGPropertyNode* tgenProp);
58
59 // Hack to force inclusion of TextureBuilder.cxx in library
60 osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type,
61                                             const SGPropertyNode*props,
62                                             const SGReaderWriterXMLOptions*
63                                             options)
64 {
65     return EffectBuilder<Texture>::buildFromType(effect, type, props, options);
66 }
67
68 typedef boost::tuple<string, Texture::FilterMode, Texture::FilterMode,
69                      Texture::WrapMode, Texture::WrapMode, Texture::WrapMode,
70                      string> TexTuple;
71
72 EffectNameValue<TexEnv::Mode> texEnvModesInit[] =
73 {
74     {"add", TexEnv::ADD},
75     {"blend", TexEnv::BLEND},
76     {"decal", TexEnv::DECAL},
77     {"modulate", TexEnv::MODULATE},
78     {"replace", TexEnv::REPLACE}
79 };
80 EffectPropertyMap<TexEnv::Mode> texEnvModes(texEnvModesInit);
81
82 TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop)
83 {
84     const SGPropertyNode* modeProp = getEffectPropertyChild(effect, prop,
85                                                             "mode");
86     const SGPropertyNode* colorProp = getEffectPropertyChild(effect, prop,
87                                                              "color");
88     if (!modeProp)
89         return 0;
90     TexEnv::Mode mode = TexEnv::MODULATE;
91     findAttr(texEnvModes, modeProp, mode);
92     if (mode == TexEnv::MODULATE) {
93         return StateAttributeFactory::instance()->getStandardTexEnv();
94     }
95     TexEnv* env = new TexEnv(mode);
96     if (colorProp)
97         env->setColor(toOsg(colorProp->getValue<SGVec4d>()));
98     return env;
99  }
100
101
102 void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
103                                         const SGPropertyNode* prop,
104                                         const SGReaderWriterXMLOptions* options)
105 {
106     if (!isAttributeActive(effect, prop))
107         return;
108     // Decode the texture unit
109     int unit = 0;
110     const SGPropertyNode* pUnit = prop->getChild("unit");
111     if (pUnit) {
112         unit = pUnit->getValue<int>();
113     } else {
114         const SGPropertyNode* pName = prop->getChild("name");
115         if (pName)
116             try {
117                 unit = boost::lexical_cast<int>(pName->getStringValue());
118             } catch (boost::bad_lexical_cast& lex) {
119                 SG_LOG(SG_INPUT, SG_ALERT, "can't decode name as texture unit "
120                        << lex.what());
121             }
122     }
123     const SGPropertyNode* pType = getEffectPropertyChild(effect, prop, "type");
124     string type;
125     if (!pType)
126         type = "2d";
127     else
128         type = pType->getStringValue();
129     Texture* texture = 0;
130     try {
131         texture = TextureBuilder::buildFromType(effect, type, prop,
132                                                 options);
133     }
134     catch (BuilderException& e) {
135         SG_LOG(SG_INPUT, SG_ALERT, "No image file for texture, using white ");
136         texture = StateAttributeFactory::instance()->getWhiteTexture();
137     }
138     pass->setTextureAttributeAndModes(unit, texture);
139     const SGPropertyNode* envProp = prop->getChild("environment");
140     if (envProp) {
141         TexEnv* env = buildTexEnv(effect, envProp);
142         if (env)
143             pass->setTextureAttributeAndModes(unit, env);
144     }
145     const SGPropertyNode* combineProp = prop->getChild("texenv-combine");
146     TexEnvCombine* combiner = 0;
147     if (combineProp && ((combiner = buildTexEnvCombine(effect, combineProp,
148                                                        options))))
149         pass->setTextureAttributeAndModes(unit, combiner);
150     const SGPropertyNode* tgenProp = prop->getChild("texgen");
151     TexGen* tgen = 0;
152     if (tgenProp && (tgen = buildTexGen(effect, tgenProp)))
153         pass->setTextureAttributeAndModes(unit, tgen);
154 }
155
156 // InstallAttributeBuilder call is in Effect.cxx to force this file to
157 // be linked in.
158
159 namespace
160 {
161 EffectNameValue<Texture::FilterMode> filterModesInit[] =
162 {
163     { "linear", Texture::LINEAR },
164     { "linear-mipmap-linear", Texture::LINEAR_MIPMAP_LINEAR},
165     { "linear-mipmap-nearest", Texture::LINEAR_MIPMAP_NEAREST},
166     { "nearest", Texture::NEAREST},
167     { "nearest-mipmap-linear", Texture::NEAREST_MIPMAP_LINEAR},
168     { "nearest-mipmap-nearest", Texture::NEAREST_MIPMAP_NEAREST}
169 };
170 EffectPropertyMap<Texture::FilterMode> filterModes(filterModesInit);
171
172 EffectNameValue<Texture::WrapMode> wrapModesInit[] =
173 {
174     {"clamp", Texture::CLAMP},
175     {"clamp-to-border", Texture::CLAMP_TO_BORDER},
176     {"clamp-to-edge", Texture::CLAMP_TO_EDGE},
177     {"mirror", Texture::MIRROR},
178     {"repeat", Texture::REPEAT}
179 };
180 EffectPropertyMap<Texture::WrapMode> wrapModes(wrapModesInit);
181
182
183 TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props,
184                       const SGReaderWriterXMLOptions* options,
185                       const string& texType)
186 {
187     Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR;
188     const SGPropertyNode* ep = 0;
189     if ((ep = getEffectPropertyChild(effect, props, "filter")))
190         findAttr(filterModes, ep, minFilter);
191     Texture::FilterMode magFilter = Texture::LINEAR;
192     if ((ep = getEffectPropertyChild(effect, props, "mag-filter")))
193         findAttr(filterModes, ep, magFilter);
194     const SGPropertyNode* pWrapS
195         = getEffectPropertyChild(effect, props, "wrap-s");
196     Texture::WrapMode sWrap = Texture::CLAMP;
197     if (pWrapS)
198         findAttr(wrapModes, pWrapS, sWrap);
199     const SGPropertyNode* pWrapT
200         = getEffectPropertyChild(effect, props, "wrap-t");
201     Texture::WrapMode tWrap = Texture::CLAMP;
202     if (pWrapT)
203         findAttr(wrapModes, pWrapT, tWrap);
204     const SGPropertyNode* pWrapR
205         = getEffectPropertyChild(effect, props, "wrap-r");
206     Texture::WrapMode rWrap = Texture::CLAMP;
207     if (pWrapR)
208         findAttr(wrapModes, pWrapR, rWrap);
209     const SGPropertyNode* pImage
210         = getEffectPropertyChild(effect, props, "image");
211     string imageName;
212     if (pImage)
213         imageName = pImage->getStringValue();
214     string absFileName = osgDB::findDataFile(imageName, options);
215     return TexTuple(absFileName, minFilter, magFilter, sWrap, tWrap, rWrap,
216                     texType);
217 }
218
219 void setAttrs(const TexTuple& attrs, Texture* tex,
220               const SGReaderWriterXMLOptions* options)
221 {
222     const string& imageName = attrs.get<0>();
223     if (imageName.empty()) {
224         throw BuilderException("no image file");
225     } else {
226         osgDB::ReaderWriter::ReadResult result
227             = osgDB::Registry::instance()->readImage(imageName, options);
228         if (result.success()) {
229             osg::Image* image = result.getImage();
230             tex->setImage(GL_FRONT_AND_BACK, image);
231             int s = image->s();
232             int t = image->t();
233             if (s <= t && 32 <= s) {
234                 SGSceneFeatures::instance()->setTextureCompression(tex);
235             } else if (t < s && 32 <= t) {
236                 SGSceneFeatures::instance()->setTextureCompression(tex);
237             }
238             tex->setMaxAnisotropy(SGSceneFeatures::instance()
239                                   ->getTextureFilter());
240         } else {
241             SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file "
242                    << imageName);
243         }
244     }
245     // texture->setDataVariance(osg::Object::STATIC);
246     tex->setFilter(Texture::MIN_FILTER, attrs.get<1>());
247     tex->setFilter(Texture::MAG_FILTER, attrs.get<2>());
248     tex->setWrap(Texture::WRAP_S, attrs.get<3>());
249     tex->setWrap(Texture::WRAP_T, attrs.get<4>());
250     tex->setWrap(Texture::WRAP_R, attrs.get<5>());
251 }
252 }
253
254 template<typename T>
255 class TexBuilder : public TextureBuilder
256 {
257 public:
258     TexBuilder(const string& texType) : _type(texType) {}
259     Texture* build(Effect* effect, const SGPropertyNode*,
260                    const SGReaderWriterXMLOptions* options);
261 protected:
262     typedef map<TexTuple, ref_ptr<T> > TexMap;
263     TexMap texMap;
264     const string _type;
265 };
266
267 template<typename T>
268 Texture* TexBuilder<T>::build(Effect* effect, const SGPropertyNode* props,
269                               const SGReaderWriterXMLOptions* options)
270 {
271     TexTuple attrs = makeTexTuple(effect, props, options, _type);
272     typename TexMap::iterator itr = texMap.find(attrs);
273     if (itr != texMap.end())
274         return itr->second.get();
275     T* tex = new T;
276     setAttrs(attrs, tex, options);
277     texMap.insert(make_pair(attrs, tex));
278     return tex;
279 }
280
281
282 namespace
283 {
284 TextureBuilder::Registrar install1D("1d", new TexBuilder<Texture1D>("1d"));
285 TextureBuilder::Registrar install2D("2d", new TexBuilder<Texture2D>("2d"));
286 TextureBuilder::Registrar install3D("3d", new TexBuilder<Texture3D>("3d"));
287 }
288
289 class WhiteTextureBuilder : public TextureBuilder
290 {
291 public:
292     Texture* build(Effect* effect, const SGPropertyNode*,
293                    const SGReaderWriterXMLOptions* options);
294 };
295
296 Texture* WhiteTextureBuilder::build(Effect* effect, const SGPropertyNode*,
297                                     const SGReaderWriterXMLOptions* options)
298 {
299     return StateAttributeFactory::instance()->getWhiteTexture();
300 }
301
302 namespace
303 {
304 TextureBuilder::Registrar installWhite("white", new WhiteTextureBuilder);
305 }
306
307 class TransparentTextureBuilder : public TextureBuilder
308 {
309 public:
310     Texture* build(Effect* effect, const SGPropertyNode*,
311                    const SGReaderWriterXMLOptions* options);
312 };
313
314 Texture* TransparentTextureBuilder::build(Effect* effect, const SGPropertyNode*,
315                                     const SGReaderWriterXMLOptions* options)
316 {
317     return StateAttributeFactory::instance()->getTransparentTexture();
318 }
319
320 namespace
321 {
322 TextureBuilder::Registrar installTransparent("transparent",
323                                              new TransparentTextureBuilder);
324 }
325
326 osg::Image* make3DNoiseImage(int texSize)
327 {
328     osg::Image* image = new osg::Image;
329     image->setImage(texSize, texSize, texSize,
330                     4, GL_RGBA, GL_UNSIGNED_BYTE,
331                     new unsigned char[4 * texSize * texSize * texSize],
332                     osg::Image::USE_NEW_DELETE);
333
334     const int startFrequency = 4;
335     const int numOctaves = 4;
336
337     int f, i, j, k, inc;
338     double ni[3];
339     double inci, incj, inck;
340     int frequency = startFrequency;
341     GLubyte *ptr;
342     double amp = 0.5;
343
344     osg::notify(osg::WARN) << "creating 3D noise texture... ";
345
346     for (f = 0, inc = 0; f < numOctaves; ++f, frequency *= 2, ++inc, amp *= 0.5)
347     {
348         SetNoiseFrequency(frequency);
349         ptr = image->data();
350         ni[0] = ni[1] = ni[2] = 0;
351
352         inci = 1.0 / (texSize / frequency);
353         for (i = 0; i < texSize; ++i, ni[0] += inci)
354         {
355             incj = 1.0 / (texSize / frequency);
356             for (j = 0; j < texSize; ++j, ni[1] += incj)
357             {
358                 inck = 1.0 / (texSize / frequency);
359                 for (k = 0; k < texSize; ++k, ni[2] += inck, ptr += 4)
360                 {
361                     *(ptr+inc) = (GLubyte) (((noise3(ni) + 1.0) * amp) * 128.0);
362                 }
363             }
364         }
365     }
366
367     osg::notify(osg::WARN) << "DONE" << std::endl;
368     return image;
369 }
370
371 class NoiseBuilder : public TextureBuilder
372 {
373 public:
374     Texture* build(Effect* effect, const SGPropertyNode*,
375                    const SGReaderWriterXMLOptions* options);
376 protected:
377     typedef map<int, ref_ptr<Texture3D> > NoiseMap;
378     NoiseMap _noises;
379 };
380
381 Texture* NoiseBuilder::build(Effect* effect, const SGPropertyNode* props,
382                              const SGReaderWriterXMLOptions* options)
383 {
384     int texSize = 64;
385     const SGPropertyNode* sizeProp = getEffectPropertyChild(effect, props,
386                                                             "size");
387     if (sizeProp)
388         texSize = sizeProp->getValue<int>();
389     NoiseMap::iterator itr = _noises.find(texSize);
390     if (itr != _noises.end())
391         return itr->second.get();
392     Texture3D* noiseTexture = new osg::Texture3D;
393     noiseTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture3D::LINEAR);
394     noiseTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture3D::LINEAR);
395     noiseTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture3D::REPEAT);
396     noiseTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture3D::REPEAT);
397     noiseTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture3D::REPEAT);
398     noiseTexture->setImage( make3DNoiseImage(texSize) );
399     _noises.insert(make_pair(texSize, noiseTexture));
400     return noiseTexture;
401 }
402
403 namespace
404 {
405 TextureBuilder::Registrar installNoise("noise", new NoiseBuilder);
406 }
407
408
409 // Image names for all sides
410 typedef boost::tuple<string, string, string, string, string, string> CubeMapTuple;
411
412 CubeMapTuple makeCubeMapTuple(Effect* effect, const SGPropertyNode* props)
413 {
414     const SGPropertyNode* ep = 0;
415
416     string positive_x;
417     if ((ep = getEffectPropertyChild(effect, props, "positive-x")))
418         positive_x = ep->getStringValue();
419     string negative_x;
420     if ((ep = getEffectPropertyChild(effect, props, "negative-x")))
421         negative_x = ep->getStringValue();
422     string positive_y;
423     if ((ep = getEffectPropertyChild(effect, props, "positive-y")))
424         positive_y = ep->getStringValue();
425     string negative_y;
426     if ((ep = getEffectPropertyChild(effect, props, "negative-y")))
427         negative_y = ep->getStringValue();
428     string positive_z;
429     if ((ep = getEffectPropertyChild(effect, props, "positive-z")))
430         positive_z = ep->getStringValue();
431     string negative_z;
432     if ((ep = getEffectPropertyChild(effect, props, "negative-z")))
433         negative_z = ep->getStringValue();
434     return CubeMapTuple(positive_x, negative_x, positive_y, negative_y, positive_z, negative_z);
435 }
436
437
438 class CubeMapBuilder : public TextureBuilder
439 {
440 public:
441     Texture* build(Effect* effect, const SGPropertyNode*,
442                    const SGReaderWriterXMLOptions* options);
443 protected:
444     typedef map<CubeMapTuple, ref_ptr<TextureCubeMap> > CubeMap;
445     CubeMap _cubemaps;
446 };
447
448 Texture* CubeMapBuilder::build(Effect* effect, const SGPropertyNode* props,
449                              const SGReaderWriterXMLOptions* options)
450 {
451     // First check that there is a <images> tag
452     const SGPropertyNode* texturesProp = getEffectPropertyChild(effect, props, "images");
453     if (!texturesProp) {
454         throw BuilderException("no <images> for cube map");
455         return NULL; // This is redundant
456     }
457
458     CubeMapTuple _tuple = makeCubeMapTuple(effect, texturesProp);
459
460     CubeMap::iterator itr = _cubemaps.find(_tuple);
461     if (itr != _cubemaps.end())
462         return itr->second.get();
463
464     TextureCubeMap* cubeTexture = new osg::TextureCubeMap;
465
466     // TODO: Read these from effect file? Maybe these are sane for all cuebmaps?
467     cubeTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
468     cubeTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture::LINEAR);
469     cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
470     cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
471     cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
472
473     osgDB::ReaderWriter::ReadResult result =
474                 osgDB::Registry::instance()->readImage(_tuple.get<0>(), options);
475     if(result.success()) {
476         osg::Image* image = result.getImage();
477         cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image);
478     }
479     result = osgDB::Registry::instance()->readImage(_tuple.get<1>(), options);
480     if(result.success()) {
481         osg::Image* image = result.getImage();
482         cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image);
483     }
484     result = osgDB::Registry::instance()->readImage(_tuple.get<2>(), options);
485     if(result.success()) {
486         osg::Image* image = result.getImage();
487         cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image);
488     }
489     result = osgDB::Registry::instance()->readImage(_tuple.get<3>(), options);
490     if(result.success()) {
491         osg::Image* image = result.getImage();
492         cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image);
493     }
494     result = osgDB::Registry::instance()->readImage(_tuple.get<4>(), options);
495     if(result.success()) {
496         osg::Image* image = result.getImage();
497         cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image);
498     }
499     result = osgDB::Registry::instance()->readImage(_tuple.get<5>(), options);
500     if(result.success()) {
501         osg::Image* image = result.getImage();
502         cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image);
503     }
504
505     _cubemaps[_tuple] = cubeTexture;
506
507     return cubeTexture;
508 }
509
510 namespace {
511 TextureBuilder::Registrar installCubeMap("cubemap", new CubeMapBuilder);
512 }
513
514
515
516 EffectNameValue<TexEnvCombine::CombineParam> combineParamInit[] =
517 {
518     {"replace", TexEnvCombine::REPLACE},
519     {"modulate", TexEnvCombine::MODULATE},
520     {"add", TexEnvCombine::ADD},
521     {"add-signed", TexEnvCombine::ADD_SIGNED},
522     {"interpolate", TexEnvCombine::INTERPOLATE},
523     {"subtract", TexEnvCombine::SUBTRACT},
524     {"dot3-rgb", TexEnvCombine::DOT3_RGB},
525     {"dot3-rgba", TexEnvCombine::DOT3_RGBA}
526 };
527
528 EffectPropertyMap<TexEnvCombine::CombineParam> combineParams(combineParamInit);
529
530 EffectNameValue<TexEnvCombine::SourceParam> sourceParamInit[] =
531 {
532     {"constant", TexEnvCombine::CONSTANT},
533     {"primary_color", TexEnvCombine::PRIMARY_COLOR},
534     {"previous", TexEnvCombine::PREVIOUS},
535     {"texture", TexEnvCombine::TEXTURE},
536     {"texture0", TexEnvCombine::TEXTURE0},
537     {"texture1", TexEnvCombine::TEXTURE1},
538     {"texture2", TexEnvCombine::TEXTURE2},
539     {"texture3", TexEnvCombine::TEXTURE3},
540     {"texture4", TexEnvCombine::TEXTURE4},
541     {"texture5", TexEnvCombine::TEXTURE5},
542     {"texture6", TexEnvCombine::TEXTURE6},
543     {"texture7", TexEnvCombine::TEXTURE7}
544 };
545
546 EffectPropertyMap<TexEnvCombine::SourceParam> sourceParams(sourceParamInit);
547
548 EffectNameValue<TexEnvCombine::OperandParam> opParamInit[] =
549 {
550     {"src-color", TexEnvCombine::SRC_COLOR},
551     {"one-minus-src-color", TexEnvCombine::ONE_MINUS_SRC_COLOR},
552     {"src-alpha", TexEnvCombine::SRC_ALPHA},
553     {"one-minus-src-alpha", TexEnvCombine::ONE_MINUS_SRC_ALPHA}
554 };
555
556 EffectPropertyMap<TexEnvCombine::OperandParam> operandParams(opParamInit);
557
558 TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp,
559                                   const SGReaderWriterXMLOptions* options)
560 {
561     if (!isAttributeActive(effect, envProp))
562         return 0;
563     TexEnvCombine* result = new TexEnvCombine;
564     const SGPropertyNode* p = 0;
565     if ((p = getEffectPropertyChild(effect, envProp, "combine-rgb"))) {
566         TexEnvCombine::CombineParam crgb = TexEnvCombine::MODULATE;
567         findAttr(combineParams, p, crgb);
568         result->setCombine_RGB(crgb);
569     }
570     if ((p = getEffectPropertyChild(effect, envProp, "combine-alpha"))) {
571         TexEnvCombine::CombineParam calpha = TexEnvCombine::MODULATE;
572         findAttr(combineParams, p, calpha);
573         result->setCombine_Alpha(calpha);
574     }
575     if ((p = getEffectPropertyChild(effect, envProp, "source0-rgb"))) {
576         TexEnvCombine::SourceParam source = TexEnvCombine::TEXTURE;
577         findAttr(sourceParams, p, source);
578         result->setSource0_RGB(source);
579     }
580     if ((p = getEffectPropertyChild(effect, envProp, "source1-rgb"))) {
581         TexEnvCombine::SourceParam source = TexEnvCombine::PREVIOUS;
582         findAttr(sourceParams, p, source);
583         result->setSource1_RGB(source);
584     }
585     if ((p = getEffectPropertyChild(effect, envProp, "source2-rgb"))) {
586         TexEnvCombine::SourceParam source = TexEnvCombine::CONSTANT;
587         findAttr(sourceParams, p, source);
588         result->setSource2_RGB(source);
589     }
590     if ((p = getEffectPropertyChild(effect, envProp, "source0-alpha"))) {
591         TexEnvCombine::SourceParam source = TexEnvCombine::TEXTURE;
592         findAttr(sourceParams, p, source);
593         result->setSource0_Alpha(source);
594     }
595     if ((p = getEffectPropertyChild(effect, envProp, "source1-alpha"))) {
596         TexEnvCombine::SourceParam source = TexEnvCombine::PREVIOUS;
597         findAttr(sourceParams, p, source);
598         result->setSource1_Alpha(source);
599     }
600     if ((p = getEffectPropertyChild(effect, envProp, "source2-alpha"))) {
601         TexEnvCombine::SourceParam source = TexEnvCombine::CONSTANT;
602         findAttr(sourceParams, p, source);
603         result->setSource2_Alpha(source);
604     }
605     if ((p = getEffectPropertyChild(effect, envProp, "operand0-rgb"))) {
606         TexEnvCombine::OperandParam op = TexEnvCombine::SRC_COLOR;
607         findAttr(operandParams, p, op);
608         result->setOperand0_RGB(op);
609     }
610     if ((p = getEffectPropertyChild(effect, envProp, "operand1-rgb"))) {
611         TexEnvCombine::OperandParam op = TexEnvCombine::SRC_COLOR;
612         findAttr(operandParams, p, op);
613         result->setOperand1_RGB(op);
614     }
615     if ((p = getEffectPropertyChild(effect, envProp, "operand2-rgb"))) {
616         TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
617         findAttr(operandParams, p, op);
618         result->setOperand2_RGB(op);
619     }
620     if ((p = getEffectPropertyChild(effect, envProp, "operand0-alpha"))) {
621         TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
622         findAttr(operandParams, p, op);
623         result->setOperand0_Alpha(op);
624     }
625     if ((p = getEffectPropertyChild(effect, envProp, "operand1-alpha"))) {
626         TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
627         findAttr(operandParams, p, op);
628         result->setOperand1_Alpha(op);
629     }
630     if ((p = getEffectPropertyChild(effect, envProp, "operand2-alpha"))) {
631         TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
632         findAttr(operandParams, p, op);
633         result->setOperand2_Alpha(op);
634     }
635     if ((p = getEffectPropertyChild(effect, envProp, "scale-rgb"))) {
636         result->setScale_RGB(p->getValue<float>());
637     }
638     if ((p = getEffectPropertyChild(effect, envProp, "scale-alpha"))) {
639         result->setScale_Alpha(p->getValue<float>());
640     }
641 #if 0
642     if ((p = getEffectPropertyChild(effect, envProp, "constant-color"))) {
643         SGVec4d color = p->getValue<SGVec4d>();
644         result->setConstantColor(toOsg(color));
645     } else if ((p = getEffectPropertyChild(effect, envProp,
646                                            "light-direction"))) {
647         SGVec3d direction = p->getValue<SGVec3d>();
648         result->setConstantColorAsLightDirection(toOsg(direction));
649     }
650 #endif
651     const SGPropertyNode* colorNode = envProp->getChild("constant-color");
652     if (colorNode)
653         initFromParameters(effect, colorNode, result,
654                            &TexEnvCombine::setConstantColor, colorFields,
655                            options);
656     return result;
657 }
658
659 EffectNameValue<TexGen::Mode> tgenModeInit[] =
660 {
661     { "object-linear", TexGen::OBJECT_LINEAR},
662     { "eye-linear", TexGen::EYE_LINEAR},
663     { "sphere-map", TexGen::SPHERE_MAP},
664     { "normal-map", TexGen::NORMAL_MAP},
665     { "reflection-map", TexGen::REFLECTION_MAP}
666 };
667
668 EffectPropertyMap<TexGen::Mode> tgenModes(tgenModeInit);
669
670 EffectNameValue<TexGen::Coord> tgenCoordInit[] =
671 {
672     {"s", TexGen::S},
673     {"t", TexGen::T},
674     {"r", TexGen::R},
675     {"q", TexGen::Q}
676 };
677
678 EffectPropertyMap<TexGen::Coord> tgenCoords(tgenCoordInit);
679
680 TexGen* buildTexGen(Effect* effect, const SGPropertyNode* tgenProp)
681 {
682     if (!isAttributeActive(effect, tgenProp))
683         return 0;
684     TexGen* result = new TexGen;
685     const SGPropertyNode* p = 0;
686     TexGen::Mode mode = TexGen::OBJECT_LINEAR;
687     findAttr(tgenModes, getEffectPropertyChild(effect, tgenProp, "mode"), mode);
688     result->setMode(mode);
689     const SGPropertyNode* planesNode = tgenProp->getChild("planes");
690     if (planesNode) {
691         for (int i = 0; i < planesNode->nChildren(); ++i) {
692             const SGPropertyNode* planeNode = planesNode->getChild(i);
693             TexGen::Coord coord;
694             findAttr(tgenCoords, planeNode->getName(), coord);
695             const SGPropertyNode* realNode
696                 = getEffectPropertyNode(effect, planeNode);
697             SGVec4d plane = realNode->getValue<SGVec4d>();
698             result->setPlane(coord, toOsg(plane));
699         }
700     }
701     return result;
702 }
703
704 bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss)
705 {
706     SGPropertyNode* texUnit = makeChild(paramRoot, "texture");
707     const Texture* tex = getStateAttribute<Texture>(0, ss);
708     const Texture2D* texture = dynamic_cast<const Texture2D*>(tex);
709     makeChild(texUnit, "unit")->setValue(0);
710     if (!tex) {
711         // The default shader-based technique ignores active
712         makeChild(texUnit, "active")->setValue(false);
713         return false;
714     }
715     const Image* image = texture->getImage();
716     string imageName;
717     if (image) {
718         imageName = image->getFileName();
719     } else {
720         makeChild(texUnit, "active")->setValue(false);
721         makeChild(texUnit, "type")->setValue("white");
722         return false;
723     }
724     makeChild(texUnit, "active")->setValue(true);
725     makeChild(texUnit, "type")->setValue("2d");
726     string filter = findName(filterModes,
727                              texture->getFilter(Texture::MIN_FILTER));
728     string magFilter = findName(filterModes,
729                              texture->getFilter(Texture::MAG_FILTER));
730     string wrapS = findName(wrapModes, texture->getWrap(Texture::WRAP_S));
731     string wrapT = findName(wrapModes, texture->getWrap(Texture::WRAP_T));
732     string wrapR = findName(wrapModes, texture->getWrap(Texture::WRAP_R));
733     makeChild(texUnit, "image")->setStringValue(imageName);
734     makeChild(texUnit, "filter")->setStringValue(filter);
735     makeChild(texUnit, "mag-filter")->setStringValue(magFilter);
736     makeChild(texUnit, "wrap-s")->setStringValue(wrapS);
737     makeChild(texUnit, "wrap-t")->setStringValue(wrapT);
738     makeChild(texUnit, "wrap-r")->setStringValue(wrapR);
739     return true;
740 }
741
742 }