From ffc525a0fde135870201bc0e6d5a53e073175838 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Wed, 8 Mar 2017 23:45:37 -0500 Subject: [PATCH] Removed most files, began rewriting program, shader, globject --- Diamond/Buffers/Buffer.cs | 161 ---------- Diamond/Buffers/VertexDataAttribute.cs | 25 -- Diamond/Buffers/VertexDataInfo.cs | 127 -------- Diamond/Buffers/VertexPointerAttribute.cs | 54 ---- Diamond/Diamond.csproj | 15 - Diamond/GLObject.cs | 56 +++- Diamond/Render/Camera.cs | 71 ----- Diamond/Render/RenderGroup.cs | 61 ---- Diamond/Render/VertexBuffer.cs | 228 -------------- Diamond/Shaders/Program.cs | 346 +++++++++++++--------- Diamond/Shaders/Shader.cs | 195 ++++++++---- Diamond/Textures/Texture.cs | 89 ------ Diamond/Util/ObjVertex.cs | 46 --- Diamond/Util/TileData.cs | 28 -- Diamond/Wrappers/BufferWrap.cs | 79 ----- Diamond/Wrappers/ProgramWrap.cs | 103 ------- Diamond/Wrappers/ShaderWrap.cs | 86 ------ Diamond/Wrappers/TextureWrap.cs | 78 ----- Diamond/Wrappers/Wrapper.cs | 70 ----- hexworld/HexRender.cs | 139 +-------- 20 files changed, 392 insertions(+), 1665 deletions(-) delete mode 100644 Diamond/Buffers/Buffer.cs delete mode 100644 Diamond/Buffers/VertexDataAttribute.cs delete mode 100644 Diamond/Buffers/VertexDataInfo.cs delete mode 100644 Diamond/Buffers/VertexPointerAttribute.cs delete mode 100644 Diamond/Render/Camera.cs delete mode 100644 Diamond/Render/RenderGroup.cs delete mode 100644 Diamond/Render/VertexBuffer.cs delete mode 100644 Diamond/Textures/Texture.cs delete mode 100644 Diamond/Util/ObjVertex.cs delete mode 100644 Diamond/Util/TileData.cs delete mode 100644 Diamond/Wrappers/BufferWrap.cs delete mode 100644 Diamond/Wrappers/ProgramWrap.cs delete mode 100644 Diamond/Wrappers/ShaderWrap.cs delete mode 100644 Diamond/Wrappers/TextureWrap.cs delete mode 100644 Diamond/Wrappers/Wrapper.cs diff --git a/Diamond/Buffers/Buffer.cs b/Diamond/Buffers/Buffer.cs deleted file mode 100644 index 3d74834..0000000 --- a/Diamond/Buffers/Buffer.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Diamond.Shaders; -using Diamond.Util; -using Diamond.Wrappers; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Buffers -{ - /// - /// Manages an OpenGL Buffer object - /// - /// The type of data used for this buffer - public class Buffer : GLObject where T : struct - { - internal readonly BufferWrap Wrapper; - - private readonly VertexDataInfo _vdi; - - /// - /// The target for this buffer; its type - /// - public BufferTarget Target => Wrapper.Target; - - /// - /// The usage hint for this buffer. Use StaticDraw for one-time uploads to - /// vertex buffers, and DynamicDraw for repeated uploads to vertex buffers. - /// - public BufferUsageHint Usage - { - get => Wrapper.Usage; - set => Wrapper.Usage = value; - } - - internal Buffer(BufferWrap wrapper, string name) - { - Wrapper = wrapper; - Name = name; - _vdi = VertexDataInfo.GetInfo(); - } - - /// - /// Upload data to this buffer - /// - /// The data to upload - public void Data(T[] data) => Wrapper.Data(_vdi.Stride, data); - - /// - /// Upload a range of data to this buffer - /// - /// The range offset - /// The range length - /// The data to upload, offset and length apply to both this and the target - public void Data(int offset, int count, T[] data) => Wrapper.SubData(_vdi.Stride, offset, count, data); - - /// - /// Upload a range of data to this buffer - /// - /// The data to upload - public void Data(SubArray data) => Data(data.Offset, data.Length, data.Array); - - /// - /// Point this buffer to a program's vertex attributes. T must have [VertexDataAttribute], and all fields - /// of T must have [VertexPointerAttribute] to infer vertex pointer locations. - /// - /// The program to point this buffer to - public void PointTo(Program program) - { - if (_vdi == null) - { - var exception = new InvalidOperationException($"Cannot use type {typeof(T)} to create a Vertex Buffer"); - Logger.Error(exception); - throw exception; - } - - Wrapper.Bind(); - foreach (var attr in _vdi.Pointers) - { - if (program.HasAttribute(attr.Name)) - GL.VertexAttribPointer(program.AttributeLocation(attr.Name), attr.Size, attr.Type, attr.Normalized, - _vdi.Stride, attr.Offset); - } - } - - public override string ToString() => Name == null - ? $"Buffer<{typeof(T).Name}> {Wrapper}" - : $"Buffer<{typeof(T).Name}> {Wrapper} \'{Name}\'"; - - public override void Dispose() - { - Logger.Debug("Disposing {0}", this); - Wrapper.Dispose(); - } - - #region Factory Methods - - /// - /// Create an empty buffer of this type - /// - /// The buffer target - /// The initial usage hint - /// The name of this GLObject - /// The buffer, or null if initialization failed - internal static Buffer Empty(BufferTarget target, BufferUsageHint usage, string name) - { - var wrapper = new BufferWrap(target, usage); - var service = new Buffer(wrapper, name); - - Logger.Debug("Created {0}", service); - - return service; - } - - /// - /// Create a buffer of this type and upload data - /// - /// The data to upload - /// The buffer target - /// The initial usage hint - /// The name of this GLObject - /// The buffer, or null if initialization failed - internal static Buffer FromData(T[] data, BufferTarget target, BufferUsageHint usage, string name = null) - { - var service = Empty(target, usage, name); - - service?.Data(data); - - return service; - } - - #endregion - } - - /// - /// Class for static Buffer operations and public factory methods - /// - public static class Buffer - { - /// - /// Create an empty buffer of this type - /// - /// The buffer target - /// The initial usage hint - /// The name of this GLObject - /// The buffer, or null if initialization failed - public static Buffer Empty(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw, - string name = null) where T : struct => Buffer.Empty(target, usage, name); - - /// - /// Create a buffer of this type and upload data - /// - /// The data to upload - /// The buffer target - /// The initial usage hint - /// The name of this GLObject - /// The buffer, or null if initialization failed - public static Buffer FromData(T[] data, BufferTarget target, - BufferUsageHint usage = BufferUsageHint.StaticDraw, - string name = null) where T : struct => Buffer.FromData(data, target, usage, name); - } -} \ No newline at end of file diff --git a/Diamond/Buffers/VertexDataAttribute.cs b/Diamond/Buffers/VertexDataAttribute.cs deleted file mode 100644 index dd45cef..0000000 --- a/Diamond/Buffers/VertexDataAttribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace Diamond.Buffers -{ - /// - /// Marks a struct as vertex data that can be sent to a shader attribute - /// - [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] - public sealed class VertexDataAttribute : Attribute - { - /// - /// The pointer divisor for this type. A value of 0 indicates per-vertex, a value of 1+ - /// indicates every n instances - /// - public int Divisor { get; set; } = 0; - - /// - /// Mark a struct with information about how to iterate over vertex data of this type. - /// All fields of this struct must have [VertexPointer] - /// - public VertexDataAttribute() - { - } - } -} \ No newline at end of file diff --git a/Diamond/Buffers/VertexDataInfo.cs b/Diamond/Buffers/VertexDataInfo.cs deleted file mode 100644 index 0989f83..0000000 --- a/Diamond/Buffers/VertexDataInfo.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Runtime.InteropServices; -using Diamond.Shaders; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Buffers -{ - /// - /// Get vertex pointer information about a struct to infer how to point shader attributes to it - /// - public class VertexDataInfo - { - /// - /// All shader attributes supported by this type - /// - public IReadOnlyCollection Pointers { get; } - - /// - /// The size of this type in bytes - /// - public int Stride { get; } - - /// - /// The pointer divisor for this type. A value of 0 indicates per-vertex, a value of 1+ - /// indicates every n instances - /// - public readonly int Divisor; - - /// - /// Create an info class with pre-computed values - /// - /// The type's supported attributes - /// The type's stride - /// The type's pointer divisor - private VertexDataInfo(IList pointers, int stride, int divisor) - { - Pointers = new ReadOnlyCollection(pointers); - Stride = stride; - Divisor = divisor; - } - - /// - /// Enable the attributes associated with this type on Program.Current - /// - public void EnableVertexPointers() - { - if (Program.Current == null) - throw new InvalidOperationException("Cant render a mesh with no active shader."); - - foreach (var attr in Pointers) - { - if (!Program.Current.HasAttribute(attr.Name)) - continue; - var loc = Program.Current.AttributeLocation(attr.Name); - GL.EnableVertexAttribArray(loc); - GL.VertexAttribDivisor(loc, Divisor); - } - } - - /// - /// Disable the attributes associated with this type on Program.Current - /// - public void DisableVertexPointers() - { - if (Program.Current == null) - throw new InvalidOperationException("Cant render a mesh with no active shader."); - - foreach (var attr in Pointers) - { - if (!Program.Current.HasAttribute(attr.Name)) - continue; - var loc = Program.Current.AttributeLocation(attr.Name); - GL.DisableVertexAttribArray(loc); - } - } - - /// - /// A cache of already computed information to prevent redundant reflection calls - /// - private static readonly Dictionary attribCache = - new Dictionary(); - - /// - /// Get the VertexDataInfo for a particular type - /// - /// The type to analyse - /// The VertexDataInfo for the type, or null if the type is not supported - public static VertexDataInfo GetInfo() where T : struct - { - if (attribCache.ContainsKey(typeof(T))) return attribCache[typeof(T)]; - - var vertexDataAttributes = typeof(T).GetCustomAttributes(typeof(VertexDataAttribute), false); - - // the type must have [VertexData] - if (vertexDataAttributes.Length != 1) - return null; - - var vertdataattrib = (VertexDataAttribute) vertexDataAttributes[0]; - var divisor = vertdataattrib.Divisor; - - - var attribList = new List(); - var stride = Marshal.SizeOf(); - - foreach (var fieldInfo in typeof(T).GetFields()) - { - var attrs = fieldInfo.GetCustomAttributes(typeof(VertexPointerAttribute), false); - - // all fields must have [VertexPointer] - if (attrs.Length == 0) - return null; - - var offset = (int) Marshal.OffsetOf(fieldInfo.Name); - foreach (var attr in attrs) - { - var vpa = (VertexPointerAttribute) attr; - vpa.Offset = offset; - attribList.Add(vpa); - } - } - - return new VertexDataInfo(attribList, stride, divisor); - } - } -} \ No newline at end of file diff --git a/Diamond/Buffers/VertexPointerAttribute.cs b/Diamond/Buffers/VertexPointerAttribute.cs deleted file mode 100644 index 04ce453..0000000 --- a/Diamond/Buffers/VertexPointerAttribute.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Buffers -{ - /// - /// Marks a field as an attribute to be sent to a shader. Must be used on public fields of a struct. - /// - [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] - public sealed class VertexPointerAttribute : Attribute - { - /// - /// The attribute name that the values of this field should point to - /// - public string Name { get; } - - /// - /// The number of elements in this attribute - /// Corresponds to the size parameter to glVertexAttribPointer. - /// - public int Size { get; } - - /// - /// The element type of the attribute - /// Corresponds to the type parameter to glVertexAttribPointer - /// - public VertexAttribPointerType Type { get; set; } = VertexAttribPointerType.Float; - - /// - /// Whether to normalize the values of this attribute - /// Corresponds to the normalized parameter to glVertexAttribPointer - /// - public bool Normalized { get; set; } = false; - - /// - /// The offset of this attribute within each element - /// Corresponds to the offset parameter to glVertexAttribPointer - /// - // todo this, and other values, should be moved into a different type for use with VertexDataInfo. - // this class should just mark fields with their use - other types should manage binding those fields - public int Offset { get; internal set; } = 0; - - /// - /// Mark a field with information about how to point a shader attribute to it - /// - /// The name of the attribute to point to this - /// The number of elements to read from this field - public VertexPointerAttribute(string name, int size) - { - Name = name; - Size = size; - } - } -} \ No newline at end of file diff --git a/Diamond/Diamond.csproj b/Diamond/Diamond.csproj index 3a6e789..0d25f7c 100644 --- a/Diamond/Diamond.csproj +++ b/Diamond/Diamond.csproj @@ -51,26 +51,11 @@ - - - - - - - - - - - - - - - diff --git a/Diamond/GLObject.cs b/Diamond/GLObject.cs index f3511e2..a30ae3f 100644 --- a/Diamond/GLObject.cs +++ b/Diamond/GLObject.cs @@ -1,26 +1,64 @@ using System; using NLog; +using OpenTK.Graphics; namespace Diamond { - /// - /// Provide managed access to OpenGL objects - /// public abstract class GLObject : IDisposable { /// - /// Logger for all GLObjects + /// The logger for GLObject-related info /// - protected static readonly Logger Logger = LogManager.GetLogger(nameof(GLObject)); + protected internal static Logger Logger = LogManager.GetLogger(nameof(GLObject)); /// - /// Name of this GLObject used for identification + /// The OpenGL object name /// - public string Name { get; protected set; } = nameof(GLObject); + public int Id { get; private set; } /// - /// Delegate Dispose to underlying wrapper class + /// Force object name assignment /// - public abstract void Dispose(); + /// The OpenGL object name + protected GLObject(int id) + { + Id = id; + } + + /// + /// Free this object name on the GPU + /// + protected abstract void Delete(); + + #region IDisposable + + /// + protected virtual void Dispose(bool disposing) + { + if (GraphicsContext.CurrentContext != null) + Delete(); + else + Logger.Error("Cannot delete {0} because there is no graphics context.", this); + + if (disposing) + { + // no managed resources to dispose + } + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + ~GLObject() + { + Dispose(false); + } + + #endregion } } \ No newline at end of file diff --git a/Diamond/Render/Camera.cs b/Diamond/Render/Camera.cs deleted file mode 100644 index 10512c3..0000000 --- a/Diamond/Render/Camera.cs +++ /dev/null @@ -1,71 +0,0 @@ -using OpenTK; - -namespace Diamond.Render -{ - /// - /// Manages a projection and view matrix - /// - public class Camera - { - private Vector3 _position = Vector3.Zero; - private Vector3 _target = -Vector3.One; - private Vector3 _up = Vector3.UnitZ; - - /// - /// The view matrix - /// - public Matrix4 View; - - /// - /// The projection matrix - /// - public Matrix4 Projection; - - /// - /// Sets and updates the position of the view matrix - /// - public Vector3 Position - { - set - { - _position = value; - UpdateView(); - } - get => _position; - } - - /// - /// Sets and updates the target of the view matrix - /// - public Vector3 Target - { - set - { - _target = value; - UpdateView(); - } - get => _target; - } - - /// - /// Sets and updates the up vector of the view matrix - /// - public Vector3 Up - { - set - { - _up = value; - UpdateView(); - } - get => _up; - } - - /// - /// Recalculate the view matrix - /// - private void UpdateView() - { - View = Matrix4.LookAt(_position, _target, _up); - } - } -} \ No newline at end of file diff --git a/Diamond/Render/RenderGroup.cs b/Diamond/Render/RenderGroup.cs deleted file mode 100644 index 8a3e928..0000000 --- a/Diamond/Render/RenderGroup.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Diamond.Shaders; -using Diamond.Textures; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Render -{ - /// - /// Manage a group of buffers, ranges, and uniforms to render - /// - /// The type of data to use as Instance information - /// The type of data to use as Vertex information - public class RenderGroup where TInstance : struct where TVertex : struct - { - /// - /// The range of vertex values to render - /// - public VertexBuffer Vertices; - - /// - /// The range of instance values to render - /// - public VertexBuffer Instance; - - /// - /// The program to use to render this Rendergroup - /// - public Program Program; - - /// - /// The Texture to use for this Rendergroup - /// - public Texture Texture; - - /// - /// View and Projection information for this Rendergroup - /// - public Camera Camera; - - /// - /// Draw this rendergroup using the predefined settings. - /// - public void Draw() - { - Program.Use(); - - Texture.Bind(0); - - if (Program.HasUniform("tex")) - GL.Uniform1(Program.UniformLocation("tex"), 0); - if (Program.HasUniform("view")) - GL.UniformMatrix4(Program.UniformLocation("view"), false, ref Camera.View); - if (Program.HasUniform("proj")) - GL.UniformMatrix4(Program.UniformLocation("proj"), false, ref Camera.Projection); - - if (Instance != null) - Vertices.DrawInstanced(Instance); - else - Vertices.Draw(); - } - } -} \ No newline at end of file diff --git a/Diamond/Render/VertexBuffer.cs b/Diamond/Render/VertexBuffer.cs deleted file mode 100644 index 3314124..0000000 --- a/Diamond/Render/VertexBuffer.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Diamond.Buffers; -using Diamond.Shaders; -using Diamond.Util; -using NLog; -using OpenTK; -using OpenTK.Graphics.OpenGL4; -using Buffer = Diamond.Buffers.Buffer; - -namespace Diamond.Render -{ - /// - /// Manage a vertex buffer object - /// - /// Buffer data type - public class VertexBuffer : IDisposable where T : struct - { - private Logger Logger = LogManager.GetLogger("VertexBuffer"); - - /// - /// The name of this buffer object for identification - /// - public string Name { get; set; } - - /// - /// The underlying buffer for this object - /// - public Buffer Buffer; - - /// - /// A subset of the Buffer's array for this buffer - /// - public SubArray Vertices; - - /// - /// Primitive type to render this object - /// - public PrimitiveType Primitive; - - /// - /// Vertex data info for this type of data - /// - private static readonly VertexDataInfo tVdi = VertexDataInfo.GetInfo(); - - internal VertexBuffer(Buffer buffer, SubArray vertices, PrimitiveType primitive, string name) - { - Buffer = buffer; - Vertices = vertices; - Primitive = primitive; - Name = name; - } - - /// - /// Render this buffer - /// - public void Draw() - { - Buffer.PointTo(Program.Current); - - tVdi.EnableVertexPointers(); - - GL.DrawArrays(Primitive, Vertices.Offset, Vertices.Length); - - tVdi.DisableVertexPointers(); - } - - /// - /// Render this buffer using a second buffer as instance data - /// - /// - /// - public void DrawInstanced(VertexBuffer instance) where TI : struct - { - var tiVdi = VertexBuffer.tVdi; - - if (tiVdi.Divisor == 0) - { - Logger.Error("Cannot render mesh with instanced of type {0} - Divisor is 0", typeof(TI).Name); - return; - } - - Buffer.PointTo(Program.Current); - instance.Buffer.PointTo(Program.Current); - - tVdi.EnableVertexPointers(); - tiVdi.EnableVertexPointers(); - - GL.DrawArraysInstancedBaseInstance(Primitive, Vertices.Offset, Vertices.Length, instance.Vertices.Length, - instance.Vertices.Offset); - - tVdi.DisableVertexPointers(); - tiVdi.DisableVertexPointers(); - } - - public void Dispose() - { - Buffer.Dispose(); - } - } - - /// - /// Static operations for vertex buffers - /// - public static class VertexBuffer - { - public static VertexBuffer[] FromArrays(T[][] arrays, PrimitiveType primitive = PrimitiveType.Triangles, - string name = null) where T : struct - { - var buffer = Buffer.Empty(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw, name); - - var vertices = arrays.SelectMany(x => x).ToArray(); - buffer.Data(vertices); - - var vertBuffers = new List>(); - - var offset = 0; - foreach (var array in arrays) - { - vertBuffers.Add(new VertexBuffer( - buffer, - new SubArray(vertices, offset, array.Length), - primitive, name)); - offset += array.Length; - } - - return vertBuffers.ToArray(); - } - - public static VertexBuffer[] FromArrays(IEnumerable> arrays, - PrimitiveType primitive = PrimitiveType.Triangles, string name = null) where T : struct => - FromArrays(arrays.Select(x => x.ToArray()).ToArray(), primitive, name); - - public static VertexBuffer[] FromWavefront(string file) - { - var lines = File.ReadAllLines(file).Where(l => !l.StartsWith("#")).Select(l => l.Split(' ')).ToArray(); - - var buffer = Buffer.Empty(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw, - $"{file} buffer"); - - var name = file; - - var vertBuffers = new List>(); - - // get all positional data - var vs = lines - .Where(items => items[0] == "v") // only "v" lines - .Select(items => new Vector3( // get a vector3 from the values - float.Parse(items[1]), - float.Parse(items[2]), - float.Parse(items[3]))) - .ToArray(); - - // get all uv data - var vts = lines - .Where(items => items[0] == "vt") // only "vt" lines - .Select(items => new Vector2( // get a vector2 from the values - float.Parse(items[1]), - 1 - float.Parse(items[2]))) // flip along y - .ToArray(); - - // get all normal data - var vns = lines - .Where(items => items[0] == "vn") // only "vn" lines - .Select(items => new Vector3( // get a vector3 from the values - float.Parse(items[1]), - float.Parse(items[2]), - float.Parse(items[3]))) - .ToArray(); - - // get all vertex data - var vertices = lines - .Where(items => items[0] == "f") // only "f" liens - .Select(items => items.Skip(1)) // skip the "f" item - .Select(items => items // get each vertex from the triangle - .Select(inds => inds.Split('/'))) // split items into indices - .SelectMany(inds => inds) // collapse nested index array into array of indexes - .Select(inds => new ObjVertex( // get vertexdata from the value data at each index - inds[0] == "" ? Vector3.Zero : vs[int.Parse(inds[0]) - 1], - inds[1] == "" ? Vector2.Zero : vts[int.Parse(inds[1]) - 1], - inds[2] == "" ? Vector3.Zero : vns[int.Parse(inds[2]) - 1])) - .ToArray(); - - buffer.Data(vertices); // upload vertex data to the buffer - - var offset = 0; // offset of each vertexbuffer - var count = 0; // length of each vertexbuffer - - foreach (var items in lines.Where(items => items[0] == "o" || items[0] == "f")) - { - if (items[0] != "f") - { - if (count > 0) - { - vertBuffers.Add(new VertexBuffer( - buffer, - new SubArray(vertices, offset, count), - PrimitiveType.Triangles, - name)); - } - - // reset for next vbo and move offset to the end of this one - name = items[1]; - offset += count; - count = 0; - } - else - { - count += items.Length - 1; // size of current vbo increases by that many vertices - } - } - - // at the last vbo, or only vbo. - if (count > 0) - { - vertBuffers.Add(new VertexBuffer( - buffer, - new SubArray(vertices, offset, count), - PrimitiveType.Triangles, - name)); - } - - return vertBuffers.ToArray(); - } - } -} \ No newline at end of file diff --git a/Diamond/Shaders/Program.cs b/Diamond/Shaders/Program.cs index 0095e35..94b0536 100644 --- a/Diamond/Shaders/Program.cs +++ b/Diamond/Shaders/Program.cs @@ -1,233 +1,291 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; -using Diamond.Wrappers; +using System.Text; using OpenTK.Graphics.OpenGL4; namespace Diamond.Shaders { /// - /// Manages an OpenGL Program object + /// Wrap and OpenGL program object /// public class Program : GLObject { - internal readonly ProgramWrap Wrapper; + #region Static + + private static Program _current; /// - /// The currently active program. Manually invoking glUseProgram will break this. + /// The currently active program /// - public static Program Current { get; private set; } + public static Program Current + { + get => _current; + set + { + if (!value?.Linked ?? false) + { + Logger.Error("Cannot use program {0}", value); + value = null; + } - // keep a cache of uniform and attributes to prevent repeated queries - private readonly Dictionary _uniforms = new Dictionary(); + Logger.Debug("Using program {0}", value); + GL.UseProgram((_current = value)?.Id ?? 0); + } + } + + #endregion + + #region Constructor, Delete() + + /// + /// Create a program object wrapper + /// + private Program() + : base(GL.CreateProgram()) + { + Logger.Debug("Created {0}", this); + } + + /// + protected override void Delete() + { + Logger.Debug("Disposing {0}", this); + GL.DeleteProgram(Id); + } + + #endregion + + #region Properties + + #region Queries + + /// + /// The number of active uniforms + /// + public int ActiveUniforms => Get(GetProgramParameterName.ActiveUniforms); + + /// + /// The number of active attributes + /// + public int ActiveAttributes => Get(GetProgramParameterName.ActiveAttributes); + + #endregion + + #region Stored + + /// + /// The InfoLog for this program + /// + public string InfoLog { get; private set; } + + /// + /// The link status of this program + /// + public bool Linked { get; private set; } + + #endregion + + #endregion + + #region Methods + + /// + /// Get a property of this program + /// + /// The program property to get + /// The int value of the program property + private int Get(GetProgramParameterName param) + { + GL.GetProgram(Id, param, out int res); + return res; + } + + /// + /// Try to link this program + /// + public void Link() + { + _attributes.Clear(); + _uniforms.Clear(); + + Logger.Debug("Linking {0}", this); + GL.LinkProgram(Id); + // link status can only change after link attempt + Linked = Get(GetProgramParameterName.LinkStatus) != 0; + + if (Linked) + { + Logger.Trace("Successfully linked {0}", this); + + for (var i = 0; i < ActiveAttributes; i++) + { + var sb = new StringBuilder(256); + GL.GetActiveAttrib(Id, i, sb.Capacity, out int length, out int size, out ActiveAttribType type, sb); + var name = sb.ToString(); + _attributes[name] = i; + } + + for (var i = 0; i < ActiveUniforms; i++) + { + var sb = new StringBuilder(256); + GL.GetActiveUniform(Id, i, sb.Capacity, out int length, out int size, out ActiveUniformType type, + sb); + var name = sb.ToString(); + _uniforms[name] = i; + } + } + else + { + InfoLog = GL.GetProgramInfoLog(Id).Trim(); + + Logger.Error("Failed to link {0}", this); + Logger.Trace("InfoLog for {0}:\n{1}", this, InfoLog); + } + } + + /// + /// Use this program + /// + /// Equivalent to Program.Current = value + /// + public void Use() => Current = this; + + #region Attribute Locations private readonly Dictionary _attributes = new Dictionary(); - - internal Program(ProgramWrap wrapper, string name) - { - Wrapper = wrapper; - Name = name; - } + private readonly Dictionary _uniforms = new Dictionary(); /// - /// Check if the program has a uniform + /// Check if this program has an active attribute /// - /// The name of the uniform - /// Whether the program has this uniform - public bool HasUniform(string name) - { - return _uniforms.ContainsKey(name); - } + /// The attribute name + /// Whether the progrma has an active attribute + public bool HasAttribute(string name) => _attributes.ContainsKey(name); /// - /// Get the location of a uniform + /// Check if this program has an active uniform /// - /// The name of the uniform - /// The location of the uniform - public int UniformLocation(string name) - { - if (HasUniform(name)) return _uniforms[name]; - throw new KeyNotFoundException($"Shader {this} does not contain uniform {name}"); - } + /// The uniform name + /// Whether the progrma has an active uniform + public bool HasUniform(string name) => _uniforms.ContainsKey(name); /// - /// Check if the program has an attribute + /// Get the location of an attribute by name /// - /// The name of the attribute - /// Whether the program has this attribute - public bool HasAttribute(string name) - { - return _attributes.ContainsKey(name); - } - - /// - /// Get the location of an attribute - /// - /// The name of the attribute + /// The attribute name /// The location of the attribute public int AttributeLocation(string name) { - if (HasAttribute(name)) return _attributes[name]; - throw new KeyNotFoundException($"Shader {this} does not contain attribute {name}"); + if (!HasAttribute(name)) + throw new InvalidOperationException($"{this} does not have active attribute '{name}'"); + return _attributes[name]; } /// - /// Use this Program to render. Also updates Program.Current + /// Get the location of an uniform by name /// - public void Use() + /// The uniform name + /// The location of the uniform + public int UniformLocation(string name) { - Wrapper.Use(); - Current = this; + if (!HasUniform(name)) throw new InvalidOperationException($"{this} does not have active uniform '{name}'"); + return _uniforms[name]; } - /// - /// Use the default shader to render - /// - //? Could create static Program instance which wraps the default shader - // ie Shader.Default.Use() - // would also allow sending arrays to the default attribs like gl_Vertex etc. - public static void UseDefault() - { - GL.UseProgram(0); - Current = null; - } + #endregion /// - /// Helper method to try to link this program - /// - /// - private bool Link() - { - _uniforms.Clear(); - _attributes.Clear(); - - Wrapper.Link(); - - if (!Wrapper.Linked) - return false; - - for (var i = 0; i < Wrapper.ActiveUniforms; i++) - _uniforms[Wrapper.UniformName(i)] = i; - - for (var i = 0; i < Wrapper.ActiveAttributes; i++) - _attributes[Wrapper.AttributeName(i)] = i; - - return true; - } - - /// - /// Helper method to attach a shader to this program + /// Attach a shader to this program /// /// The shader to attach - private void Attach(Shader shader) + public void Attach(Shader shader) { - Wrapper.Attach(shader.Wrapper); + Logger.Debug("Attaching {0} to {1}", shader, this); + GL.AttachShader(Id, shader.Id); } - public override string ToString() => $"Program {Wrapper} \'{Name}\'"; + /// + public override string ToString() => + $"'Program {Id}'"; - public override void Dispose() - { - Logger.Debug("Disposing {0}", this); - Wrapper.Dispose(); - } + #endregion #region Factory Methods /// - /// Create a program from compiled shaders + /// Create and link a program from precompiled shaders /// - /// The name of this GLObject - /// The shaders to use in this program - /// The linked program, or null if initialization failed - public static Program FromShaders(string name, params Shader[] shaders) => FromShaders(name, - (IEnumerable) shaders); + /// The shaders used in this program + /// A linked program, or null if initialization failed + public static Program FromShaders(params Shader[] shaders) => FromShaders((IEnumerable) shaders); /// - /// Create a program from compiled shaders + /// Create and link a program from precompiled shaders /// - /// The name of this GLObject - /// The shaders to use in this program - /// The linked program, or null if initialization failed - public static Program FromShaders(string name, IEnumerableshaders) + /// The shaders used in this program + /// A linked program, or null if initialization failed + public static Program FromShaders(IEnumerable shaders) { if (shaders == null) { - Logger.Error("Cannot create program {0} with no shaders.", name); + Logger.Error("Cannot create program from no shaders."); return null; } - var wrapper = new ProgramWrap(); - var service = new Program(wrapper, name); - - Logger.Debug("Created {0}", service); + var program = new Program(); foreach (var shader in shaders) { if (shader == null) { - Logger.Error("One or more shaders failed to compile - cannot create program {0}", name); - service.Dispose(); + Logger.Error("One or more shaders is null - cannot create program"); + program.Dispose(); return null; } - - service.Attach(shader); + program.Attach(shader); } - var linked = service.Link(); + program.Link(); - if (!linked) - { - Logger.Warn("Failed to link {0}", service); - Logger.Debug("InfoLog for {0}", service); - service.Dispose(); - return null; - } + if (program.Linked) return program; - Logger.Debug("Successfully linked {0}", service); - - return service; + program.Dispose(); + return null; } /// - /// Create a program from compiled shaders + /// Create and link a program from glsl source files. Shader types must be inferrable from file extensions. + /// + /// See for file extension details /// - /// The shaders to use in this program + /// /// The linked program, or null if initialization failed - public static Program FromShaders(params Shader[] shaders) => FromShaders((IEnumerable) shaders); + public static Program FromFiles(params string[] files) => FromFiles((IEnumerable) files); /// - /// Create a program from compiled shaders + /// Create and link a program from glsl source files. Shader types must be inferrable from file extensions. + /// + /// See for file extension details /// - /// The shaders to use in this program + /// /// The linked program, or null if initialization failed - public static Program FromShaders(IEnumerable shaders) + public static Program FromFiles(IEnumerable files) { - var shaderList = shaders.ToList(); // prevent multiple enumeration - var shaderNames = shaderList.Select(s => s.Name); - string name = $"[{string.Join(", ", shaderNames)}]"; - return FromShaders(name, shaderList); - } - - /// - /// Create shaders from glsl source files, and create a program using them. - /// Shader types must be inferrable from file extensions. - /// - /// The glsl source files - /// The linked program, or null if initialization faileds - public static Program FromFiles(params string[] paths) - { - if (paths == null) + if (files == null) { - Logger.Warn("Cannot create a program from no shaders."); + Logger.Warn("Cannot create a program from no shaders"); return null; } - var shaders = paths.Select(path => Shader.FromFile(path)).ToList(); + var shaders = files.Select(Shader.FromFile).ToList(); var program = FromShaders(shaders); foreach (var shader in shaders) + { shader?.Dispose(); + } return program; } diff --git a/Diamond/Shaders/Shader.cs b/Diamond/Shaders/Shader.cs index 81f96e7..17c8980 100644 --- a/Diamond/Shaders/Shader.cs +++ b/Diamond/Shaders/Shader.cs @@ -1,96 +1,165 @@ using System.Collections.Generic; using System.IO; -using Diamond.Wrappers; using OpenTK.Graphics.OpenGL4; namespace Diamond.Shaders { /// - /// Manges a OpenGL Shader object + /// Wrap an OpenGL shader object /// - public class Shader : GLObject + public sealed class Shader : GLObject { - internal readonly ShaderWrap Wrapper; + #region Constructor, Delete() /// - /// The source used to create this shader + /// Create a shader object wrapper /// - public string Source { get; } + /// The type of this shader + private Shader(ShaderType type) + : base(GL.CreateShader(type)) + { + ShaderType = type; + Logger.Debug("Created {0}", this); + } + + /// + protected override void Delete() + { + Logger.Debug("Disposing {0}", this); + GL.DeleteShader(Id); + } + + #endregion + + #region Properties + + #region Queries + + #endregion + + #region Stored + + /// + /// Store the source code to prevent repeated queries to glGetShaderSource + /// + private string _source; + + /// + /// GLSL source code for this shader + /// + public string Source + { + get => _source; + set + { + _source = value; + GL.ShaderSource(Id, _source); + + Logger.Debug("Set shader source for {0}", this); + } + } + + /// + /// The compilation status of this shader + /// + public bool Compiled { get; private set; } /// /// The type of this shader /// - public ShaderType Type { get; } + public ShaderType ShaderType { get; private set; } - internal Shader(ShaderWrap wrapper, string source, ShaderType type, string name) + /// + /// The InfoLog for this program + /// + public string InfoLog { get; private set; } + + #endregion + + #endregion + + #region Methods + + /// + /// Get a property of this shader + /// + /// The shader property to get + /// The int value of the shader property + private int Get(ShaderParameter param) { - Wrapper = wrapper; - Source = source; - Type = type; - Name = name; + GL.GetShader(Id, param, out int res); + return res; } - public override string ToString() => Name == null - ? $"{Wrapper}" - : $"{Wrapper} \'{Name}\'"; - - public override void Dispose() + /// + /// Try to compile this shader + /// + public void Compile() { - Logger.Debug("Disposing {0}", this); - Wrapper.Dispose(); + Logger.Debug("Compiling {0}", this); + GL.CompileShader(Id); + // compilation status can only change after glCompileShader + Compiled = Get(ShaderParameter.CompileStatus) != 0; + + if (Compiled) + Logger.Trace("Successfully compiled {0}", this); + else + { + InfoLog = GL.GetShaderInfoLog(Id).Trim(); + + Logger.Error("Failed to compile {0}", this); + Logger.Trace("InfoLog for {0}: \n{1}", this, InfoLog); + } } + /// + public override string ToString() => + $"'Shader {Id}: {ShaderType}'"; + + #endregion + #region Factory Methods - // Used to infer shader type based on file extension + /// + /// Map file extensions to appropriate shader type + /// private static readonly Dictionary Extensions = new Dictionary { [".vs"] = ShaderType.VertexShader, [".vert"] = ShaderType.VertexShader, - [".fs"] = ShaderType.FragmentShader, - [".frag"] = ShaderType.FragmentShader, [".gs"] = ShaderType.GeometryShader, [".geom"] = ShaderType.GeometryShader, + [".fs"] = ShaderType.FragmentShader, + [".frag"] = ShaderType.FragmentShader, }; /// - /// Create and compile a shader from glsl source code + /// Create and compile a shader from source /// - /// The glsl source - /// The type of shader to create - /// The name of this GLObject - /// The compiled Shader, or null if initialization failed - public static Shader FromSource(string source, ShaderType type, string name = "Shader") + /// The GLSL source for the shader + /// The type of the shader + /// The compiled shader, or null if initialization failed + public static Shader FromSource(string source, ShaderType type) { - var wrapper = new ShaderWrap(type); - var service = new Shader(wrapper, source, type, name); + var shader = new Shader(type) {Source = source}; + shader.Compile(); - Logger.Debug("Created {0}", service); - - wrapper.Source = source; - wrapper.Compile(); - - if (!wrapper.Compiled) + if (!shader.Compiled) { - Logger.Warn("Failed to compile {0}", service); - Logger.Debug("InfoLog for {0}", service); - service.Dispose(); + shader.Dispose(); return null; } - Logger.Debug("Successfully compiled {0}", service); - - return service; + return shader; } /// - /// Create and compile a shader from a glsl source file + /// Create and compile a shader from a source file /// - /// The path to the glsl source file - /// The type of the shader to create - /// The name of this GLObject - /// - public static Shader FromFile(string path, ShaderType type, string name = null) + /// The path to the source file + /// The type of the shader + /// The compiled shader, or null if initialization failed + public static Shader FromFile(string path, ShaderType type) { if (!File.Exists(path)) { @@ -98,21 +167,20 @@ namespace Diamond.Shaders return null; } - if (name == null) - name = Path.GetFileNameWithoutExtension(path); - - return FromSource(File.ReadAllText(path), type, name); + var source = File.ReadAllText(path); + return FromSource(source, type); } /// - /// Create and compile a shader from a glsl source file. Shader type is inferred from file extension. - /// Extension must be .vs, .vert, .fs, .frag, .gs, or .geom. This can optionally be followed by .glsl or .txt, - /// but the shader type extension must be present. + /// Create and compile a shader from a source file, and infer the type of the shader from the file extension. + /// + /// File must have extension or sub-extension .vs, .fs, .gs, .vert, + /// .frag, or .geom. For example: shader.fs, shader.vert.glsl, + /// shader.gs.txt /// - /// The path to the glsl source file - /// The name of this GLObject - /// The compiled shader, or null if initialization failed or shader type cannot be inferred - public static Shader FromFile(string path, string name = null) + /// + /// + public static Shader FromFile(string path) { if (!File.Exists(path)) { @@ -121,12 +189,12 @@ namespace Diamond.Shaders } var ext = Path.GetExtension(path); - var fileName = Path.GetFileNameWithoutExtension(path); + var file = Path.GetFileNameWithoutExtension(path); // get sub-extension if real extension is not valid if (ext != null) if (!Extensions.ContainsKey(ext)) - ext = Path.GetExtension(fileName); + ext = Path.GetExtension(file); // if no extension, no sub-extension, or invalid sub-extension if (ext == null || !Extensions.ContainsKey(ext)) @@ -136,10 +204,7 @@ namespace Diamond.Shaders } var type = Extensions[ext]; - if (name == null) - name = fileName; - - return FromFile(path, type, name); + return FromFile(path, type); } #endregion diff --git a/Diamond/Textures/Texture.cs b/Diamond/Textures/Texture.cs deleted file mode 100644 index 869554c..0000000 --- a/Diamond/Textures/Texture.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System.Drawing; -using System.Drawing.Imaging; -using System.IO; -using Diamond.Wrappers; -using OpenTK.Graphics.OpenGL4; -using PixelFormat = OpenTK.Graphics.OpenGL4.PixelFormat; - -namespace Diamond.Textures -{ - /// - /// Manages a OpenGL Texture object - /// - public class Texture : GLObject - { - internal readonly TextureWrap Wrapper; - - internal Texture(TextureWrap wrapper, string name) - { - Wrapper = wrapper; - Name = name; - } - - /// - /// This textures target; how it is used - /// - public TextureTarget Target => Wrapper.Target; - - /// - /// Bind this texture to a particular unit - /// - public void Bind(int unit) => Wrapper.Bind(unit); - - public override string ToString() => Name == null - ? $"{Wrapper}" - : $"{Wrapper} \'{Name}\'"; - - public override void Dispose() - { - Logger.Debug("Disposing {0}", this); - Wrapper.Dispose(); - } - - #region Factory Methods - - /// - /// Create a texture object and upload bitmap data to it - /// - /// The image to upload - /// The name of this GLObject - /// The initialized Texture, or null if initialsation failed - public static Texture FromBitmap(Bitmap bmp, string name = null) - { - var wrapper = new TextureWrap(TextureTarget.Texture2D); - var service = new Texture(wrapper, null); - - Logger.Debug("Created Texture {0}", service); - - wrapper.Bind(); - - // todo: expose texture parameters to enable setting different filters - wrapper.TexParameter(TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Nearest); - wrapper.TexParameter(TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Nearest); - - var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, - System.Drawing.Imaging.PixelFormat.Format32bppArgb); - wrapper.Image2D(PixelInternalFormat.Rgba, bmp.Width, bmp.Height, PixelFormat.Bgra, PixelType.UnsignedByte, - data.Scan0); - bmp.UnlockBits(data); - - return service; - } - - /// - /// Create a texture and upload the contents of an image file to it - /// - /// The path to the file - /// The name of this GLObject - /// The initialized Texture, or null if instantiation failed - public static Texture FromFile(string path, string name = null) - { - if (name == null) - name = Path.GetFileNameWithoutExtension(path); - - return FromBitmap(new Bitmap(path), name); - } - - #endregion - } -} \ No newline at end of file diff --git a/Diamond/Util/ObjVertex.cs b/Diamond/Util/ObjVertex.cs deleted file mode 100644 index 16bd041..0000000 --- a/Diamond/Util/ObjVertex.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Diamond.Buffers; -using OpenTK; - -namespace Diamond.Util -{ - /// - /// Vertex buffer data for Wavefront meshes - /// - [VertexData] - public struct ObjVertex - { - /// - /// Vertex position (v) - /// - [VertexPointer("position", 3)] - [VertexPointer("v", 3)] - public Vector3 Position; - - /// - /// UV coordinate (vt) - /// - [VertexPointer("uv", 2)] - [VertexPointer("vt", 2)] - public Vector2 UV; - - /// - /// Vertex normal (vn) - /// - [VertexPointer("normal", 3)] - [VertexPointer("vn", 3)] - public Vector3 Normal; - - /// - /// Create a new ObjVertex - /// - /// The vertex position (v) - /// The uv coordinate (vt) - /// The vertex normal (n) - public ObjVertex(Vector3 position, Vector2 uv, Vector3 normal) - { - Position = position; - UV = uv; - Normal = normal; - } - } -} \ No newline at end of file diff --git a/Diamond/Util/TileData.cs b/Diamond/Util/TileData.cs deleted file mode 100644 index 9493a4d..0000000 --- a/Diamond/Util/TileData.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Diamond.Buffers; -using OpenTK; - -namespace Diamond.Util -{ - /// - /// Vertex buffer data for instanced rendering - /// - [VertexData(Divisor = 1)] - public struct TileData - { - /// - /// The global position of the instance - /// - [VertexPointer("glbpos", 3)] - [VertexPointer("global_pos", 3)] - public Vector3 Position; - - /// - /// Create a new TileData - /// - /// The global position of the instance - public TileData(Vector3 position) - { - Position = position; - } - } -} \ No newline at end of file diff --git a/Diamond/Wrappers/BufferWrap.cs b/Diamond/Wrappers/BufferWrap.cs deleted file mode 100644 index ba924d5..0000000 --- a/Diamond/Wrappers/BufferWrap.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Wrappers -{ - /// - /// Wrapper class for OpenGL Buffer objects - /// - internal sealed class BufferWrap : Wrapper - { - #region Constructor, GLDelete() - - internal BufferWrap(BufferTarget target, BufferUsageHint usage) - : base(GL.GenBuffer()) - { - Target = target; - Usage = usage; - } - - protected override void GLDelete() => GL.DeleteBuffer(Id); - - #endregion - - #region Properties - - #region Stored - - /// - /// BufferTarget parameter used in gl* calls - /// - public BufferTarget Target { get; } - - /// - /// BufferUsageHint parameter using in glBufferData calls - /// - public BufferUsageHint Usage { get; set; } - - #endregion - - #endregion - - #region Methods - - /// - /// Binds this buffer (glBindBuffer) - /// - public void Bind() => GL.BindBuffer(Target, Id); - - /// - /// Upload data to this buffer (glBufferData) - /// - /// Type of value to upload - /// Size of T in bytes - /// Values to upload - public void Data(int size, T[] data) where T : struct - { - Bind(); - GL.BufferData(Target, (IntPtr)(size * data.Length), data, Usage); - } - - /// - /// Upload a range data to this buffer (glBufferSubData) - /// - /// Type of value to upload - /// Size of T in bytes - /// Offset of upload range in bytes - /// Number of bytes to upload - /// All values to upload (offset will be applied to both this and the target) - public void SubData(int size, int offset, int count, T[] data) where T : struct - { - Bind(); - GL.BufferSubData(Target, (IntPtr)(offset * size), (IntPtr)(count * size), data); - } - - #endregion - - public override string ToString() => $"{Target} ({Id})"; - } -} \ No newline at end of file diff --git a/Diamond/Wrappers/ProgramWrap.cs b/Diamond/Wrappers/ProgramWrap.cs deleted file mode 100644 index 7e014bd..0000000 --- a/Diamond/Wrappers/ProgramWrap.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Text; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Wrappers -{ - /// - /// Wrapper class for OpenGL Program objects - /// - internal sealed class ProgramWrap : Wrapper - { - #region Constructor, GLDelete() - - internal ProgramWrap() - : base(GL.CreateProgram()) - { - } - - protected override void GLDelete() => GL.DeleteProgram(Id); - - #endregion - - #region Properties - - /// - /// Get the number of active uniforms for this program - /// - public int ActiveUniforms => Get(GetProgramParameterName.ActiveUniforms); - - /// - /// Get the number of active attributes for this program - /// - public int ActiveAttributes => Get(GetProgramParameterName.ActiveAttributes); - - /// - /// Check whether this program has been Linked - /// - public bool Linked => Get(GetProgramParameterName.LinkStatus) != 0; - - /// - /// Get the InfoLog related to this program. Unless Link() failed, should be null. - /// - public string InfoLog => GL.GetProgramInfoLog(Id).Trim(); // trim to remove trailing newlines - - #endregion - - #region Methods - - /// - /// Get a parameter from this program (glGetProgram) - /// - /// The parameter to get - /// The int value of the parameter - public int Get(GetProgramParameterName parameter) - { - GL.GetProgram(Id, parameter, out int res); - return res; - } - - /// - /// Attach a compiled shader to this program (glAttachShader) - /// - /// - public void Attach(ShaderWrap shader) => GL.AttachShader(Id, shader.Id); - - /// - /// Link this program (glLinkProgram) - /// - public void Link() => GL.LinkProgram(Id); - - /// - /// Use this program (glUseProgram) - /// - public void Use() => GL.UseProgram(Id); - - /// - /// Get the name of the uniform at a location - /// - /// The uniform id - /// The uniform name - public string UniformName(int location) - { - var sb = new StringBuilder(64); - GL.GetActiveUniformName(Id, location, sb.Capacity, out int length, sb); - return sb.ToString(); - } - - /// - /// Get the name of the attribute at a location - /// - /// The attribute id - /// The attribute name - public string AttributeName(int location) - { - var sb = new StringBuilder(64); - GL.GetActiveAttrib(Id, location, sb.Capacity, out int length, out int size, out ActiveAttribType type, sb); - return sb.ToString(); - } - - #endregion - - public override string ToString() => $"Program ({Id})"; - } -} \ No newline at end of file diff --git a/Diamond/Wrappers/ShaderWrap.cs b/Diamond/Wrappers/ShaderWrap.cs deleted file mode 100644 index f63c24f..0000000 --- a/Diamond/Wrappers/ShaderWrap.cs +++ /dev/null @@ -1,86 +0,0 @@ -using System.Text; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Wrappers -{ - /// - /// Wrapper class for OpenGL Shader objects - /// - internal sealed class ShaderWrap : Wrapper - { - #region Constructor, GLDelete() - - internal ShaderWrap(ShaderType shaderType) - : base(GL.CreateShader(shaderType)) - { - ShaderType = shaderType; - } - - protected override void GLDelete() => GL.DeleteShader(Id); - - #endregion - - #region Properties - - #region Stored - - /// - /// The type of this shader - stored at creation time to prevent repeated queries - /// - public ShaderType ShaderType { get; } - - #endregion - - /// - /// Get or set the source of this shader (glShaderSource) - /// - public string Source - { - get - { - var sb = new StringBuilder(1024); - GL.GetShaderSource(Id, sb.Capacity, out int length, sb); - return sb.ToString(); - } - set { GL.ShaderSource(Id, value); } - } - - /// - /// Check the compilation status of this shader - /// - public bool Compiled - { - get - { - GL.GetShader(Id, ShaderParameter.CompileStatus, out int res); - return res != 0; - } - } - - public string InfoLog => GL.GetShaderInfoLog(Id); - - #endregion - - #region Methods - - /// - /// Get a parameter of this shader (glGetShader) - /// - /// The parameter to get - /// The parameter value - public int Get(ShaderParameter parameter) - { - GL.GetShader(Id, parameter, out int res); - return res; - } - - /// - /// Compile this shader (glCompileShader) - /// - public void Compile() => GL.CompileShader(Id); - - #endregion - - public override string ToString() => $"{ShaderType} ({Id})"; - } -} \ No newline at end of file diff --git a/Diamond/Wrappers/TextureWrap.cs b/Diamond/Wrappers/TextureWrap.cs deleted file mode 100644 index 8423298..0000000 --- a/Diamond/Wrappers/TextureWrap.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Wrappers -{ - /// - /// Wrapper class for OpenGL Texture objects - /// - internal sealed class TextureWrap : Wrapper - { - #region Constructor, GLDelete() - - internal TextureWrap(TextureTarget target) - : base(GL.GenTexture()) - { - Target = target; - } - - protected override void GLDelete() => GL.DeleteTexture(Id); - - #endregion - - #region Properties - - #region Stored - - /// - /// The target for this texture; Texture type. - /// - public TextureTarget Target { get; } - - #endregion - - #endregion - - #region Methods - - /// - /// Bind this texture to the currently active TextureUnit (glBindTexture) - /// - public void Bind() => GL.BindTexture(Target, Id); - - /// - /// Bind this texture to a particular TextureUnit (glActiveTexture, glBindTexture) - /// - /// Unit to bind to - public void Bind(int unit) - { - GL.ActiveTexture(TextureUnit.Texture0 + unit); - Bind(); - } - - /// - /// Set a texture parameter (glTexParameter) - /// - /// The parameter to set - /// The value to set - public void TexParameter(TextureParameterName parameter, int value) => GL.TexParameter(Target, parameter, - value); - - /// - /// Upload data to this texture - /// - /// The number of color components in the texture - /// The width of the texture - /// The height of the texture - /// The pixel format of the texture - /// The type of the pixel data - /// Location of the pixel data - public void Image2D(PixelInternalFormat internalFormat, int width, int height, PixelFormat format, - PixelType type, IntPtr pixels) => - GL.TexImage2D(Target, 0, internalFormat, width, height, 0, format, type, pixels); - - #endregion - - public override string ToString() => $"{Target} ({Id})"; - } -} \ No newline at end of file diff --git a/Diamond/Wrappers/Wrapper.cs b/Diamond/Wrappers/Wrapper.cs deleted file mode 100644 index 347f56d..0000000 --- a/Diamond/Wrappers/Wrapper.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using NLog; -using OpenTK.Graphics; - -namespace Diamond.Wrappers -{ - internal abstract class Wrapper : IDisposable - { - /// - /// Logger for all Wrapper types. - /// - protected static readonly Logger Logger = LogManager.GetLogger("Wrapper"); - - /// - /// The OpenGL name of this object - /// - public int Id { get; private set; } - - // Force wrapper types to generate an Id at creation time - protected Wrapper(int id) - { - Id = id; - } - - public override string ToString() => $"{GetType().Name} {Id}"; - - #region IDisposable - - /// - /// Delete this OpenGL object (glDelete*) - /// - protected abstract void GLDelete(); - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - return; - - // no managed resources to dispose - - if (GraphicsContext.CurrentContext == null) - Logger.Error("No graphics context, cannot delete {0}", this); - else - GLDelete(); - - Id = 0; - - _disposed = true; - } - - #region Implemented - - private bool _disposed; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~Wrapper() - { - Dispose(false); - } - - #endregion - - #endregion - } -} \ No newline at end of file diff --git a/hexworld/HexRender.cs b/hexworld/HexRender.cs index b38cfe5..ee30754 100644 --- a/hexworld/HexRender.cs +++ b/hexworld/HexRender.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Diamond.Render; using Diamond.Shaders; -using Diamond.Textures; using Diamond.Util; using Newtonsoft.Json.Linq; using OpenTK; @@ -15,142 +13,31 @@ namespace hexworld { public class HexRender : GameWindow { - #region Fields - - #region Disposables - - private Program _texPgm; - - private Texture _doorTex; - private Texture _grassTex; - private Texture _stoneTex; - - private Dictionary> _meshVbos; - private VertexBuffer[] _tileVbos; - - protected override void OnClosed(EventArgs e) - { - _texPgm?.Dispose(); - - _doorTex?.Dispose(); - _grassTex?.Dispose(); - _stoneTex?.Dispose(); - - foreach (var vbo in _meshVbos.Values) - vbo?.Dispose(); - - foreach (var vbo in _tileVbos) - vbo?.Dispose(); - } - - #endregion - - private List> _renderGroups; - - private Camera _camera; - - private double _time; - - #endregion - public HexRender(int width, int height) : base(width, height, new GraphicsMode(32, 24, 0, 0)) { Width = width; - Height = Height; + Height = height; X = (DisplayDevice.Default.Width - Width) / 2; Y = (DisplayDevice.Default.Height - Height) / 2; } + private Program _pgm; + + /// + protected override void OnUnload(EventArgs e) + { + base.OnUnload(e); + + _pgm.Dispose(); + } + + /// protected override void OnLoad(EventArgs e) { base.OnLoad(e); - _texPgm = Program.FromFiles("res/obj.vs.glsl", "res/obj.fs.glsl"); - - _doorTex = Texture.FromFile("res/door.png"); - _grassTex = Texture.FromFile("res/grass.png"); - _stoneTex = Texture.FromFile("res/stone.png"); - - var dir = "res"; - - var json = JObject.Parse(File.ReadAllText("res/level.json")); - - var allTiles = json["tiles"] - .GroupBy(ti => ti["tex"]) - .Select(g => g - .Select(ti => ti["pos"]) - .Select(pos => pos.ToObject()) - .Select(pos => new TileData(pos)) - .ToArray()) - .Select(arr => new SubArray(arr)) - .ToArray(); - - _tileVbos = VertexBuffer.FromArrays(allTiles, 0, "tiles"); - - var vertexBuffers = json["models"] - .Select(path => (string) path) - .Select(path => Path.Combine(dir, path)) - .Select(VertexBuffer.FromWavefront) - .SelectMany(meshes => meshes) - .ToArray(); - - _meshVbos = vertexBuffers.ToDictionary(vbo => vbo.Name, vbo => vbo); - - _camera = new Camera(); - - _renderGroups = new List> - { - new RenderGroup() - { - Vertices = _meshVbos["Cube"], - Instance = _tileVbos[0], - Program = _texPgm, - Texture = _stoneTex, - Camera = _camera, - }, - new RenderGroup() - { - Vertices = _meshVbos["Cube"], - Instance = _tileVbos[1], - Program = _texPgm, - Texture = _grassTex, - Camera = _camera, - } - }; - } - - protected override void OnUpdateFrame(FrameEventArgs e) - { - base.OnUpdateFrame(e); - - _time += e.Time; - - _camera.View = Matrix4.CreateRotationZ((float) _time / 3) * - Matrix4.LookAt(10 * Vector3.One, Vector3.Zero, Vector3.UnitZ); - _camera.Projection = Matrix4.CreateOrthographic(Width / 100f, Height / 100f, -100, 100); - } - - protected override void OnRenderFrame(FrameEventArgs e) - { - base.OnRenderFrame(e); - - GL.Viewport(ClientRectangle); - - GL.ClearColor(0.2392157F, 0.5607843F, 0.9960784F, 1f); - GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); - - GL.Enable(EnableCap.DepthTest); - GL.DepthFunc(DepthFunction.Lequal); - GL.Enable(EnableCap.Blend); - GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); - - foreach (var renderGroup in _renderGroups) - { - renderGroup.Draw(); - } - - SwapBuffers(); + _pgm = Program.FromFiles("res/obj.fs.glsl", "res/obj.vs.glsl"); } } } \ No newline at end of file