//------------------------------------------------------------------------ // // Author : Dario Corno (rIo) / Jeff Molofee (NeHe) // Converted to Delphi : Jan Horn // Email : jhorn@global.co.za // Website : http://www.sulaco.co.za // Authors Web Site : http://www.spinningkids.org/rio // Date : 14 October 2001 // Version : 1.0 // Description : Radial Blur // // Adapted to FPC : Sebastian Guenther (sg@freepascal.org) 2001-11-21 // //------------------------------------------------------------------------ program RadialBlur; {$mode objfpc} uses GL, GLU, GLUT; const WND_TITLE = 'Radial Blur'; type TVector = Array[0..2] of glFloat; var ElapsedTime : Integer; // Elapsed time between frames // Textures BlurTexture : glUint; // An Unsigned Int To Store The Texture Number // User vaiables Angle : glFloat; Vertexes : Array[0..3] of TVector; normal : TVector; const FPSCount : Integer = 0; // Counter for FPS // Lights and Materials globalAmbient : Array[0..3] of glFloat = (0.2, 0.2, 0.2, 1.0); // Set Ambient Lighting To Fairly Dark Light (No Color) Light0Pos : Array[0..3] of glFloat = (0.0, 5.0, 10.0, 1.0); // Set The Light Position Light0Ambient : Array[0..3] of glFloat = (0.2, 0.2, 0.2, 1.0); // More Ambient Light Light0Diffuse : Array[0..3] of glFloat = (0.3, 0.3, 0.3, 1.0); // Set The Diffuse Light A Bit Brighter Light0Specular : Array[0..3] of glFloat = (0.8, 0.8, 0.8, 1.0); // Fairly Bright Specular Lighting LmodelAmbient : Array[0..3] of glFloat = (0.2, 0.2, 0.2, 1.0); // And More Ambient Light function EmptyTexture : glUint; var txtnumber : glUint; pData : Pointer; begin // Create Storage Space For Texture Data (128x128x4) GetMem(pData, 128*128*4); glGenTextures(1, @txtnumber); // Create 1 Texture glBindTexture(GL_TEXTURE_2D, txtnumber); // Bind The Texture glTexImage2D(GL_TEXTURE_2D, 0, 4, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); result :=txtNumber; end; procedure ReduceToUnit(var vector : Array of glFloat); var length : glFLoat; begin // Calculates The Length Of The Vector length := sqrt((vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2])); if Length = 0 then Length :=1; vector[0] :=vector[0] / length; vector[1] :=vector[1] / length; vector[2] :=vector[2] / length; end; procedure calcNormal(const v : Array of TVector; var cross : Array of glFloat); var v1, v2 : Array[0..2] of glFloat; begin // Finds The Vector Between 2 Points By Subtracting // The x,y,z Coordinates From One Point To Another. // Calculate The Vector From Point 1 To Point 0 v1[0] := v[0][0] - v[1][0]; // Vector 1.x=Vertex[0].x-Vertex[1].x v1[1] := v[0][1] - v[1][1]; // Vector 1.y=Vertex[0].y-Vertex[1].y v1[2] := v[0][2] - v[1][2]; // Vector 1.z=Vertex[0].y-Vertex[1].z // Calculate The Vector From Point 2 To Point 1 v2[0] := v[1][0] - v[2][0]; // Vector 2.x=Vertex[0].x-Vertex[1].x v2[1] := v[1][1] - v[2][1]; // Vector 2.y=Vertex[0].y-Vertex[1].y v2[2] := v[1][2] - v[2][2]; // Vector 2.z=Vertex[0].z-Vertex[1].z // Compute The Cross Product To Give Us A Surface Normal cross[0] := v1[1]*v2[2] - v1[2]*v2[1]; // Cross Product For Y - Z cross[1] := v1[2]*v2[0] - v1[0]*v2[2]; // Cross Product For X - Z cross[2] := v1[0]*v2[1] - v1[1]*v2[0]; // Cross Product For X - Y ReduceToUnit(cross); // Normalize The Vectors end; // Draws A Helix procedure ProcessHelix; const Twists = 5; MaterialColor : Array[1..4] of glFloat = (0.4, 0.2, 0.8, 1.0); Specular : Array[1..4] of glFloat = (1, 1, 1, 1); var x, y, z : glFLoat; phi, theta : Integer; r, u, v : glFLoat; begin glLoadIdentity(); // Reset The Modelview Matrix gluLookAt(0, 5, 50, 0, 0, 0, 0, 1, 0); // Eye Position (0,5,50) Center Of Scene (0,0,0), Up On Y Axis glPushMatrix(); // Push The Modelview Matrix glTranslatef(0,0,-50); // Translate 50 Units Into The Screen glRotatef(angle/2.0, 1, 0, 0); // Rotate By angle/2 On The X-Axis glRotatef(angle/3.0, 0, 1, 0); // Rotate By angle/3 On The Y-Axis glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, @MaterialColor); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, @specular); r :=1.5; // Radius glBegin(GL_QUADS); // Begin Drawing Quads phi :=0; while phi < 360 do begin theta :=0; while theta < 360*twists do begin v := phi / 180.0 * pi; // Calculate Angle Of First Point ( 0 ) u := theta / 180.0 * pi; // Calculate Angle Of First Point ( 0 ) x :=cos(u)*(2 + cos(v))*r; // Calculate x Position (1st Point) y :=sin(u)*(2 + cos(v))*r; // Calculate y Position (1st Point) z :=(u-(2*pi) + sin(v))*r; // Calculate z Position (1st Point) vertexes[0][0] :=x; // Set x Value Of First Vertex vertexes[0][1] :=y; // Set y Value Of First Vertex vertexes[0][2] :=z; // Set z Value Of First Vertex v :=(phi/180.0 * pi); // Calculate Angle Of Second Point ( 0 ) u :=((theta+20)/180.0 * pi); // Calculate Angle Of Second Point ( 20 ) x :=cos(u)*(2 + cos(v))*r; // Calculate x Position (2nd Point) y :=sin(u)*(2 + cos(v))*r; // Calculate y Position (2nd Point) z :=(u-(2*pi) + sin(v))*r; // Calculate z Position (2nd Point) vertexes[1][0] :=x; // Set x Value Of Second Vertex vertexes[1][1] :=y; // Set y Value Of Second Vertex vertexes[1][2] :=z; // Set z Value Of Second Vertex v :=(phi+20)/180.0*pi; // Calculate Angle Of Third Point ( 20 ) u :=(theta+20)/180.0*pi; // Calculate Angle Of Third Point ( 20 ) x :=cos(u)*(2 + cos(v))*r; // Calculate x Position (3rd Point) y :=sin(u)*(2 + cos(v))*r; // Calculate y Position (3rd Point) z :=(u-(2*pi) + sin(v))*r; // Calculate z Position (3rd Point) vertexes[2][0] :=x; // Set x Value Of Third Vertex vertexes[2][1] :=y; // Set y Value Of Third Vertex vertexes[2][2] :=z; // Set z Value Of Third Vertex v :=(phi+20)/180.0*pi; // Calculate Angle Of Fourth Point ( 20 ) u :=theta / 180.0*pi; // Calculate Angle Of Fourth Point ( 0 ) x :=cos(u)*(2 + cos(v))*r; // Calculate x Position (4th Point) y :=sin(u)*(2 + cos(v))*r; // Calculate y Position (4th Point) z :=(u-(2*pi) + sin(v))*r; // Calculate z Position (4th Point) vertexes[3][0] :=x; // Set x Value Of Fourth Vertex vertexes[3][1] :=y; // Set y Value Of Fourth Vertex vertexes[3][2] :=z; // Set z Value Of Fourth Vertex calcNormal(vertexes, normal); // Calculate The Quad Normal glNormal3f(normal[0],normal[1],normal[2]); // Set The Normal // Render The Quad glVertex3f(vertexes[0][0],vertexes[0][1],vertexes[0][2]); glVertex3f(vertexes[1][0],vertexes[1][1],vertexes[1][2]); glVertex3f(vertexes[2][0],vertexes[2][1],vertexes[2][2]); glVertex3f(vertexes[3][0],vertexes[3][1],vertexes[3][2]); theta := theta + 20; end; phi :=phi + 20; end; glEnd(); // Done Rendering Quads glPopMatrix(); // Pop The Matrix end; // Set Up An Ortho View procedure ViewOrtho; begin glMatrixMode(GL_PROJECTION); // Select Projection glPushMatrix(); // Push The Matrix glLoadIdentity(); // Reset The Matrix glOrtho( 0, 640 , 480 , 0, -1, 1 ); // Select Ortho Mode (640x480) glMatrixMode(GL_MODELVIEW); // Select Modelview Matrix glPushMatrix(); // Push The Matrix glLoadIdentity(); // Reset The Matrix end; // Set Up A Perspective View procedure ViewPerspective; begin glMatrixMode( GL_PROJECTION ); // Select Projection glPopMatrix(); // Pop The Matrix glMatrixMode( GL_MODELVIEW ); // Select Modelview glPopMatrix(); // Pop The Matrix end; // Renders To A Texture procedure RenderToTexture; begin glViewport(0, 0, 128, 128); // Set Our Viewport (Match Texture Size) ProcessHelix(); // Render The Helix glBindTexture(GL_TEXTURE_2D,BlurTexture); // Bind To The Blur Texture // Copy Our ViewPort To The Blur Texture (From 0,0 To 128,128... No Border) glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 0, 0, 128, 128, 0); glClearColor(0.0, 0.0, 0.5, 0.5); // Set The Clear Color To Medium Blue glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT); // Clear The Screen And Depth Buffer glViewport(0, 0, 640 ,480); // Set Viewport (0,0 to 640x480) end; // Draw The Blurred Image procedure DrawBlur(const times : Integer; const inc : glFloat); var spost, alpha, alphainc : glFloat; I : Integer; begin alpha := 0.2; glEnable(GL_TEXTURE_2D); // Enable 2D Texture Mapping glDisable(GL_DEPTH_TEST); // Disable Depth Testing glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Set Blending Mode glEnable(GL_BLEND); // Enable Blending glBindTexture(GL_TEXTURE_2D,BlurTexture); // Bind To The Blur Texture ViewOrtho(); // Switch To An Ortho View alphainc := alpha / times; // alphainc=0.2f / Times To Render Blur glBegin(GL_QUADS); // Begin Drawing Quads // Number Of Times To Render Blur For I :=0 to times-1 do begin glColor4f(1.0, 1.0, 1.0, alpha); // Set The Alpha Value (Starts At 0.2) glTexCoord2f(0+spost,1-spost); // Texture Coordinate ( 0, 1 ) glVertex2f(0,0); // First Vertex ( 0, 0 ) glTexCoord2f(0+spost,0+spost); // Texture Coordinate ( 0, 0 ) glVertex2f(0,480); // Second Vertex ( 0, 480 ) glTexCoord2f(1-spost,0+spost); // Texture Coordinate ( 1, 0 ) glVertex2f(640,480); // Third Vertex ( 640, 480 ) glTexCoord2f(1-spost,1-spost); // Texture Coordinate ( 1, 1 ) glVertex2f(640,0); // Fourth Vertex ( 640, 0 ) spost := spost + inc; // Gradually Increase spost (Zooming Closer To Texture Center) alpha := alpha - alphainc; // Gradually Decrease alpha (Gradually Fading Image Out) end; glEnd(); // Done Drawing Quads ViewPerspective(); // Switch To A Perspective View glEnable(GL_DEPTH_TEST); // Enable Depth Testing glDisable(GL_TEXTURE_2D); // Disable 2D Texture Mapping glDisable(GL_BLEND); // Disable Blending glBindTexture(GL_TEXTURE_2D,0); // Unbind The Blur Texture end; {------------------------------------------------------------------} { Function to draw the actual scene } {------------------------------------------------------------------} procedure glDraw; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); // Reset The View RenderToTexture; // Render To A Texture ProcessHelix; // Draw Our Helix DrawBlur(25, 0.02); // Draw The Blur Effect angle :=ElapsedTime / 5.0; // Update angle Based On The Clock end; {------------------------------------------------------------------} { Initialise OpenGL } {------------------------------------------------------------------} procedure glInit; begin glClearColor(0.0, 0.0, 0.0, 0.5); // Black Background glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading glClearDepth(1.0); // Depth Buffer Setup glDepthFunc(GL_LESS); // The Type Of Depth Test To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //Realy Nice perspective calculations glEnable(GL_DEPTH_TEST); // Enable Depth Buffer glEnable(GL_TEXTURE_2D); // Enable Texture Mapping glLightModelfv(GL_LIGHT_MODEL_AMBIENT, @LmodelAmbient); // Set The Ambient Light Model glLightModelfv(GL_LIGHT_MODEL_AMBIENT, @GlobalAmbient); // Set The Global Ambient Light Model glLightfv(GL_LIGHT0, GL_POSITION, @light0Pos); // Set The Lights Position glLightfv(GL_LIGHT0, GL_AMBIENT, @light0Ambient); // Set The Ambient Light glLightfv(GL_LIGHT0, GL_DIFFUSE, @light0Diffuse); // Set The Diffuse Light glLightfv(GL_LIGHT0, GL_SPECULAR, @light0Specular); // Set Up Specular Lighting glEnable(GL_LIGHTING); // Enable Lighting glEnable(GL_LIGHT0); // Enable Light0 BlurTexture := EmptyTexture(); // Create Our Empty Texture glShadeModel(GL_SMOOTH); // Select Smooth Shading glMateriali(GL_FRONT, GL_SHININESS, 128); end; {------------------------------------------------------------------} { Handle window resize } {------------------------------------------------------------------} procedure glResizeWnd(Width, Height : Integer); begin if (Height = 0) then // prevent divide by zero exception Height := 1; glViewport(0, 0, Width, Height); // Set the viewport for the OpenGL window glMatrixMode(GL_PROJECTION); // Change Matrix Mode to Projection glLoadIdentity(); // Reset View gluPerspective(45.0, Width/glFloat(Height), 2.0, 200.0); // Do the perspective calculations. Last value = max clipping depth glMatrixMode(GL_MODELVIEW); // Return to the modelview matrix glLoadIdentity(); // Reset View end; var DemoStart, LastTime : LongWord; procedure DisplayWindow; cdecl; begin Inc(FPSCount); // Increment FPS Counter LastTime :=ElapsedTime; ElapsedTime := glutGet(GLUT_ELAPSED_TIME) - DemoStart; // Calculate Elapsed Time ElapsedTime :=(LastTime + ElapsedTime) DIV 2; // Average it out for smoother movement glDraw; glutSwapBuffers; Inc(ElapsedTime, 10); glutPostRedisplay; end; procedure OnReshape(width, height: Integer); cdecl; begin glResizeWnd(width, height); end; begin glutInit(@argc, argv); glutInitDisplayMode(GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH); glutCreateWindow(WND_TITLE); glutDisplayFunc(@DisplayWindow); glutReshapeFunc(@OnReshape); glutInitWindowSize(640, 480); glInit; DemoStart := glutGet(GLUT_ELAPSED_TIME); glutMainLoop; end.