// This code was written for the OpenTK library and has been released // to the Public Domain. // It is provided "as is" without express or implied warranty of any kind. using System; using System.Drawing; using System.Collections.Generic; using System.Diagnostics; using System.Windows.Forms; using System.IO; using System.Text; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using Examples.Shapes; using Examples.TextureLoaders; namespace Examples.Tutorial { [Example("DDS Cube Map", ExampleCategory.OpenGL, "2.x", Documentation = "DDSCubeMap")] public class T13_GLSL_Earth: GameWindow { public T13_GLSL_Earth( ) : base( 800, 800 ) { } #region internal Fields // Shader int VertexShaderObject, FragmentShaderObject, ProgramObject; const string VertexShaderFilename = "Data/Shaders/CubeMap_VS.glsl"; const string FragmentShaderFilename = "Data/Shaders/CubeMap_FS.glsl"; // Textures const TextureUnit TMU0_Unit = TextureUnit.Texture0; const int TMU0_UnitInteger = 0; const string TMU0_Filename = "Data/Textures/earth-cubemap.dds"; uint TMU0_Handle; TextureTarget TMU0_Target; // DL DrawableShape sphere; // Camera Vector3 EyePos = new Vector3( 0.0f, 0.0f, 6.0f ); Vector3 Trackball = Vector3.Zero; #endregion internal Fields /// Setup OpenGL and load resources here. /// Not used. protected override void OnLoad(EventArgs e) { this.VSync = VSyncMode.Off; // Check for necessary capabilities: string extensions = GL.GetString(StringName.Extensions); if (!GL.GetString(StringName.Extensions).Contains("GL_ARB_shading_language")) { throw new NotSupportedException(String.Format("This example requires OpenGL 2.0. Found {0}. Aborting.", GL.GetString(StringName.Version).Substring(0, 3))); } if (!extensions.Contains("GL_ARB_texture_compression") || !extensions.Contains("GL_EXT_texture_compression_s3tc")) { throw new NotSupportedException("This example requires support for texture compression. Aborting."); } #region GL State GL.ClearColor( 0f, 0f, 0f, 0f ); GL.Disable( EnableCap.Dither ); GL.Enable( EnableCap.CullFace ); GL.FrontFace( FrontFaceDirection.Ccw ); GL.PolygonMode( MaterialFace.Front, PolygonMode.Fill ); // GL.PolygonMode( MaterialFace.Back, PolygonMode.Line ); #endregion GL State #region Shaders string LogInfo; // Load&Compile Vertex Shader using ( StreamReader sr = new StreamReader( VertexShaderFilename ) ) { VertexShaderObject = GL.CreateShader( ShaderType.VertexShader ); GL.ShaderSource( VertexShaderObject, sr.ReadToEnd( ) ); GL.CompileShader( VertexShaderObject ); } GL.GetShaderInfoLog( VertexShaderObject, out LogInfo ); if ( LogInfo.Length > 0 && !LogInfo.Contains( "hardware" ) ) Trace.WriteLine( "Vertex Shader failed!\nLog:\n" + LogInfo ); else Trace.WriteLine( "Vertex Shader compiled without complaint." ); // Load&Compile Fragment Shader using ( StreamReader sr = new StreamReader( FragmentShaderFilename ) ) { FragmentShaderObject = GL.CreateShader( ShaderType.FragmentShader ); GL.ShaderSource( FragmentShaderObject, sr.ReadToEnd( ) ); GL.CompileShader( FragmentShaderObject ); } GL.GetShaderInfoLog( FragmentShaderObject, out LogInfo ); if ( LogInfo.Length > 0 && !LogInfo.Contains( "hardware" ) ) Trace.WriteLine( "Fragment Shader failed!\nLog:\n" + LogInfo ); else Trace.WriteLine( "Fragment Shader compiled without complaint." ); // Link the Shaders to a usable Program ProgramObject = GL.CreateProgram( ); GL.AttachShader( ProgramObject, VertexShaderObject ); GL.AttachShader( ProgramObject, FragmentShaderObject ); // link it all together GL.LinkProgram( ProgramObject ); // flag ShaderObjects for delete when not used anymore GL.DeleteShader( VertexShaderObject ); GL.DeleteShader( FragmentShaderObject ); int[] temp = new int[1]; GL.GetProgram(ProgramObject, GetProgramParameterName.LinkStatus, out temp[0]); Trace.WriteLine( "Linking Program (" + ProgramObject + ") " + ( ( temp[0] == 1 ) ? "succeeded." : "FAILED!" ) ); if ( temp[0] != 1 ) { GL.GetProgramInfoLog( ProgramObject, out LogInfo ); Trace.WriteLine( "Program Log:\n" + LogInfo ); } GL.GetProgram(ProgramObject, GetProgramParameterName.ActiveAttributes, out temp[0]); Trace.WriteLine( "Program registered " + temp[0] + " Attributes. (Should be 4: Pos, UV, Normal, Tangent)" ); Trace.WriteLine( "Tangent attribute bind location: " + GL.GetAttribLocation( ProgramObject, "AttributeTangent" ) ); Trace.WriteLine( "End of Shader build. GL Error: " + GL.GetError( ) ); #endregion Shaders #region Textures TextureLoaderParameters.FlipImages = false; TextureLoaderParameters.MagnificationFilter = TextureMagFilter.Linear; TextureLoaderParameters.MinificationFilter = TextureMinFilter.Linear; TextureLoaderParameters.WrapModeS = TextureWrapMode.ClampToEdge; TextureLoaderParameters.WrapModeT = TextureWrapMode.ClampToEdge; TextureLoaderParameters.EnvMode = TextureEnvMode.Modulate; ImageDDS.LoadFromDisk( TMU0_Filename, out TMU0_Handle, out TMU0_Target ); Trace.WriteLine( "Loaded " + TMU0_Filename + " with handle " + TMU0_Handle + " as " + TMU0_Target ); #endregion Textures Trace.WriteLine( "End of Texture Loading. GL Error: " + GL.GetError( ) ); Trace.WriteLine( ""); sphere = new SlicedSphere(1.5f, Vector3d.Zero, SlicedSphere.eSubdivisions.Four, new SlicedSphere.eDir[] { SlicedSphere.eDir.All }, true); } protected override void OnUnload(EventArgs e) { sphere.Dispose(); GL.DeleteProgram( ProgramObject ); GL.DeleteTextures( 1, ref TMU0_Handle ); base.OnUnload( e ); } /// Respond to resize events here. /// Contains information on the new GameWindow size. /// There is no need to call the base implementation. protected override void OnResize( EventArgs e ) { GL.Viewport( 0, 0, Width, Height ); GL.MatrixMode( MatrixMode.Projection ); Matrix4 p = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Width / (float)Height, 0.1f, 10.0f); GL.LoadMatrix(ref p); GL.MatrixMode( MatrixMode.Modelview ); GL.LoadIdentity( ); base.OnResize( e ); } /// Add your game logic here. /// Contains timing information. /// There is no need to call the base implementation. protected override void OnUpdateFrame( FrameEventArgs e ) { base.OnUpdateFrame( e ); if ( Keyboard[OpenTK.Input.Key.Escape] ) this.Exit( ); if ( Keyboard[OpenTK.Input.Key.Space] ) Trace.WriteLine( "GL: " + GL.GetError( ) ); Trackball.X = Mouse.X; Trackball.Y = Mouse.Y; Trackball.Z = Mouse.Wheel * 0.5f; } /// Add your game rendering code here. /// Contains timing information. /// There is no need to call the base implementation. protected override void OnRenderFrame(FrameEventArgs e) { this.Title = "FPS: " + (1 / e.Time).ToString("0."); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.UseProgram(ProgramObject); #region Textures GL.ActiveTexture(TMU0_Unit); GL.BindTexture(TMU0_Target, TMU0_Handle); #endregion Textures #region Uniforms GL.Uniform1(GL.GetUniformLocation(ProgramObject, "Earth"), TMU0_UnitInteger); #endregion Uniforms GL.PushMatrix(); Matrix4 temp = Matrix4.LookAt(EyePos, Vector3.Zero, Vector3.UnitY); GL.MultMatrix(ref temp); GL.Rotate(Trackball.X, Vector3.UnitY); GL.Rotate(Trackball.Y, Vector3.UnitX); #region Draw GL.Color3(1f, 1f, 1f); sphere.Draw(); #endregion Draw GL.PopMatrix(); this.SwapBuffers(); } /// Entry point [STAThread] public static void Main( ) { using ( T13_GLSL_Earth example = new T13_GLSL_Earth( ) ) { Utilities.SetWindowTitle(example); example.Run( 30.0, 0.0 ); } } } }