#region --- License --- /* Copyright (c) 2006, 2007 Stefanos Apostolopoulos * See license.txt for license info */ #endregion using System; using OpenTK; using OpenTK.Graphics.OpenGL; namespace Examples.Shapes { // Abstract base class for procedurally generated geometry // // All classes derived from it must produce Counter-Clockwise (CCW) primitives. // Derived classes must create a single VBO and IBO, without primitive restarts for strips. // Uses an double-precision all-possible-attributes VertexT2dN3dV3d Array internally. // Cannot directly use VBO, but has Get-methods to retrieve VBO-friendly data. // Can use a Display List to prevent repeated immediate mode draws. // public abstract class DrawableShape: IDisposable { protected BeginMode PrimitiveMode; protected VertexT2dN3dV3d[] VertexArray; protected uint[] IndexArray; public int GetTriangleCount { get { switch ( PrimitiveMode ) { case BeginMode.Triangles: if ( IndexArray != null ) { return IndexArray.Length / 3; } else { return VertexArray.Length / 3; } // break; default: throw new NotImplementedException("Unknown primitive type."); } } } #region Display List private bool UseDisplayList; private int DisplayListHandle = 0; #endregion Display List public DrawableShape( bool useDisplayList ) { UseDisplayList = useDisplayList; PrimitiveMode = BeginMode.Triangles; VertexArray = null; IndexArray = null; } #region Convert to VBO public void GetArraysforVBO(out BeginMode primitives, out VertexT2dN3dV3d[] vertices, out uint[] indices) { primitives = PrimitiveMode; vertices = new VertexT2dN3dV3d[VertexArray.Length]; for (uint i = 0; i < VertexArray.Length; i++) { vertices[i].TexCoord = VertexArray[i].TexCoord; vertices[i].Normal = VertexArray[i].Normal; vertices[i].Position = VertexArray[i].Position; } indices = IndexArray; } public void GetArraysforVBO(out BeginMode primitives, out VertexT2fN3fV3f[] vertices, out uint[] indices) { primitives = PrimitiveMode; vertices = new VertexT2fN3fV3f[VertexArray.Length]; for (uint i = 0; i < VertexArray.Length; i++) { vertices[i].TexCoord = (Vector2)VertexArray[i].TexCoord; vertices[i].Normal = (Vector3)VertexArray[i].Normal; vertices[i].Position = (Vector3)VertexArray[i].Position; } indices = IndexArray; } public void GetArraysforVBO(out BeginMode primitives, out VertexT2hN3hV3h[] vertices, out uint[] indices) { primitives = PrimitiveMode; vertices = new VertexT2hN3hV3h[VertexArray.Length]; for (uint i = 0; i < VertexArray.Length; i++) { vertices[i].TexCoord = (Vector2h)VertexArray[i].TexCoord; vertices[i].Normal = (Vector3h)VertexArray[i].Normal; vertices[i].Position = (Vector3h)VertexArray[i].Position; } indices = IndexArray; } #endregion Convert to VBO private void DrawImmediateMode() { GL.Begin( PrimitiveMode ); { if ( IndexArray == null ) foreach ( VertexT2dN3dV3d v in VertexArray ) { GL.TexCoord2( v.TexCoord.X, v.TexCoord.Y ); GL.Normal3( v.Normal.X, v.Normal.Y, v.Normal.Z ); GL.Vertex3( v.Position.X, v.Position.Y, v.Position.Z ); } else { for ( uint i = 0; i < IndexArray.Length; i++ ) { uint index = IndexArray[i]; GL.TexCoord2( VertexArray[index].TexCoord.X, VertexArray[index].TexCoord.Y ); GL.Normal3( VertexArray[index].Normal.X, VertexArray[index].Normal.Y, VertexArray[index].Normal.Z ); GL.Vertex3( VertexArray[index].Position.X, VertexArray[index].Position.Y, VertexArray[index].Position.Z ); } } } GL.End(); } /// /// Does not touch any state/matrices. Does call Begin/End and Vertex&Co. /// Creates and compiles a display list if not present yet. Requires an OpenGL context. /// public void Draw() { if ( !UseDisplayList ) DrawImmediateMode(); else if ( DisplayListHandle == 0 ) { if ( VertexArray == null ) throw new Exception("Cannot draw null Vertex Array."); DisplayListHandle = GL.GenLists( 1 ); GL.NewList( DisplayListHandle, ListMode.CompileAndExecute ); DrawImmediateMode(); GL.EndList(); } else GL.CallList( DisplayListHandle ); } #region IDisposable Members /// /// Removes reference to VertexArray and IndexArray. /// Deletes the Display List, so it requires an OpenGL context. /// The instance is effectively destroyed. /// public void Dispose() { if ( VertexArray != null ) VertexArray = null; if ( IndexArray != null ) IndexArray = null; if ( DisplayListHandle != 0 ) { GL.DeleteLists( DisplayListHandle, 1 ); DisplayListHandle = 0; } } #endregion } }