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