Migrating to Factory/Wrapper - GLBuffer and VertexBuffer complete
This commit is contained in:
@@ -1,41 +1,151 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Diamond.Shaders;
|
||||||
using Diamond.Util;
|
using Diamond.Util;
|
||||||
|
using NLog;
|
||||||
using OpenTK.Graphics.OpenGL4;
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
|
||||||
namespace Diamond.Buffers
|
namespace Diamond.Buffers
|
||||||
{
|
{
|
||||||
public class GLBuffer<T> : GLWrapper where T : struct
|
internal class GLBufferWrapper : GLWrapper
|
||||||
{
|
{
|
||||||
public readonly BufferTarget Target;
|
public BufferTarget Target { get; }
|
||||||
public readonly BufferUsageHint Usage;
|
public BufferUsageHint Usage { get; set; }
|
||||||
|
|
||||||
public GLBuffer(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw)
|
internal GLBufferWrapper(BufferTarget target, BufferUsageHint usage)
|
||||||
: base((uint) GL.GenBuffer())
|
|
||||||
{
|
{
|
||||||
|
Id = GL.GenBuffer();
|
||||||
Target = target;
|
Target = target;
|
||||||
Usage = usage;
|
Usage = usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Bind()
|
public void Bind() => GL.BindBuffer(Target, Id);
|
||||||
{
|
|
||||||
GL.BindBuffer(Target, Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Delete() => GL.DeleteBuffer(Id);
|
public void Data<T>(int size, T[] data) where T : struct
|
||||||
|
|
||||||
public void Data(T[] data)
|
|
||||||
{
|
{
|
||||||
var size = Marshal.SizeOf<T>();
|
|
||||||
Bind();
|
Bind();
|
||||||
GL.BufferData(Target, (IntPtr) (size * data.Length), data, Usage);
|
GL.BufferData(Target, (IntPtr) (size * data.Length), data, Usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SubData(SubArray<T> data)
|
public void SubData<T>(int size, int offset, int count, T[] data) where T : struct
|
||||||
{
|
{
|
||||||
var size = Marshal.SizeOf<T>();
|
|
||||||
Bind();
|
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<T> : 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<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<T> 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<T> Empty<T>(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw,
|
||||||
|
string name = null) where T : struct
|
||||||
|
{
|
||||||
|
var wrapper = new GLBufferWrapper(target, usage);
|
||||||
|
var service = new GLBuffer<T>(wrapper, name);
|
||||||
|
|
||||||
|
Logger.Debug("Created {0}", service);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GLBuffer<T> FromData<T>(T[] data, BufferTarget target,
|
||||||
|
BufferUsageHint usage = BufferUsageHint.StaticDraw,
|
||||||
|
string name = null) where T : struct
|
||||||
|
{
|
||||||
|
var service = Empty<T>(target, usage, name);
|
||||||
|
|
||||||
|
service?.Data(data);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VertexBuffer<T> : GLBuffer<T> where T : struct
|
||||||
|
{
|
||||||
|
private readonly VertexDataInfo _vdi;
|
||||||
|
private readonly GLBufferWrapper _buffer;
|
||||||
|
|
||||||
|
internal VertexBuffer(GLBufferWrapper buffer, string name)
|
||||||
|
: base(buffer, name)
|
||||||
|
{
|
||||||
|
_vdi = VertexDataInfo.GetInfo<T>();
|
||||||
|
_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<T> Empty<T>(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<T>(wrapper, name);
|
||||||
|
|
||||||
|
GLBuffer.Logger.Debug("Created {0}", service);
|
||||||
|
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static VertexBuffer<T> FromData<T>(T[] data, BufferTarget target,
|
||||||
|
BufferUsageHint usage = BufferUsageHint.StaticDraw,
|
||||||
|
string name = null) where T : struct
|
||||||
|
{
|
||||||
|
var service = Empty<T>(target, usage, name);
|
||||||
|
|
||||||
|
service?.Data(data);
|
||||||
|
|
||||||
|
return service;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,9 +56,7 @@
|
|||||||
<Compile Include="Util\SubArray.cs" />
|
<Compile Include="Util\SubArray.cs" />
|
||||||
<Compile Include="Buffers\VertexDataAttribute.cs" />
|
<Compile Include="Buffers\VertexDataAttribute.cs" />
|
||||||
<Compile Include="GLWrapper.cs" />
|
<Compile Include="GLWrapper.cs" />
|
||||||
<Compile Include="Level\Level.cs" />
|
|
||||||
<Compile Include="Level\TileData.cs" />
|
<Compile Include="Level\TileData.cs" />
|
||||||
<Compile Include="Level\TileGroup.cs" />
|
|
||||||
<Compile Include="Mesh.cs" />
|
<Compile Include="Mesh.cs" />
|
||||||
<Compile Include="ObjVertex.cs" />
|
<Compile Include="ObjVertex.cs" />
|
||||||
<Compile Include="Shaders\Program.cs" />
|
<Compile Include="Shaders\Program.cs" />
|
||||||
|
|||||||
@@ -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<string, Program> Programs { get; private set; }
|
|
||||||
|
|
||||||
private TileData[] _allTiles;
|
|
||||||
private ObjVertex[] _allVertices;
|
|
||||||
|
|
||||||
private Mesh<ObjVertex>[] _meshes;
|
|
||||||
private TileGroup[] _tileGroups;
|
|
||||||
|
|
||||||
private Texture[] _textures;
|
|
||||||
|
|
||||||
private GLBuffer<TileData> _tileBuffer;
|
|
||||||
private GLBuffer<ObjVertex> _vertexBuffer;
|
|
||||||
|
|
||||||
private void InitializeBuffers()
|
|
||||||
{
|
|
||||||
_tileBuffer = new GLBuffer<TileData>(BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw);
|
|
||||||
_tileBuffer.Data(_allTiles);
|
|
||||||
|
|
||||||
_vertexBuffer = new GLBuffer<ObjVertex>(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<Vector3>()
|
|
||||||
})
|
|
||||||
.GroupBy(tile => tile.info)
|
|
||||||
.Select(group => new TileGroup(group.Key.mesh, group.Key.shader, group.Key.texture,
|
|
||||||
new SubArray<TileData>(
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using Diamond.Buffers;
|
|
||||||
using Diamond.Shaders;
|
|
||||||
using Diamond.Util;
|
|
||||||
|
|
||||||
namespace Diamond.Level
|
|
||||||
{
|
|
||||||
internal class TileGroup
|
|
||||||
{
|
|
||||||
public SubArray<TileData> Tiles;
|
|
||||||
public Mesh<ObjVertex> Mesh;
|
|
||||||
public Program Program;
|
|
||||||
public int Texture;
|
|
||||||
|
|
||||||
public TileGroup(Mesh<ObjVertex> mesh, Program program, int texture, SubArray<TileData> tiles)
|
|
||||||
{
|
|
||||||
Mesh = mesh;
|
|
||||||
Program = program;
|
|
||||||
Tiles = tiles;
|
|
||||||
Texture = texture;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -51,7 +51,7 @@ namespace Diamond.Shaders
|
|||||||
|
|
||||||
public class Program : GLObject
|
public class Program : GLObject
|
||||||
{
|
{
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
internal static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
internal ProgramWrapper _program;
|
internal ProgramWrapper _program;
|
||||||
internal override GLWrapper Wrapper => _program;
|
internal override GLWrapper Wrapper => _program;
|
||||||
@@ -61,7 +61,7 @@ namespace Diamond.Shaders
|
|||||||
private readonly Dictionary<string, int> _uniforms = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _uniforms = new Dictionary<string, int>();
|
||||||
private readonly Dictionary<string, int> _attributes = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _attributes = new Dictionary<string, int>();
|
||||||
|
|
||||||
private Program(ProgramWrapper program, string name)
|
internal Program(ProgramWrapper program, string name)
|
||||||
{
|
{
|
||||||
_program = program;
|
_program = program;
|
||||||
Name = name;
|
Name = name;
|
||||||
@@ -79,19 +79,6 @@ namespace Diamond.Shaders
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAttribPointers<T>(GLBuffer<T> buff) where T : struct
|
|
||||||
{
|
|
||||||
var vdi = VertexDataInfo.GetInfo<T>();
|
|
||||||
|
|
||||||
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()
|
public void Use()
|
||||||
{
|
{
|
||||||
GL.UseProgram(Id);
|
GL.UseProgram(Id);
|
||||||
@@ -126,7 +113,7 @@ namespace Diamond.Shaders
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => $"\'{Name}\' ({Id})";
|
public override string ToString() => $"Program \'{Name}\' ({Id})";
|
||||||
|
|
||||||
#region Factory Methods
|
#region Factory Methods
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Diamond.Shaders
|
|||||||
|
|
||||||
public class Shader : GLObject
|
public class Shader : GLObject
|
||||||
{
|
{
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
internal static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private readonly ShaderWrapper _shader;
|
private readonly ShaderWrapper _shader;
|
||||||
internal override GLWrapper Wrapper => _shader;
|
internal override GLWrapper Wrapper => _shader;
|
||||||
@@ -54,7 +54,7 @@ namespace Diamond.Shaders
|
|||||||
public string Source { get; }
|
public string Source { get; }
|
||||||
public ShaderType Type { 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;
|
_shader = shader;
|
||||||
Source = source;
|
Source = source;
|
||||||
|
|||||||
Reference in New Issue
Block a user