diff --git a/Diamond/Buffers/GLBuffer.cs b/Diamond/Buffers/GLBuffer.cs index de5f3fd..edbe3a4 100644 --- a/Diamond/Buffers/GLBuffer.cs +++ b/Diamond/Buffers/GLBuffer.cs @@ -1,41 +1,151 @@ using System; using System.Runtime.InteropServices; +using Diamond.Shaders; using Diamond.Util; +using NLog; using OpenTK.Graphics.OpenGL4; namespace Diamond.Buffers { - public class GLBuffer : GLWrapper where T : struct + internal class GLBufferWrapper : GLWrapper { - public readonly BufferTarget Target; - public readonly BufferUsageHint Usage; + public BufferTarget Target { get; } + public BufferUsageHint Usage { get; set; } - public GLBuffer(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw) - : base((uint) GL.GenBuffer()) + internal GLBufferWrapper(BufferTarget target, BufferUsageHint usage) { + Id = GL.GenBuffer(); Target = target; Usage = usage; } - public void Bind() - { - GL.BindBuffer(Target, Id); - } + public void Bind() => GL.BindBuffer(Target, Id); - protected override void Delete() => GL.DeleteBuffer(Id); - - public void Data(T[] data) + public void Data(int size, T[] data) where T : struct { - var size = Marshal.SizeOf(); Bind(); GL.BufferData(Target, (IntPtr) (size * data.Length), data, Usage); } - public void SubData(SubArray data) + public void SubData(int size, int offset, int count, T[] data) where T : struct { - var size = Marshal.SizeOf(); Bind(); - GL.BufferSubData(Target, (IntPtr) (data.Offset * size), (IntPtr) (data.Length * size), data.Array); + GL.BufferSubData(Target, (IntPtr) (offset * size), (IntPtr) (count * size), data); + } + + public override void GLDelete() => GL.DeleteBuffer(Id); + } + + public class GLBuffer : GLObject where T : struct + { + private GLBufferWrapper _buffer; + internal override GLWrapper Wrapper => _buffer; + + private int _size; + + public BufferTarget Target => _buffer.Target; + + public BufferUsageHint Usage + { + get => _buffer.Usage; + set => _buffer.Usage = value; + } + + internal GLBuffer(GLBufferWrapper buffer, string name) + { + _buffer = buffer; + Name = name; + _size = Marshal.SizeOf(); + } + + public void Data(T[] data) => _buffer.Data(_size, data); + + public void Data(int offset, int count, T[] data) => _buffer.SubData(_size, offset, count, data); + + public void Data(SubArray data) => Data(data.Offset, data.Length, data.Array); + + public override string ToString() => Name == null ? $"{Target} ({Id})" : $"{Target} {Name} ({Id})"; + } + + public static class GLBuffer + { + internal static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public static GLBuffer Empty(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw, + string name = null) where T : struct + { + var wrapper = new GLBufferWrapper(target, usage); + var service = new GLBuffer(wrapper, name); + + Logger.Debug("Created {0}", service); + + return service; + } + + public static GLBuffer FromData(T[] data, BufferTarget target, + BufferUsageHint usage = BufferUsageHint.StaticDraw, + string name = null) where T : struct + { + var service = Empty(target, usage, name); + + service?.Data(data); + + return service; + } + } + + public class VertexBuffer : GLBuffer where T : struct + { + private readonly VertexDataInfo _vdi; + private readonly GLBufferWrapper _buffer; + + internal VertexBuffer(GLBufferWrapper buffer, string name) + : base(buffer, name) + { + _vdi = VertexDataInfo.GetInfo(); + _buffer = buffer; + } + + public void PointTo(Program program) + { + _buffer.Bind(); + foreach (var attr in _vdi.Pointers) + { + var loc = program.AttributeLocation(attr.Name); + if (loc.HasValue) + GL.VertexAttribPointer((int) loc, attr.Size, attr.Type, attr.Normalized, _vdi.Stride, attr.Offset); + } + } + } + + public static class VertexBuffer + { + public static VertexBuffer Empty(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw, + string name = null) where T : struct + { + if (typeof(T).GetCustomAttributes(typeof(VertexDataAttribute), false).Length == 0) + { + GLBuffer.Logger.Warn("Cannot use type {0} to create a VertexBuffer", typeof(T)); + return null; + } + + var wrapper = new GLBufferWrapper(target, usage); + var service = new VertexBuffer(wrapper, name); + + GLBuffer.Logger.Debug("Created {0}", service); + + return service; + } + + public static VertexBuffer FromData(T[] data, BufferTarget target, + BufferUsageHint usage = BufferUsageHint.StaticDraw, + string name = null) where T : struct + { + var service = Empty(target, usage, name); + + service?.Data(data); + + return service; } } } \ No newline at end of file diff --git a/Diamond/Diamond.csproj b/Diamond/Diamond.csproj index 2474d1b..dffddf1 100644 --- a/Diamond/Diamond.csproj +++ b/Diamond/Diamond.csproj @@ -56,9 +56,7 @@ - - diff --git a/Diamond/Level/Level.cs b/Diamond/Level/Level.cs deleted file mode 100644 index 3ebc946..0000000 --- a/Diamond/Level/Level.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using Diamond.Buffers; -using Diamond.Shaders; -using Diamond.Textures; -using Diamond.Util; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using OpenTK; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Level -{ - public class Level : IDisposable - { - public Dictionary Programs { get; private set; } - - private TileData[] _allTiles; - private ObjVertex[] _allVertices; - - private Mesh[] _meshes; - private TileGroup[] _tileGroups; - - private Texture[] _textures; - - private GLBuffer _tileBuffer; - private GLBuffer _vertexBuffer; - - private void InitializeBuffers() - { - _tileBuffer = new GLBuffer(BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw); - _tileBuffer.Data(_allTiles); - - _vertexBuffer = new GLBuffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw); - _vertexBuffer.Data(_allVertices); - } - - public static Level LoadLevel(string file) - { - var levelData = JObject.Parse(File.ReadAllText(file)); - - var dir = Path.GetDirectoryName(file); - - // this is horrendous, but not as bad as trying to directly deserialize it. - - var meshes = levelData["models"] - .Select(path => Mesh.FromObj(Path.Combine(dir, (string) path), false)) - .SelectMany(objects => objects) - .ToArray(); - - var meshDict = meshes - .ToDictionary(mesh => mesh.Name, mesh => mesh); - - var allVertices = Mesh.Join(meshes); - - var programs = levelData["shaders"] - .Select(shader => new - { - name = (string) shader["name"], - program = Program.FromFiles( - shader["files"] - .Select(path => Path.Combine(dir, (string) path)) - .ToArray()) - }) - .ToDictionary(s => s.name, s => s.program); - - var texturePaths = levelData["textures"] - .Select(path => (string) path) - .ToArray(); - var textures = texturePaths.Select(path => Texture.FromBitmap(new Bitmap(Path.Combine(dir, path)))) - .ToArray(); - var textureMap = texturePaths.Select((path, i) => new {path = path, i = i}) - .ToDictionary(v => v.path, v => v.i); - - var tilegroups = levelData["tiles"] - .Select(tile => new - { - info = new - { - mesh = meshDict[(string) tile["mesh"]], - shader = programs[(string) tile["shader"]], - texture = textureMap[(string) tile["tex"]] - }, - pos = tile["pos"].ToObject() - }) - .GroupBy(tile => tile.info) - .Select(group => new TileGroup(group.Key.mesh, group.Key.shader, group.Key.texture, - new SubArray( - group.Select(data => new TileData(data.pos)) - .ToArray()))) - .ToArray(); - - var tileArrays = tilegroups - .Select(group => group.Tiles); - - var allTiles = SubArray.Join(tileArrays); - - var level = new Level - { - _allTiles = allTiles, - _allVertices = allVertices, - _meshes = meshes, - _tileGroups = tilegroups, - Programs = programs, - _textures = textures - }; - - level.InitializeBuffers(); - - return level; - } - - public void Draw() - { - for (var i = 0; i < _textures.Length; i++) - { - var texture = _textures[i]; - texture.Bind(i); - } - - foreach (var tileGroup in _tileGroups) - { - var pgm = tileGroup.Program; - pgm.Use(); - - var loc = pgm.UniformLocation("tex"); - - if (!loc.HasValue) - continue; - - GL.Uniform1((int)loc, tileGroup.Texture); - - pgm.SetAttribPointers(_vertexBuffer); - pgm.SetAttribPointers(_tileBuffer); - - tileGroup.Mesh.DrawInstanced(tileGroup.Tiles); - } - } - - public void Dispose() - { - _tileBuffer?.Dispose(); - _vertexBuffer?.Dispose(); - - foreach (var texture in _textures) - texture?.Dispose(); - - foreach (var program in Programs.Values) - program?.Dispose(); - - GC.SuppressFinalize(this); - } - - ~Level() - { - Dispose(); - } - } -} \ No newline at end of file diff --git a/Diamond/Level/TileGroup.cs b/Diamond/Level/TileGroup.cs deleted file mode 100644 index 98786a3..0000000 --- a/Diamond/Level/TileGroup.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Diamond.Buffers; -using Diamond.Shaders; -using Diamond.Util; - -namespace Diamond.Level -{ - internal class TileGroup - { - public SubArray Tiles; - public Mesh Mesh; - public Program Program; - public int Texture; - - public TileGroup(Mesh mesh, Program program, int texture, SubArray tiles) - { - Mesh = mesh; - Program = program; - Tiles = tiles; - Texture = texture; - } - } -} \ No newline at end of file diff --git a/Diamond/Shaders/Program.cs b/Diamond/Shaders/Program.cs index ef81b94..c7e6a6a 100644 --- a/Diamond/Shaders/Program.cs +++ b/Diamond/Shaders/Program.cs @@ -51,7 +51,7 @@ namespace Diamond.Shaders public class Program : GLObject { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + internal static readonly Logger Logger = LogManager.GetCurrentClassLogger(); internal ProgramWrapper _program; internal override GLWrapper Wrapper => _program; @@ -61,7 +61,7 @@ namespace Diamond.Shaders private readonly Dictionary _uniforms = new Dictionary(); private readonly Dictionary _attributes = new Dictionary(); - private Program(ProgramWrapper program, string name) + internal Program(ProgramWrapper program, string name) { _program = program; Name = name; @@ -79,19 +79,6 @@ namespace Diamond.Shaders return null; } - public void SetAttribPointers(GLBuffer buff) where T : struct - { - var vdi = VertexDataInfo.GetInfo(); - - buff.Bind(); - foreach (var attr in vdi.Pointers) - { - var loc = AttributeLocation(attr.Name); - if (loc.HasValue) - GL.VertexAttribPointer((int) loc, attr.Size, attr.Type, attr.Normalized, vdi.Stride, attr.Offset); - } - } - public void Use() { GL.UseProgram(Id); @@ -126,7 +113,7 @@ namespace Diamond.Shaders return true; } - public override string ToString() => $"\'{Name}\' ({Id})"; + public override string ToString() => $"Program \'{Name}\' ({Id})"; #region Factory Methods diff --git a/Diamond/Shaders/Shader.cs b/Diamond/Shaders/Shader.cs index f930602..1284a3b 100644 --- a/Diamond/Shaders/Shader.cs +++ b/Diamond/Shaders/Shader.cs @@ -46,7 +46,7 @@ namespace Diamond.Shaders public class Shader : GLObject { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + internal static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly ShaderWrapper _shader; internal override GLWrapper Wrapper => _shader; @@ -54,7 +54,7 @@ namespace Diamond.Shaders public string Source { get; } public ShaderType Type { get; } - private Shader(ShaderWrapper shader, string source, ShaderType type, string name) + internal Shader(ShaderWrapper shader, string source, ShaderType type, string name) { _shader = shader; Source = source;