1 // non fixed Opengl pipeline rendering
3 // Written by Harald JOHNSEN, started Jully 2005.
5 // Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
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.
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.
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, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
28 #include <simgear/props/condition.hxx>
29 #include <simgear/props/props.hxx>
30 #include <simgear/screen/extensions.hxx>
32 #include <simgear/debug/logstream.hxx>
34 #include <simgear/screen/shader.h>
36 #include "animation.hxx"
40 <shader>fresnel</shader>
41 <object-name>...</object-name>
46 <shader>heat-haze</shader>
47 <object-name>...</object-name>
49 <speed-prop>...</speed-prop>
51 <factor-prop>...</factor-prop>
57 <object-name>...</object-name>
58 <depth-test>false</depth-test>
62 static Shader *shFresnel=NULL;
63 static GLuint texFresnel = 0;
65 static GLuint texBackground = 0;
66 static const int texBackgroundWidth = 1024, texBackgroundHeight = 1024;
67 static bool initDone = false;
68 static bool haveBackground = false;
70 static glActiveTextureProc glActiveTexturePtr = 0;
71 static double totalTime = 0.0;
73 static int null_shader_callback( ssgEntity *e ) {
75 ssgLeaf *leaf = (ssgLeaf *) e;
77 dlist = leaf->getDListIndex();
80 dlist = leaf->getDListIndex();
85 ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
89 SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
90 if( ! my_shader->_depth_test )
91 glDisable( GL_DEPTH_TEST );
92 glCallList ( dlist ) ;
94 if( ! my_shader->_depth_test )
95 glEnable( GL_DEPTH_TEST );
101 static int heat_haze_shader_callback( ssgEntity *e ) {
103 ssgLeaf *leaf = (ssgLeaf *) e;
104 #ifdef _SSG_USE_DLIST
105 dlist = leaf->getDListIndex();
108 dlist = leaf->getDListIndex();
113 if( ! haveBackground ) {
114 // store the backbuffer in a texture
115 if( ! texBackground ) {
116 // allocate our texture here so we don't waste memory if no model use that effect
117 glGenTextures(1, &texBackground);
118 glBindTexture(GL_TEXTURE_2D, texBackground);
119 // trying to match the backbuffer pixel format
120 GLint internalFormat = GL_RGB8;
121 GLint colorBits = 0, alphaBits = 0;
122 glGetIntegerv( GL_BLUE_BITS, &colorBits );
123 glGetIntegerv( GL_ALPHA_BITS, &alphaBits );
126 internalFormat = GL_RGB5;
128 internalFormat = GL_RGB5_A1;
131 internalFormat = GL_RGBA8;
133 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat,
134 texBackgroundWidth, texBackgroundHeight, 0, GL_RGB, GL_FLOAT, NULL);
136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
138 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
139 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
140 glBindTexture(GL_TEXTURE_2D, 0);
143 glGetIntegerv( GL_VIEWPORT, viewport );
144 const int screen_width = viewport[2];
145 const int screen_height = viewport[3];
146 glBindTexture(GL_TEXTURE_2D, texBackground);
147 // center of texture = center of screen
148 // obviously we don't have the whole screen if screen_width > texBackgroundWidth
149 glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
150 (screen_width - texBackgroundWidth) / 2,
151 (screen_height - texBackgroundHeight) / 2,
152 texBackgroundWidth, texBackgroundHeight );
153 haveBackground = true;
154 glBindTexture(GL_TEXTURE_2D, 0);
156 ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
160 SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
161 if( ! my_shader->_depth_test )
162 glDisable( GL_DEPTH_TEST );
163 glDepthMask( GL_FALSE );
164 glDisable( GL_LIGHTING );
166 // noise texture, tex coord from the model translated by a time factor
167 glActiveTexturePtr( GL_TEXTURE0_ARB );
168 glEnable(GL_TEXTURE_2D);
169 const float noiseDist = fmodf(- totalTime * my_shader->_factor * my_shader->_speed, 4.0f);
170 glMatrixMode(GL_TEXTURE);
172 glTranslatef( noiseDist, 0.0f, 0.0f );
173 glMatrixMode(GL_MODELVIEW);
175 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
177 // background texture
178 glActiveTexturePtr( GL_TEXTURE1_ARB );
179 glEnable(GL_TEXTURE_2D);
180 glBindTexture(GL_TEXTURE_2D, texBackground);
182 // automatic generation of texture coordinates
183 // map to screen space
184 sgMat4 CameraProjM, CameraViewM, textureMatrix;
186 glGetIntegerv( GL_VIEWPORT, viewport );
187 const int screen_width = viewport[2];
188 const int screen_height = viewport[3];
189 glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *) CameraProjM);
190 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) CameraViewM);
191 const float dummy_scale = 1.0f; //0.95f;
192 const float deltaPos = 0.05f;
193 glMatrixMode(GL_TEXTURE);
195 glTranslatef( 0.5f, 0.5f, 0.0f );
196 glScalef( float( screen_width ) / float( texBackgroundWidth ) * 0.5f * dummy_scale,
197 float( screen_height ) / float( texBackgroundHeight ) * 0.5f * dummy_scale, 1.0f );
198 glMultMatrixf( (GLfloat *) CameraProjM );
199 glMultMatrixf( (GLfloat *) CameraViewM );
200 glTranslatef( deltaPos, deltaPos, deltaPos );
201 glMatrixMode(GL_MODELVIEW);
203 sgMakeIdentMat4( textureMatrix );
204 glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
205 glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
206 glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
207 glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR );
208 glTexGenfv( GL_S, GL_EYE_PLANE, textureMatrix[0] );
209 glTexGenfv( GL_T, GL_EYE_PLANE, textureMatrix[1] );
210 glTexGenfv( GL_R, GL_EYE_PLANE, textureMatrix[2] );
211 glTexGenfv( GL_Q, GL_EYE_PLANE, textureMatrix[3] );
212 glEnable( GL_TEXTURE_GEN_S );
213 glEnable( GL_TEXTURE_GEN_T );
214 glEnable( GL_TEXTURE_GEN_R );
215 glEnable( GL_TEXTURE_GEN_Q );
217 sgVec4 enviro = {1.00f, 1.00f, 1.00f, 0.85f};
219 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
220 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
221 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE );
222 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
223 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB );
224 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
225 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
227 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
228 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE0_ARB);
229 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
230 // glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT_ARB );
231 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PRIMARY_COLOR_ARB );
232 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA_ARB, GL_SRC_ALPHA );
234 glCallList ( dlist ) ;
235 glMatrixMode(GL_TEXTURE);
236 glTranslatef( - deltaPos*2.0f, -deltaPos*2.5f, -deltaPos*2.0f );
237 glMatrixMode(GL_MODELVIEW);
238 glCallList ( dlist ) ;
240 // alter colors only on last rendering
241 sgVec4 fLight = {0.93f, 0.93f, 1.00f, 0.85f};
242 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB );
243 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
244 // glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fLight);
246 glMatrixMode(GL_TEXTURE);
247 glTranslatef( deltaPos*0.7f, deltaPos*1.7f, deltaPos*0.7f );
248 glMatrixMode(GL_MODELVIEW);
249 glCallList ( dlist ) ;
252 glActiveTexturePtr( GL_TEXTURE1_ARB );
253 glDisable( GL_TEXTURE_GEN_S );
254 glDisable( GL_TEXTURE_GEN_T );
255 glDisable( GL_TEXTURE_GEN_R );
256 glDisable( GL_TEXTURE_GEN_Q );
257 glMatrixMode(GL_TEXTURE);
259 glMatrixMode(GL_MODELVIEW);
260 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
261 glDisable(GL_TEXTURE_2D);
262 glActiveTexturePtr( GL_TEXTURE0_ARB );
263 glMatrixMode(GL_TEXTURE);
265 glMatrixMode(GL_MODELVIEW);
266 glEnable(GL_TEXTURE_2D);
267 glBindTexture(GL_TEXTURE_2D, 0);
270 if( ! my_shader->_depth_test )
271 glEnable( GL_DEPTH_TEST );
273 glEnable( GL_LIGHTING );
274 glDepthMask( GL_TRUE );
282 static int fresnel_shader_callback( ssgEntity *e ) {
284 ssgLeaf *leaf = (ssgLeaf *) e;
285 #ifdef _SSG_USE_DLIST
286 dlist = leaf->getDListIndex();
289 dlist = leaf->getDListIndex();
294 ssgSimpleState *sst = ((ssgSimpleState *)leaf->getState());
298 sgVec4 sunColor, ambientColor;
299 ssgGetLight( 0 )->getColour(GL_DIFFUSE, sunColor );
300 ssgGetLight( 0 )->getColour(GL_AMBIENT, ambientColor );
302 SGShaderAnimation *my_shader = (SGShaderAnimation *) ( e->getUserData() );
304 glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
305 glEnable(GL_ALPHA_TEST);
306 glAlphaFunc(GL_GREATER, 0.0f);
309 // sgVec4 R = {0.5,0.0,0.0,0.0};
310 sgVec4 enviro = {1.0,0.0,0.0,1.0};
311 // sgCopyVec4( enviro, sunColor );
312 glActiveTexturePtr( GL_TEXTURE0_ARB );
313 glEnable(GL_TEXTURE_2D);
314 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
315 glActiveTexturePtr( GL_TEXTURE1_ARB );
316 glDisable(GL_TEXTURE_2D);
317 glEnable(GL_TEXTURE_1D);
318 glBindTexture(GL_TEXTURE_1D, texFresnel);
319 // c = a0 * a2 + a1 * (1-a2)
320 // glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
321 // glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
322 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
323 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE_ARB );
324 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
325 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
326 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB );
327 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
328 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE );
329 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
330 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, enviro);
333 glCallList ( dlist ) ;
334 shFresnel->disable();
335 glActiveTexturePtr( GL_TEXTURE1_ARB );
336 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
337 glDisable(GL_TEXTURE_1D);
338 glActiveTexturePtr( GL_TEXTURE0_ARB );
339 glDisable(GL_TEXTURE_1D);
340 glEnable(GL_TEXTURE_2D);
343 // glBindTexture(GL_TEXTURE_2D, 0);
344 // glDepthFunc(GL_LESS);
345 // glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
353 static void init_shaders(void) {
355 if( Shader::is_VP_supported() ) {
356 shFresnel = new Shader("/FlightGear/data/Textures/fresnel_vp.txt", "fresnel_vp");
357 // shFresnel->bindNames("somedata", 0);
359 glActiveTexturePtr = (glActiveTextureProc) SGLookupFunction("glActiveTextureARB");
360 const int fresnelSize = 512;
361 unsigned char imageFresnel[ fresnelSize * 3 ];
362 for(int i = 0; i < fresnelSize; i++) {
363 const float R0 = 0.2f;
364 float NdotV = float( i ) / float( fresnelSize );
365 float f = R0 + (1.0f-R0)*pow(1.0f - NdotV, 5);
366 unsigned char ff = (unsigned char) (f * 255.0);
367 imageFresnel[i*3+0] = imageFresnel[i*3+1] = imageFresnel[i*3+2] = ff;
369 glGenTextures( 1, &texFresnel );
370 glBindTexture(GL_TEXTURE_1D, texFresnel );
371 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
372 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
373 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
374 glTexParameteri(GL_TEXTURE_1D, GL_GENERATE_MIPMAP_SGIS, true);
375 glTexImage1D(GL_TEXTURE_1D, 0, 3, fresnelSize, 0, GL_RGB, GL_UNSIGNED_BYTE, imageFresnel);
376 glBindTexture(GL_TEXTURE_1D, 0 );
381 ////////////////////////////////////////////////////////////////////////
382 // Implementation of SGShaderAnimation
383 ////////////////////////////////////////////////////////////////////////
385 SGShaderAnimation::SGShaderAnimation ( SGPropertyNode *prop_root,
386 SGPropertyNode_ptr props )
387 : SGAnimation(props, new ssgBranch),
389 _condition_value(true),
391 _param_1(props->getFloatValue("param", 1.0f)),
392 _depth_test(props->getBoolValue("depth-test", true)),
393 _factor(props->getFloatValue("factor", 1.0f)),
395 _speed(props->getFloatValue("speed", 1.0f)),
399 SGPropertyNode_ptr node = props->getChild("condition");
401 _condition = sgReadCondition(prop_root, node);
402 _condition_value = false;
404 node = props->getChild("factor-prop");
406 _factor_prop = prop_root->getNode(node->getStringValue(), true);
407 node = props->getChild("speed-prop");
409 _speed_prop = prop_root->getNode(node->getStringValue(), true);
411 string shader_name = props->getStringValue("shader");
412 if( shader_name == "fresnel" || shader_name == "reflection" )
414 else if( shader_name == "heat-haze" )
418 static void setCallBack(ssgBranch *branch, ssgBase *user_data, ssgCallback cb) {
419 for (int i = 0; i < branch->getNumKids(); i++) {
420 ssgEntity *e = branch->getKid(i);
421 if( e->isAKindOf( ssgTypeBranch() ) )
422 setCallBack( (ssgBranch *) e, user_data, cb);
423 else if( e->isAKindOf( ssgTypeVtxTable() ) ) {
424 e->setCallback( SSG_CALLBACK_PREDRAW, cb );
425 e->setUserData( user_data );
430 void SGShaderAnimation::init()
434 if( _shader_type == 1 && Shader::is_VP_supported() )
435 setCallBack( getBranch(), (ssgBase *) this, fresnel_shader_callback );
436 else if( _shader_type == 2 )
437 setCallBack( getBranch(), (ssgBase *) this, heat_haze_shader_callback );
439 setCallBack( getBranch(), (ssgBase *) this, null_shader_callback );
442 SGShaderAnimation::~SGShaderAnimation()
448 SGShaderAnimation::update()
451 _condition_value = _condition->test();
453 _factor = _factor_prop->getFloatValue();
455 _speed = _speed_prop->getFloatValue();
459 void sgShaderFrameInit(double delta_time_sec) {
460 haveBackground = false;
461 totalTime += delta_time_sec;