2009-02-22 11:43:35 +01:00
|
|
|
|
#region --- License ---
|
|
|
|
|
/* Licensed under the MIT/X11 license.
|
|
|
|
|
* Copyright (c) 2006-2008 the OpenTK Team.
|
|
|
|
|
* This notice may not be removed from any source distribution.
|
|
|
|
|
* See license.txt for licensing detailed licensing details.
|
|
|
|
|
*/
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region --- Using Directives ---
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
|
|
|
|
using OpenTK;
|
|
|
|
|
using OpenTK.Graphics;
|
|
|
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
|
|
|
|
|
|
#endregion --- Using Directives ---
|
|
|
|
|
|
|
|
|
|
namespace Examples.Tutorial
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Demonstrates how to load and use a simple OpenGL shader program. Example is incomplete (documentation).
|
|
|
|
|
/// </summary>
|
2009-04-20 11:48:33 +02:00
|
|
|
|
[Example("First shader", ExampleCategory.OpenGL, "GLSL", Documentation="SimpleGLSL")]
|
2009-02-22 11:43:35 +01:00
|
|
|
|
public class T10_GLSL_Cube : GameWindow
|
|
|
|
|
{
|
|
|
|
|
#region --- Fields ---
|
|
|
|
|
|
|
|
|
|
static float angle = 0.0f, rotation_speed = 3.0f;
|
|
|
|
|
int vertex_shader_object, fragment_shader_object, shader_program;
|
|
|
|
|
int vertex_buffer_object, color_buffer_object, element_buffer_object;
|
|
|
|
|
|
|
|
|
|
Shapes.Shape shape = new Examples.Shapes.Cube();
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region --- Constructors ---
|
|
|
|
|
|
|
|
|
|
public T10_GLSL_Cube()
|
|
|
|
|
: base(800, 600, GraphicsMode.Default)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region OnLoad
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This is the place to load resources that change little
|
|
|
|
|
/// during the lifetime of the GameWindow. In this case, we
|
|
|
|
|
/// check for GLSL support, and load the shaders.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="e">Not used.</param>
|
2009-10-21 15:33:00 +02:00
|
|
|
|
protected override void OnLoad(EventArgs e)
|
2009-02-22 11:43:35 +01:00
|
|
|
|
{
|
|
|
|
|
// Check for necessary capabilities:
|
2009-08-17 11:57:43 +02:00
|
|
|
|
string version = GL.GetString(StringName.Version);
|
|
|
|
|
int major = (int)version[0];
|
|
|
|
|
int minor = (int)version[2];
|
|
|
|
|
if (major < 2)
|
2009-02-22 11:43:35 +01:00
|
|
|
|
{
|
|
|
|
|
MessageBox.Show("You need at least OpenGL 2.0 to run this example. Aborting.", "GLSL not supported",
|
|
|
|
|
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
|
|
|
this.Exit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GL.ClearColor(Color.MidnightBlue);
|
|
|
|
|
GL.Enable(EnableCap.DepthTest);
|
|
|
|
|
|
|
|
|
|
CreateVBO();
|
|
|
|
|
|
|
|
|
|
using (StreamReader vs = new StreamReader("Data/Shaders/Simple_VS.glsl"))
|
|
|
|
|
using (StreamReader fs = new StreamReader("Data/Shaders/Simple_FS.glsl"))
|
|
|
|
|
CreateShaders(vs.ReadToEnd(), fs.ReadToEnd(),
|
|
|
|
|
out vertex_shader_object, out fragment_shader_object,
|
|
|
|
|
out shader_program);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region CreateShaders
|
|
|
|
|
|
|
|
|
|
void CreateShaders(string vs, string fs,
|
|
|
|
|
out int vertexObject, out int fragmentObject,
|
|
|
|
|
out int program)
|
|
|
|
|
{
|
|
|
|
|
int status_code;
|
|
|
|
|
string info;
|
|
|
|
|
|
|
|
|
|
vertexObject = GL.CreateShader(ShaderType.VertexShader);
|
|
|
|
|
fragmentObject = GL.CreateShader(ShaderType.FragmentShader);
|
|
|
|
|
|
|
|
|
|
// Compile vertex shader
|
|
|
|
|
GL.ShaderSource(vertexObject, vs);
|
|
|
|
|
GL.CompileShader(vertexObject);
|
|
|
|
|
GL.GetShaderInfoLog(vertexObject, out info);
|
|
|
|
|
GL.GetShader(vertexObject, ShaderParameter.CompileStatus, out status_code);
|
|
|
|
|
|
|
|
|
|
if (status_code != 1)
|
|
|
|
|
throw new ApplicationException(info);
|
|
|
|
|
|
|
|
|
|
// Compile vertex shader
|
|
|
|
|
GL.ShaderSource(fragmentObject, fs);
|
|
|
|
|
GL.CompileShader(fragmentObject);
|
|
|
|
|
GL.GetShaderInfoLog(fragmentObject, out info);
|
|
|
|
|
GL.GetShader(fragmentObject, ShaderParameter.CompileStatus, out status_code);
|
|
|
|
|
|
|
|
|
|
if (status_code != 1)
|
|
|
|
|
throw new ApplicationException(info);
|
|
|
|
|
|
|
|
|
|
program = GL.CreateProgram();
|
|
|
|
|
GL.AttachShader(program, fragmentObject);
|
|
|
|
|
GL.AttachShader(program, vertexObject);
|
|
|
|
|
|
|
|
|
|
GL.LinkProgram(program);
|
|
|
|
|
GL.UseProgram(program);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region private void CreateVBO()
|
|
|
|
|
|
|
|
|
|
void CreateVBO()
|
|
|
|
|
{
|
|
|
|
|
int size;
|
|
|
|
|
|
|
|
|
|
GL.GenBuffers(1, out vertex_buffer_object);
|
|
|
|
|
GL.GenBuffers(1, out color_buffer_object);
|
|
|
|
|
GL.GenBuffers(1, out element_buffer_object);
|
|
|
|
|
|
|
|
|
|
// Upload the vertex buffer.
|
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vertex_buffer_object);
|
|
|
|
|
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(shape.Vertices.Length * 3 * sizeof(float)), shape.Vertices,
|
|
|
|
|
BufferUsageHint.StaticDraw);
|
|
|
|
|
GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out size);
|
|
|
|
|
if (size != shape.Vertices.Length * 3 * sizeof(Single))
|
|
|
|
|
throw new ApplicationException(String.Format(
|
|
|
|
|
"Problem uploading vertex buffer to VBO (vertices). Tried to upload {0} bytes, uploaded {1}.",
|
|
|
|
|
shape.Vertices.Length * 3 * sizeof(Single), size));
|
|
|
|
|
|
|
|
|
|
// Upload the color buffer.
|
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, color_buffer_object);
|
|
|
|
|
GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(shape.Colors.Length * sizeof(int)), shape.Colors,
|
|
|
|
|
BufferUsageHint.StaticDraw);
|
|
|
|
|
GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out size);
|
|
|
|
|
if (size != shape.Colors.Length * sizeof(int))
|
|
|
|
|
throw new ApplicationException(String.Format(
|
|
|
|
|
"Problem uploading vertex buffer to VBO (colors). Tried to upload {0} bytes, uploaded {1}.",
|
|
|
|
|
shape.Colors.Length * sizeof(int), size));
|
|
|
|
|
|
|
|
|
|
// Upload the index buffer (elements inside the vertex buffer, not color indices as per the IndexPointer function!)
|
|
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, element_buffer_object);
|
|
|
|
|
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(shape.Indices.Length * sizeof(Int32)), shape.Indices,
|
|
|
|
|
BufferUsageHint.StaticDraw);
|
|
|
|
|
GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out size);
|
|
|
|
|
if (size != shape.Indices.Length * sizeof(int))
|
|
|
|
|
throw new ApplicationException(String.Format(
|
|
|
|
|
"Problem uploading vertex buffer to VBO (offsets). Tried to upload {0} bytes, uploaded {1}.",
|
|
|
|
|
shape.Indices.Length * sizeof(int), size));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region OnUnload
|
|
|
|
|
|
2009-10-21 15:51:39 +02:00
|
|
|
|
protected override void OnUnload(EventArgs e)
|
2009-02-22 11:43:35 +01:00
|
|
|
|
{
|
|
|
|
|
if (shader_program != 0)
|
|
|
|
|
GL.DeleteProgram(shader_program);
|
|
|
|
|
if (fragment_shader_object != 0)
|
|
|
|
|
GL.DeleteShader(fragment_shader_object);
|
|
|
|
|
if (vertex_shader_object != 0)
|
|
|
|
|
GL.DeleteShader(vertex_shader_object);
|
|
|
|
|
if (vertex_buffer_object != 0)
|
|
|
|
|
GL.DeleteBuffers(1, ref vertex_buffer_object);
|
|
|
|
|
if (element_buffer_object != 0)
|
|
|
|
|
GL.DeleteBuffers(1, ref element_buffer_object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region OnResize
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Called when the user resizes the window.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="e">Contains the new width/height of the window.</param>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// You want the OpenGL viewport to match the window. This is the place to do it!
|
|
|
|
|
/// </remarks>
|
2009-06-02 17:49:39 +02:00
|
|
|
|
protected override void OnResize(EventArgs e)
|
2009-02-22 11:43:35 +01:00
|
|
|
|
{
|
|
|
|
|
GL.Viewport(0, 0, Width, Height);
|
|
|
|
|
|
2009-08-14 15:13:28 +02:00
|
|
|
|
float aspect_ratio = Width / (float)Height;
|
2009-08-15 19:52:49 +02:00
|
|
|
|
Matrix4 perpective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 64);
|
2009-02-22 11:43:35 +01:00
|
|
|
|
GL.MatrixMode(MatrixMode.Projection);
|
2009-08-14 15:13:28 +02:00
|
|
|
|
GL.LoadMatrix(ref perpective);
|
2009-02-22 11:43:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region OnUpdateFrame
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Prepares the next frame for rendering.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Place your control logic here. This is the place to respond to user input,
|
|
|
|
|
/// update object positions etc.
|
|
|
|
|
/// </remarks>
|
2009-06-02 17:49:39 +02:00
|
|
|
|
protected override void OnUpdateFrame(FrameEventArgs e)
|
2009-02-22 11:43:35 +01:00
|
|
|
|
{
|
|
|
|
|
if (Keyboard[OpenTK.Input.Key.Escape])
|
|
|
|
|
this.Exit();
|
|
|
|
|
|
2010-02-03 20:04:42 +01:00
|
|
|
|
if (Keyboard[OpenTK.Input.Key.F11])
|
2009-02-22 11:43:35 +01:00
|
|
|
|
if (WindowState != WindowState.Fullscreen)
|
|
|
|
|
WindowState = WindowState.Fullscreen;
|
|
|
|
|
else
|
|
|
|
|
WindowState = WindowState.Normal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region OnRenderFrame
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Place your rendering code here.
|
|
|
|
|
/// </summary>
|
2009-06-02 17:49:39 +02:00
|
|
|
|
protected override void OnRenderFrame(FrameEventArgs e)
|
2009-02-22 11:43:35 +01:00
|
|
|
|
{
|
|
|
|
|
GL.Clear(ClearBufferMask.ColorBufferBit |
|
|
|
|
|
ClearBufferMask.DepthBufferBit);
|
|
|
|
|
|
2009-08-14 15:13:28 +02:00
|
|
|
|
Matrix4 lookat = Matrix4.LookAt(0, 5, 5, 0, 0, 0, 0, 1, 0);
|
2009-02-22 11:43:35 +01:00
|
|
|
|
GL.MatrixMode(MatrixMode.Modelview);
|
2009-08-14 15:13:28 +02:00
|
|
|
|
GL.LoadMatrix(ref lookat);
|
2009-02-22 11:43:35 +01:00
|
|
|
|
|
2009-06-02 17:49:39 +02:00
|
|
|
|
angle += rotation_speed * (float)e.Time;
|
2009-02-22 11:43:35 +01:00
|
|
|
|
GL.Rotate(angle, 0.0f, 1.0f, 0.0f);
|
|
|
|
|
|
|
|
|
|
GL.EnableClientState(EnableCap.VertexArray);
|
|
|
|
|
GL.EnableClientState(EnableCap.ColorArray);
|
|
|
|
|
|
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, vertex_buffer_object);
|
|
|
|
|
GL.VertexPointer(3, VertexPointerType.Float, 0, IntPtr.Zero);
|
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, color_buffer_object);
|
|
|
|
|
GL.ColorPointer(4, ColorPointerType.UnsignedByte, 0, IntPtr.Zero);
|
|
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, element_buffer_object);
|
|
|
|
|
|
|
|
|
|
GL.DrawElements(BeginMode.Triangles, shape.Indices.Length,
|
|
|
|
|
DrawElementsType.UnsignedInt, IntPtr.Zero);
|
|
|
|
|
|
|
|
|
|
//GL.DrawArrays(GL.Enums.BeginMode.POINTS, 0, shape.Vertices.Length);
|
|
|
|
|
|
|
|
|
|
GL.DisableClientState(EnableCap.VertexArray);
|
|
|
|
|
GL.DisableClientState(EnableCap.ColorArray);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//int error = GL.GetError();
|
|
|
|
|
//if (error != 0)
|
|
|
|
|
// Debug.Print(Glu.ErrorString(Glu.Enums.ErrorCode.INVALID_OPERATION));
|
|
|
|
|
|
|
|
|
|
SwapBuffers();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region public static void Main()
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Entry point of this example.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[STAThread]
|
|
|
|
|
public static void Main()
|
|
|
|
|
{
|
|
|
|
|
using (T10_GLSL_Cube example = new T10_GLSL_Cube())
|
|
|
|
|
{
|
|
|
|
|
// Get the title and category of this example using reflection.
|
|
|
|
|
ExampleAttribute info = ((ExampleAttribute)example.GetType().GetCustomAttributes(false)[0]);
|
|
|
|
|
example.Title = String.Format("OpenTK | {0} {1}: {2}", info.Category, info.Difficulty, info.Title);
|
|
|
|
|
example.Run(30.0, 0.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|