// 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. #region --- Using directives --- using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Threading; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; using OpenTK.Platform; using System.Drawing; #endregion namespace Examples.Tutorial { [Example("VBO Static", ExampleCategory.OpenGL, "1.x", 3, Documentation = "VBOStatic")] public class T08_VBO : GameWindow { const float rotation_speed = 180.0f; float angle; struct Vbo { public int VboID, EboID, NumElements; } Vbo[] vbo = new Vbo[2]; VertexPositionColor[] CubeVertices = new VertexPositionColor[] { new VertexPositionColor(-1.0f, -1.0f, 1.0f, Color.DarkRed), new VertexPositionColor( 1.0f, -1.0f, 1.0f, Color.DarkRed), new VertexPositionColor( 1.0f, 1.0f, 1.0f, Color.Gold), new VertexPositionColor(-1.0f, 1.0f, 1.0f, Color.Gold), new VertexPositionColor(-1.0f, -1.0f, -1.0f, Color.DarkRed), new VertexPositionColor( 1.0f, -1.0f, -1.0f, Color.DarkRed), new VertexPositionColor( 1.0f, 1.0f, -1.0f, Color.Gold), new VertexPositionColor(-1.0f, 1.0f, -1.0f, Color.Gold) }; readonly short[] CubeElements = new short[] { 0, 1, 2, 2, 3, 0, // front face 3, 2, 6, 6, 7, 3, // top face 7, 6, 5, 5, 4, 7, // back face 4, 0, 3, 3, 7, 4, // left face 0, 1, 5, 5, 4, 0, // bottom face 1, 5, 6, 6, 2, 1, // right face }; public T08_VBO() : base(800, 600) { } protected override void OnLoad(EventArgs e) { base.OnLoad(e); Version version = new Version(GL.GetString(StringName.Version).Substring(0, 3)); Version target = new Version(1, 5); if (version < target) { throw new NotSupportedException(String.Format( "OpenGL {0} is required (you only have {1}).", target, version)); } GL.ClearColor(System.Drawing.Color.MidnightBlue); GL.Enable(EnableCap.DepthTest); vbo[0] = LoadVBO(CubeVertices, CubeElements); vbo[1] = LoadVBO(CubeVertices, CubeElements); } protected override void OnResize(EventArgs e) { base.OnResize(e); GL.Viewport(0, 0, Width, Height); float aspect_ratio = Width / (float)Height; Matrix4 perpective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 64); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref perpective); } protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); if (Keyboard[OpenTK.Input.Key.Escape]) this.Exit(); } protected override void OnRenderFrame(FrameEventArgs e) { base.OnRenderFrame(e); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); Matrix4 lookat = Matrix4.LookAt(0, 5, 5, 0, 0, 0, 0, 1, 0); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref lookat); angle += rotation_speed * (float)e.Time; GL.Rotate(angle, 0.0f, 1.0f, 0.0f); Draw(vbo[0]); SwapBuffers(); } Vbo LoadVBO(TVertex[] vertices, short[] elements) where TVertex : struct { Vbo handle = new Vbo(); int size; // To create a VBO: // 1) Generate the buffer handles for the vertex and element buffers. // 2) Bind the vertex buffer handle and upload your vertex data. Check that the buffer was uploaded correctly. // 3) Bind the element buffer handle and upload your element data. Check that the buffer was uploaded correctly. GL.GenBuffers(1, out handle.VboID); GL.BindBuffer(BufferTarget.ArrayBuffer, handle.VboID); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Length * BlittableValueType.StrideOf(vertices)), vertices, BufferUsageHint.StaticDraw); GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out size); if (vertices.Length * BlittableValueType.StrideOf(vertices) != size) throw new ApplicationException("Vertex data not uploaded correctly"); GL.GenBuffers(1, out handle.EboID); GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle.EboID); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(elements.Length * sizeof(short)), elements, BufferUsageHint.StaticDraw); GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out size); if (elements.Length * sizeof(short) != size) throw new ApplicationException("Element data not uploaded correctly"); handle.NumElements = elements.Length; return handle; } void Draw(Vbo handle) { // To draw a VBO: // 1) Ensure that the VertexArray client state is enabled. // 2) Bind the vertex and element buffer handles. // 3) Set up the data pointers (vertex, normal, color) according to your vertex format. // 4) Call DrawElements. (Note: the last parameter is an offset into the element buffer // and will usually be IntPtr.Zero). GL.EnableClientState(ArrayCap.ColorArray); GL.EnableClientState(ArrayCap.VertexArray); GL.BindBuffer(BufferTarget.ArrayBuffer, handle.VboID); GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle.EboID); GL.VertexPointer(3, VertexPointerType.Float, BlittableValueType.StrideOf(CubeVertices), new IntPtr(0)); GL.ColorPointer(4, ColorPointerType.UnsignedByte, BlittableValueType.StrideOf(CubeVertices), new IntPtr(12)); GL.DrawElements(BeginMode.Triangles, handle.NumElements, DrawElementsType.UnsignedShort, IntPtr.Zero); } /// /// Entry point of this example. /// [STAThread] public static void Main() { using (T08_VBO example = new T08_VBO()) { Utilities.SetWindowTitle(example); example.Run(30.0, 0.0); } } } }