1 // non fixed Opengl pipeline rendering
2 //
3 // Written by Harald JOHNSEN, started Jully 2005.
4 //
5 // Copyright (C) 2005  Harald JOHNSEN
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 //
22 
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26 
27 #include <map>
28 
29 #include <osg/Group>
30 #include <osg/Program>
31 #include <osg/Shader>
32 #include <osg/StateSet>
33 #include <osg/TextureCubeMap>
34 #include <osg/TexEnvCombine>
35 #include <osg/TexGen>
36 #include <osg/Texture1D>
37 #include <osgUtil/HighlightMapGenerator>
38 
39 #include <OpenThreads/Mutex>
40 #include <OpenThreads/ScopedLock>
41 
42 #include <simgear/scene/util/SGUpdateVisitor.hxx>
43 
44 #include <simgear/props/condition.hxx>
45 #include <simgear/props/props.hxx>
46 
47 #include <simgear/debug/logstream.hxx>
48 
49 #include "animation.hxx"
50 #include "model.hxx"
51 
52 using OpenThreads::Mutex;
53 using OpenThreads::ScopedLock;
54 
55 /*
56     <animation>
57         <type>shader</type>
58         <shader>fresnel</shader>
59         <object-name>...</object-name>
60     </animation>
61 
62     <animation>
63         <type>shader</type>
64         <shader>heat-haze</shader>
65         <object-name>...</object-name>
66         <speed>...</speed>
67         <speed-prop>...</speed-prop>
68         <factor>...</factor>
69         <factor-prop>...</factor-prop>
70     </animation>
71 
72     <animation>
73         <type>shader</type>
74         <shader>chrome</shader>
75         <texture>...</texture>
76         <object-name>...</object-name>
77     </animation>
78 
79     <animation>
80         <type>shader</type>
81         <shader></shader>
82         <object-name>...</object-name>
83         <depth-test>false</depth-test>
84     </animation>
85 
86 */
87 
88 
89 class SGMapGenCallback :
90   public osg::StateAttribute::Callback {
91 public:
operator ()(osg::StateAttribute * sa,osg::NodeVisitor * nv)92   virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
93   {
94     SGUpdateVisitor* updateVisitor = dynamic_cast<SGUpdateVisitor*>(nv);
95     if (!updateVisitor)
96       return;
97 
98     if (distSqr(_lastLightDirection, updateVisitor->getLightDirection()) < 1e-4
99         && distSqr(_lastLightColor, updateVisitor->getAmbientLight()) < 1e-4)
100       return;
101 
102     _lastLightDirection = updateVisitor->getLightDirection();
103     _lastLightColor = updateVisitor->getAmbientLight();
104 
105     osg::TextureCubeMap *tcm = static_cast<osg::TextureCubeMap*>(sa);
106 
107     // FIXME: need an update or callback ...
108     // generate the six highlight map images (light direction = [1, 1, -1])
109     osg::ref_ptr<osgUtil::HighlightMapGenerator> mapgen;
110     mapgen = new osgUtil::HighlightMapGenerator(toOsg(_lastLightDirection),
111                                                 toOsg(_lastLightColor), 5);
112     mapgen->generateMap();
113 
114     // assign the six images to the texture object
115     tcm->setImage(osg::TextureCubeMap::POSITIVE_X,
116                   mapgen->getImage(osg::TextureCubeMap::POSITIVE_X));
117     tcm->setImage(osg::TextureCubeMap::NEGATIVE_X,
118                   mapgen->getImage(osg::TextureCubeMap::NEGATIVE_X));
119     tcm->setImage(osg::TextureCubeMap::POSITIVE_Y,
120                   mapgen->getImage(osg::TextureCubeMap::POSITIVE_Y));
121     tcm->setImage(osg::TextureCubeMap::NEGATIVE_Y,
122                   mapgen->getImage(osg::TextureCubeMap::NEGATIVE_Y));
123     tcm->setImage(osg::TextureCubeMap::POSITIVE_Z,
124                   mapgen->getImage(osg::TextureCubeMap::POSITIVE_Z));
125     tcm->setImage(osg::TextureCubeMap::NEGATIVE_Z,
126                   mapgen->getImage(osg::TextureCubeMap::NEGATIVE_Z));
127   }
128 private:
129   SGVec3f _lastLightDirection;
130   SGVec4f _lastLightColor;
131 };
132 
133 static Mutex cubeMutex;
134 
135 #if 0
136 static osg::TextureCubeMap*
137 getOrCreateTextureCubeMap()
138 {
139   static osg::ref_ptr<osg::TextureCubeMap> textureCubeMap;
140   if (textureCubeMap.get())
141     return textureCubeMap.get();
142 
143   ScopedLock<Mutex> lock(cubeMutex);
144   if (textureCubeMap.get())
145     return textureCubeMap.get();
146 
147   // create and setup the texture object
148   textureCubeMap = new osg::TextureCubeMap;
149 
150   textureCubeMap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
151   textureCubeMap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
152   textureCubeMap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP);
153   textureCubeMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
154   textureCubeMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
155 
156   textureCubeMap->setUpdateCallback(new SGMapGenCallback);
157 
158   return textureCubeMap.get();
159 }
160 
161 static void create_specular_highlights(osg::Node *node)
162 {
163   osg::StateSet *ss = node->getOrCreateStateSet();
164 
165   // create and setup the texture object
166   osg::TextureCubeMap *tcm = getOrCreateTextureCubeMap();
167 
168   // enable texturing, replacing any textures in the subgraphs
169   ss->setTextureAttributeAndModes(0, tcm, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
170 
171   // texture coordinate generation
172   osg::TexGen *tg = new osg::TexGen;
173   tg->setMode(osg::TexGen::REFLECTION_MAP);
174   ss->setTextureAttributeAndModes(0, tg, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
175 
176   // use TexEnvCombine to add the highlights to the original lighting
177   osg::TexEnvCombine *te = new osg::TexEnvCombine;
178   te->setCombine_RGB(osg::TexEnvCombine::ADD);
179   te->setSource0_RGB(osg::TexEnvCombine::TEXTURE);
180   te->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
181   te->setSource1_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
182   te->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
183   ss->setTextureAttributeAndModes(0, te, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
184 }
185 #endif
186 
187 
SGShaderAnimation(simgear::SGTransientModelData & modelData)188 SGShaderAnimation::SGShaderAnimation(simgear::SGTransientModelData &modelData) :
189   SGAnimation(modelData)
190 {
191   const SGPropertyNode* node = modelData.getConfigNode()->getChild("texture");
192   if (node)
193     _effect_texture = SGLoadTexture2D(node->getStringValue(), modelData.getOptions());
194 }
195 
196 namespace {
197 class ChromeLightingCallback :
198   public osg::StateAttribute::Callback {
199 public:
operator ()(osg::StateAttribute * sa,osg::NodeVisitor * nv)200   virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
201   {
202     SGUpdateVisitor* updateVisitor = dynamic_cast<SGUpdateVisitor*>(nv);
203     if (!updateVisitor)
204       return;
205     osg::TexEnvCombine *combine = dynamic_cast<osg::TexEnvCombine *>(sa);
206     if (!combine)
207 	return;
208     // An approximation for light reflected back by chrome.
209     osg::Vec4 globalColor = toOsg(updateVisitor->getAmbientLight() * .4f
210                                   + updateVisitor->getDiffuseLight());
211     globalColor.a() = 1.0f;
212     combine->setConstantColor(globalColor);
213   }
214 };
215 
216 typedef std::map<osg::ref_ptr<osg::Texture2D>, osg::ref_ptr<osg::StateSet> >
217 StateSetMap;
218 }
219 
220 static Mutex chromeMutex;
221 
222 // The chrome effect is mixed by the alpha channel of the texture
223 // on the model, which will be attached to a node lower in the scene
224 // graph: 0 -> completely chrome, 1 -> completely model texture.
create_chrome(osg::Group * group,osg::Texture2D * texture)225 static void create_chrome(osg::Group* group, osg::Texture2D* texture)
226 {
227     ScopedLock<Mutex> lock(chromeMutex);
228     static StateSetMap chromeMap;
229     osg::StateSet *stateSet;
230     StateSetMap::iterator iterator = chromeMap.find(texture);
231     if (iterator != chromeMap.end()) {
232 	stateSet = iterator->second.get();
233     } else {
234 	stateSet = new osg::StateSet;
235 	// If the model doesn't have any texture, we need to have one
236 	// activated so that we don't need a seperate combiner
237 	// attribute for the non-textured case. This texture will be
238 	// shadowed by any attached to the model.
239 	osg::Image *dummyImage = new osg::Image;
240 	dummyImage->allocateImage(1, 1, 1, GL_LUMINANCE_ALPHA,
241 				  GL_UNSIGNED_BYTE);
242 	unsigned char* imageBytes = dummyImage->data(0, 0);
243 	imageBytes[0] = 255;
244 	imageBytes[1] = 0;
245 	osg::Texture2D* dummyTexture = new osg::Texture2D;
246 	dummyTexture->setImage(dummyImage);
247 	dummyTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
248 	dummyTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
249 	stateSet->setTextureAttributeAndModes(0, dummyTexture,
250 					      osg::StateAttribute::ON);
251 	osg::TexEnvCombine* combine0 = new osg::TexEnvCombine;
252 	osg::TexEnvCombine* combine1 = new osg::TexEnvCombine;
253 	osg::TexGen* texGen = new osg::TexGen;
254 	// Mix the environmental light color and the chrome map on texture
255 	// unit 0
256 	combine0->setCombine_RGB(osg::TexEnvCombine::MODULATE);
257 	combine0->setSource0_RGB(osg::TexEnvCombine::CONSTANT);
258 	combine0->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
259 	combine0->setSource1_RGB(osg::TexEnvCombine::TEXTURE1);
260 	combine0->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
261 	combine0->setDataVariance(osg::Object::DYNAMIC);
262 	combine0->setUpdateCallback(new ChromeLightingCallback);
263 
264 	// Interpolate the colored chrome map with the texture on the
265 	// model, using the model texture's alpha.
266 	combine1->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
267 	combine1->setSource0_RGB(osg::TexEnvCombine::TEXTURE0);
268 	combine1->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
269 	combine1->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
270 	combine1->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
271 	combine1->setSource2_RGB(osg::TexEnvCombine::TEXTURE0);
272 	combine1->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA);
273 	// Are these used for anything?
274 	combine1->setCombine_Alpha(osg::TexEnvCombine::REPLACE);
275 	combine1->setSource0_Alpha(osg::TexEnvCombine::TEXTURE1);
276 	combine1->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA);
277 
278 	texGen->setMode(osg::TexGen::SPHERE_MAP);
279 	stateSet->setTextureAttribute(0, combine0);
280 	stateSet->setTextureAttribute(1, combine1);
281 	stateSet->setTextureAttributeAndModes(1, texture,
282 					      osg::StateAttribute::ON);
283 	stateSet->setTextureAttributeAndModes(1, texGen,
284 					      osg::StateAttribute::ON);
285 	chromeMap[texture] = stateSet;
286     }
287     group->setStateSet(stateSet);
288 }
289 
290 osg::Group*
createAnimationGroup(osg::Group & parent)291 SGShaderAnimation::createAnimationGroup(osg::Group& parent)
292 {
293   osg::Group* group = new osg::Group;
294   group->setName("shader animation");
295   parent.addChild(group);
296 
297   std::string shader_name = getConfig()->getStringValue("shader", "");
298 //   if( shader_name == "fresnel" || shader_name == "reflection" )
299 //     _shader_type = 1;
300 //   else if( shader_name == "heat-haze" )
301 //     _shader_type = 2;
302 //   else
303   if( shader_name == "chrome")
304 #if 0
305     create_specular_highlights(group);
306 #endif
307   create_chrome(group, _effect_texture.get());
308   return group;
309 }
310 
311 #if 0
312 // static Shader *shFresnel=NULL;
313 // static GLuint texFresnel = 0;
314 
315 // static GLuint texBackground = 0;
316 // static int texBackgroundWidth = 1024, texBackgroundHeight = 1024;
317 // static GLenum texBackgroundTarget = GL_TEXTURE_2D;
318 // static bool isRectangleTextureSupported = false;
319 // static bool istexBackgroundRectangle = false;
320 // static bool initDone = false;
321 static bool haveBackground = false;
322 
323 // static glActiveTextureProc glActiveTexturePtr = 0;
324 // static sgMat4 shadIdentMatrix;
325 
326 
327 // static int null_shader_callback( ssgEntity *e ) {
328 //  	GLuint dlist = 0;
329 //     ssgLeaf *leaf = (ssgLeaf *) e;
330 // #ifdef _SSG_USE_DLIST
331 //     dlist = leaf->getDListIndex();
332 //     if( ! dlist ) {
333 //         leaf->makeDList();
334 //         dlist = leaf->getDListIndex();
335 //     }
336 // #endif
337 //     if( ! dlist )
338 //         return true;
339 //     ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
340 //     if ( sst )
341 //         sst->apply();
342 
343 //     SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
344 //     if( ! my_shader->_depth_test )
345 //         glDisable( GL_DEPTH_TEST );
346 //     glCallList ( dlist ) ;
347 //     // restore states
348 //     if( ! my_shader->_depth_test )
349 //         glEnable( GL_DEPTH_TEST );
350 
351 //     // don't draw !
352 //     return false;
353 // }
354 
355 // static int heat_haze_shader_callback( ssgEntity *e ) {
356 //    if( ! ((SGShadowAnimation *)e->getUserData())->get_condition_value() )
357 //        return true;
358 
359 //  	GLuint dlist = 0;
360 //     ssgLeaf *leaf = (ssgLeaf *) e;
361 // #ifdef _SSG_USE_DLIST
362 //     dlist = leaf->getDListIndex();
363 //     if( ! dlist ) {
364 //         leaf->makeDList();
365 //         dlist = leaf->getDListIndex();
366 //     }
367 // #endif
368 //     if( ! dlist )
369 //         return true;
370 
371 //     GLint viewport[4];
372 //     glGetIntegerv( GL_VIEWPORT, viewport );
373 //     const int screen_width = viewport[2];
374 //     const int screen_height = viewport[3];
375 //     if( ! haveBackground ) {
376 //         // store the backbuffer in a texture
377 //         if( ! texBackground ) {
378 //             // allocate our texture here so we don't waste memory if no model use that effect
379 //             // check if we need a rectangle texture and if the card support it
380 //             if( (screen_width > 1024 || screen_height > 1024) && isRectangleTextureSupported ) {
381 //                 // Note that the 3 (same) extensions use the same enumerants
382 //                 texBackgroundTarget = GL_TEXTURE_RECTANGLE_NV;
383 //                 istexBackgroundRectangle = true;
384 //                 texBackgroundWidth = screen_width;
385 //                 texBackgroundHeight = screen_height;
386 //             }
387 //             glGenTextures(1, &texBackground);
388 //             glEnable(texBackgroundTarget);
389 //             glBindTexture(texBackgroundTarget, texBackground);
390 //             // trying to match the backbuffer pixel format
391 //             GLint internalFormat = GL_RGB8;
392 //             GLint colorBits = 0, alphaBits = 0;
393 //             glGetIntegerv( GL_BLUE_BITS, &colorBits );
394 //             glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
395 //             if(colorBits == 5) {
396 //                 if( alphaBits == 0 )
397 //                     internalFormat = GL_RGB5;
398 //                 else
399 //                     internalFormat = GL_RGB5_A1;
400 //             } else {
401 //                 if( alphaBits != 0 )
402 //                     internalFormat = GL_RGBA8;
403 //             }
404 //             glTexImage2D(texBackgroundTarget, 0, internalFormat,
405 //                             texBackgroundWidth, texBackgroundHeight, 0, GL_RGB, GL_FLOAT, NULL);
406 
407 //             glTexParameteri(texBackgroundTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
408 //             glTexParameteri(texBackgroundTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
409 //             glTexParameteri(texBackgroundTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
410 //             glTexParameteri(texBackgroundTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
411 //         }
412 //         glEnable(texBackgroundTarget);
413 //         glBindTexture(texBackgroundTarget, texBackground);
414 //         // center of texture = center of screen
415 //         // obviously we don't have the whole screen if screen_width > texBackgroundWidth
416 //         // if rectangle textures are not supported, this give some artifacts on the borders
417 //         if( istexBackgroundRectangle ) {
418 //             glCopyTexSubImage2D( texBackgroundTarget, 0, 0, 0,
419 //                 0, 0, texBackgroundWidth, texBackgroundHeight );
420 //         } else {
421 //             glCopyTexSubImage2D( texBackgroundTarget, 0, 0, 0,
422 //                 (screen_width - texBackgroundWidth) / 2,
423 //                 (screen_height - texBackgroundHeight) / 2,
424 //                 texBackgroundWidth, texBackgroundHeight );
425 //         }
426 //         haveBackground = true;
427 //         glBindTexture(texBackgroundTarget, 0);
428 //         glDisable(texBackgroundTarget);
429 //     }
430 //     ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
431 //     if ( sst )
432 //         sst->apply();
433 
434 //     SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
435 //     if( ! my_shader->_depth_test )
436 //         glDisable( GL_DEPTH_TEST );
437 //     glDepthMask( GL_FALSE );
438 //     glDisable( GL_LIGHTING );
439 //     if(1) {
440 //         // noise texture, tex coord from the model translated by a time factor
441 //         glActiveTexturePtr( GL_TEXTURE0_ARB );
442 //         glEnable(GL_TEXTURE_2D);
443 //         const float noiseDist = fmod(- totalTime * my_shader->_factor * my_shader->_speed, 4.0);
444 //         glMatrixMode(GL_TEXTURE);
445 //             glLoadIdentity();
446 //             glTranslatef( noiseDist, 0.0f, 0.0f );
447 //         glMatrixMode(GL_MODELVIEW);
448 
449 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
450 
451 //         // background texture
452 //         glActiveTexturePtr( GL_TEXTURE1_ARB );
453 //         glEnable(texBackgroundTarget);
454 //         glBindTexture(texBackgroundTarget, texBackground);
455 
456 //         // automatic generation of texture coordinates
457 //         // map to screen space
458 //         sgMat4 CameraProjM, CameraViewM;
459 //         glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *) CameraProjM);
460 //         glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) CameraViewM);
461 //         // const float dummy_scale = 1.0f; //0.95f;
462 //         const float deltaPos = 0.05f;
463 //         glMatrixMode(GL_TEXTURE);
464 //             glLoadIdentity();
465 //             if( istexBackgroundRectangle ) {
466 //                 // coords go from 0.0 to n, not from 0.0 to 1.0
467 //                 glTranslatef( texBackgroundWidth * 0.5f, texBackgroundHeight * 0.5f, 0.0f );
468 //                 glScalef( texBackgroundWidth * 0.5f,
469 //                     texBackgroundHeight * 0.5f, 1.0f );
470 //             } else {
471 //                 glTranslatef( 0.5f, 0.5f, 0.0f );
472 //                 glScalef( float( screen_width ) / float( texBackgroundWidth ) * 0.5f,
473 //                     float( screen_height ) / float( texBackgroundHeight ) * 0.5f, 1.0f );
474 //             }
475 //             glMultMatrixf( (GLfloat *) CameraProjM );
476 //             glMultMatrixf( (GLfloat *) CameraViewM );
477 //             glTranslatef( deltaPos, deltaPos, deltaPos );
478 //         glMatrixMode(GL_MODELVIEW);
479 
480 //         glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
481 //         glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
482 //         glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
483 //         glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
484 //         glTexGenfv( GL_S, GL_EYE_PLANE, shadIdentMatrix[0] );
485 //         glTexGenfv( GL_T, GL_EYE_PLANE, shadIdentMatrix[1] );
486 //         glTexGenfv( GL_R, GL_EYE_PLANE, shadIdentMatrix[2] );
487 //         glTexGenfv( GL_Q, GL_EYE_PLANE, shadIdentMatrix[3] );
488 //         glEnable( GL_TEXTURE_GEN_S );
489 //         glEnable( GL_TEXTURE_GEN_T );
490 //         glEnable( GL_TEXTURE_GEN_R );
491 //         glEnable( GL_TEXTURE_GEN_Q );
492 
493 //         sgVec4 enviro = {1.00f, 1.00f, 1.00f, 0.85f};
494 
495 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
496 //         glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
497 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
498 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
499 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB );
500 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
501 // 		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
502 
503 //         glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
504 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0_ARB);
505 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
506 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB );
507 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA );
508 
509 //         glCallList ( dlist ) ;
510 //         glMatrixMode(GL_TEXTURE);
511 //         glTranslatef( - deltaPos*2.0f, -deltaPos*2.5f, -deltaPos*2.0f );
512 //         glMatrixMode(GL_MODELVIEW);
513 //         glCallList ( dlist ) ;
514 
515 //         // alter colors only on last rendering
516 //         // sgVec4 fLight = {0.93f, 0.93f, 1.00f, 0.85f};
517 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
518 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
519 
520 //         glMatrixMode(GL_TEXTURE);
521 //         glTranslatef( deltaPos*0.7f, deltaPos*1.7f, deltaPos*0.7f );
522 //         glMatrixMode(GL_MODELVIEW);
523 //         glCallList ( dlist ) ;
524 
525 
526 //         glActiveTexturePtr( GL_TEXTURE1_ARB );
527 //         glDisable( GL_TEXTURE_GEN_S );
528 //         glDisable( GL_TEXTURE_GEN_T );
529 //         glDisable( GL_TEXTURE_GEN_R );
530 //         glDisable( GL_TEXTURE_GEN_Q );
531 //         glMatrixMode(GL_TEXTURE);
532 //             glLoadIdentity();
533 //         glMatrixMode(GL_MODELVIEW);
534 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
535 //         glDisable(texBackgroundTarget);
536 //         glActiveTexturePtr( GL_TEXTURE0_ARB );
537 //         glMatrixMode(GL_TEXTURE);
538 //             glLoadIdentity();
539 //         glMatrixMode(GL_MODELVIEW);
540 //         glEnable(GL_TEXTURE_2D);
541 //         glBindTexture(GL_TEXTURE_2D, 0);
542 //     }
543 //     // restore states
544 //     if( ! my_shader->_depth_test )
545 //         glEnable( GL_DEPTH_TEST );
546 
547 //     glEnable( GL_LIGHTING );
548 //     glDepthMask( GL_TRUE );
549 //     if( sst )
550 //         sst->force();
551 
552 //    // don't draw !
553 //     return false;
554 // }
555 
556 // static int fresnel_shader_callback( ssgEntity *e ) {
557 //    if( ! ((SGShadowAnimation *)e->getUserData())->get_condition_value() )
558 //        return true;
559 
560 //  	GLuint dlist = 0;
561 //     ssgLeaf *leaf = (ssgLeaf *) e;
562 // #ifdef _SSG_USE_DLIST
563 //     dlist = leaf->getDListIndex();
564 //     if( ! dlist ) {
565 //         leaf->makeDList();
566 //         dlist = leaf->getDListIndex();
567 //     }
568 // #endif
569 //     if( ! dlist )
570 //         return true;
571 //     ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
572 //     if ( sst )
573 //         sst->apply();
574 
575 //     sgVec4 sunColor, ambientColor;
576 //     ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
577 //     ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
578 
579 //     // SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
580 //     glEnable(GL_BLEND);
581 // 	glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
582 // 	glEnable(GL_ALPHA_TEST);
583 // 	glAlphaFunc(GL_GREATER, 0.0f);
584 
585 // 	if( true ) {
586 // //        sgVec4 R = {0.5,0.0,0.0,0.0};
587 //         sgVec4 enviro = {1.0,0.0,0.0,1.0};
588 // //        sgCopyVec4( enviro, sunColor );
589 //         glActiveTexturePtr( GL_TEXTURE0_ARB );
590 //         glEnable(GL_TEXTURE_2D);
591 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
592 //         glActiveTexturePtr( GL_TEXTURE1_ARB );
593 //         glDisable(GL_TEXTURE_2D);
594 //         glEnable(GL_TEXTURE_1D);
595 //         glBindTexture(GL_TEXTURE_1D, texFresnel);
596 //         // c = a0 * a2 + a1 * (1-a2)
597 // //        glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
598 // //        glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
599 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
600 //         glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
601 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
602 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
603 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
604 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
605 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE );
606 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
607 // 		glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
608 //         shFresnel->enable();
609 //             shFresnel->bind();
610 //             glCallList ( dlist ) ;
611 //         shFresnel->disable();
612 //         glActiveTexturePtr( GL_TEXTURE1_ARB );
613 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
614 //         glDisable(GL_TEXTURE_1D);
615 //         glActiveTexturePtr( GL_TEXTURE0_ARB );
616 //         glDisable(GL_TEXTURE_1D);
617 //         glEnable(GL_TEXTURE_2D);
618 //     }
619 //     // restore states
620 // //    glBindTexture(GL_TEXTURE_2D, 0);
621 // //    glDepthFunc(GL_LESS);
622 // //    glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
623 //    if( sst )
624 // 	    sst->force();
625 
626 //     // don't draw !
627 //     return false;
628 // }
629 
630 
631 
632 // static int chrome_shader_callback( ssgEntity *e ) {
633 //    if( ! ((SGShadowAnimation *)e->getUserData())->get_condition_value() )
634 //        return true;
635 
636 //  	GLuint dlist = 0;
637 //     ssgLeaf *leaf = (ssgLeaf *) e;
638 // #ifdef _SSG_USE_DLIST
639 //     dlist = leaf->getDListIndex();
640 //     if( ! dlist ) {
641 //         leaf->makeDList();
642 //         dlist = leaf->getDListIndex();
643 //     }
644 // #endif
645 //     if( ! dlist )
646 //         return true;
647 //     ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
648 //     if ( sst )
649 //         sst->apply();
650 
651 //     SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
652 //     if( ! my_shader->_depth_test )
653 //         glDisable( GL_DEPTH_TEST );
654 
655 //     GLint maskTexComponent = 3;
656 //     glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_COMPONENTS, &maskTexComponent);
657 
658 //     // The fake env chrome texture
659 //     glActiveTexturePtr( GL_TEXTURE1_ARB );
660 //     glEnable(GL_TEXTURE_2D);
661 //     {
662 //         // No lighting is computed in spherical mapping mode because the environment
663 //         // is supposed to be allready lighted. We must reshade our environment texture.
664 //         sgVec4 sunColor, ambientColor, envColor;
665 //         ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
666 //         ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
667 //         sgAddScaledVec3( envColor, ambientColor, sunColor, 0.4f);
668 //         glBindTexture(GL_TEXTURE_2D, my_shader->_effectTexture->getHandle());
669 
670 //         sgVec3 delta_light;
671 //         sgSubVec3(delta_light, envColor, my_shader->_envColor);
672 //         if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
673 // 		    sgCopyVec3( my_shader->_envColor, envColor );
674 //             // reload the texture data and let the driver reshade it for us
675 //             glPixelTransferf( GL_RED_SCALE, envColor[0] );
676 //             glPixelTransferf( GL_GREEN_SCALE, envColor[1] );
677 //             glPixelTransferf( GL_BLUE_SCALE, envColor[2] );
678 //             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, my_shader->_texWidth, my_shader->_texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, my_shader->_textureData);
679 //             glPixelTransferf( GL_RED_SCALE, 1.0f );
680 //             glPixelTransferf( GL_GREEN_SCALE, 1.0f );
681 //             glPixelTransferf( GL_BLUE_SCALE, 1.0f );
682 //         }
683 //     }
684 //     if( maskTexComponent == 4 ) {
685 //         // c = lerp(model tex, chrome tex, model tex alpha)
686 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
687 //         glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
688 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
689 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
690 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
691 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
692 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PREVIOUS_ARB );
693 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA );
694 
695 //         glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
696 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
697 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
698 //     } else {
699 //         // c = chrome tex
700 //         glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
701 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
702 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
703 
704 //         glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
705 //         glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
706 //         glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
707 //     }
708 //     // automatic generation of texture coordinates
709 //     // from normals
710 
711 //     glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
712 //     glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP );
713 //     glEnable( GL_TEXTURE_GEN_S );
714 //     glEnable( GL_TEXTURE_GEN_T );
715 
716 //     glCallList ( dlist ) ;
717 
718 //     glActiveTexturePtr( GL_TEXTURE1_ARB );
719 //     glDisable( GL_TEXTURE_GEN_S );
720 //     glDisable( GL_TEXTURE_GEN_T );
721 
722 //     glMatrixMode(GL_TEXTURE);
723 //         glLoadIdentity();
724 //     glMatrixMode(GL_MODELVIEW);
725 
726 //     glDisable(GL_TEXTURE_2D);
727 //     glBindTexture(GL_TEXTURE_2D, 0);
728 //     glActiveTexturePtr( GL_TEXTURE0_ARB );
729 
730 //     // restore states
731 //     if( ! my_shader->_depth_test )
732 //         glEnable( GL_DEPTH_TEST );
733 
734 //     if( sst )
735 //         sst->force();
736 
737 //    // don't draw !
738 //     return false;
739 // }
740 
741 // static void init_shaders(void) {
742 // 	Shader::Init();
743 //     if( false && Shader::is_VP_supported() ) {
744 // 	    shFresnel = new Shader("/FlightGear/data/Textures/fresnel_vp.txt", "fresnel_vp");
745 //     }
746 // 	glActiveTexturePtr = (glActiveTextureProc) SGLookupFunction("glActiveTextureARB");
747 //     const int fresnelSize = 512;
748 //     unsigned char imageFresnel[ fresnelSize * 3 ];
749 //     for(int i = 0; i < fresnelSize; i++) {
750 //         const float R0 = 0.2f;
751 //         float NdotV = float( i ) / float( fresnelSize );
752 //         float f = R0 + (1.0f-R0)*pow(1.0f - NdotV, 5);
753 //         unsigned char ff = (unsigned char) (f * 255.0);
754 //         imageFresnel[i*3+0] = imageFresnel[i*3+1] = imageFresnel[i*3+2] = ff;
755 //     }
756 //     glGenTextures( 1, &texFresnel );
757 // 	glBindTexture(GL_TEXTURE_1D, texFresnel );
758 // 	glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
759 //     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
760 //     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
761 // 	glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, true);
762 // 	glTexImage1D(GL_TEXTURE_1D, 0, 3, fresnelSize, 0, GL_RGB, GL_UNSIGNED_BYTE, imageFresnel);
763 // 	glBindTexture(GL_TEXTURE_1D, 0 );
764 
765 //     sgMakeIdentMat4( shadIdentMatrix );
766 
767 // 	initDone = true;
768 // }
769 
770 // ////////////////////////////////////////////////////////////////////////
771 // // Implementation of SGShaderAnimation
772 // ////////////////////////////////////////////////////////////////////////
773 
774 SGShaderAnimation::SGShaderAnimation ( SGPropertyNode *prop_root,
775                    SGPropertyNode_ptr props )
776   : SGAnimation(props, new osg::Group),
777     _condition(0),
778     _condition_value(true),
779     _shader_type(0),
780     _param_1(props->getFloatValue("param", 1.0f)),
781     _depth_test(props->getBoolValue("depth-test", true)),
782     _factor(props->getFloatValue("factor", 1.0f)),
783     _factor_prop(0),
784     _speed(props->getFloatValue("speed", 1.0f)),
785     _speed_prop(0),
786     _textureData(0),
787     _texWidth(0),
788     _texHeight(0)
789 
790 {
791     SGPropertyNode_ptr node = props->getChild("condition");
792     if (node != 0) {
793         _condition = sgReadCondition(prop_root, node);
794         _condition_value = false;
795     }
796     node = props->getChild("factor-prop");
797     if( node )
798         _factor_prop = prop_root->getNode(node->getStringValue(), true);
799     node = props->getChild("speed-prop");
800     if( node )
801         _speed_prop = prop_root->getNode(node->getStringValue(), true);
802 
803     _envColor = osg::Vec4(0, 0, 0, 1);
804     node = props->getChild("texture");
805     if( node ) {
806       _effectTexture = SGLoadTexture2D(node->getStringValue());
807 //         glBindTexture(GL_TEXTURE_2D, _effectTexture->getHandle() );
808 //         glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &_texWidth);
809 //         glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &_texHeight);
810 
811 //         _textureData = new unsigned char[_texWidth * _texHeight * 3];
812 //         glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, _textureData);
813 //         glBindTexture(GL_TEXTURE_2D, 0 );
814     }
815     string shader_name = props->getStringValue("shader");
816     if( shader_name == "fresnel" || shader_name == "reflection" )
817         _shader_type = 1;
818     else if( shader_name == "heat-haze" )
819         _shader_type = 2;
820     else if( shader_name == "chrome" && _effectTexture.valid())
821         _shader_type = 3;
822 }
823 
824 void SGShaderAnimation::init()
825 {
826 //     if( ! initDone )
827 //         init_shaders();
828 //     if( _shader_type == 1 && Shader::is_VP_supported() && shFresnel)
829 //         setCallBack( getBranch(), (ssgBase *) this, fresnel_shader_callback );
830 //     else if( _shader_type == 2 ) {
831 //         // this is the same extension with different names
832 //         isRectangleTextureSupported = SGIsOpenGLExtensionSupported("GL_EXT_texture_rectangle") ||
833 //             SGIsOpenGLExtensionSupported("GL_ARB_texture_rectangle") ||
834 //             SGIsOpenGLExtensionSupported("GL_NV_texture_rectangle");
835 //         setCallBack( getBranch(), (ssgBase *) this, heat_haze_shader_callback );
836 //     }
837 //     else if( _shader_type == 3 )
838 //         setCallBack( getBranch(), (ssgBase *) this, chrome_shader_callback );
839 //     else
840 //         setCallBack( getBranch(), (ssgBase *) this, null_shader_callback );
841 }
842 
843 SGShaderAnimation::~SGShaderAnimation()
844 {
845   delete _condition;
846   delete _textureData;
847 }
848 
849 void
850 SGShaderAnimation::operator()(osg::Node* node, osg::NodeVisitor* nv)
851 {
852   if (_condition)
853     _condition_value = _condition->test();
854   if( _factor_prop)
855     _factor = _factor_prop->getFloatValue();
856   if( _speed_prop)
857     _speed = _speed_prop->getFloatValue();
858 
859   // OSGFIXME fiddle with totalTime
860   totalTime = nv->getFrameStamp()->getReferenceTime();
861 
862   // note, callback is responsible for scenegraph traversal so
863   // should always include call traverse(node,nv) to ensure
864   // that the rest of cullbacks and the scene graph are traversed.
865   traverse(node, nv);
866 }
867 #endif
868