Migrating to Factory/Wrapper - GLBuffer and VertexBuffer complete
This commit is contained in:
@@ -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<T> : 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<T>(int size, T[] data) where T : struct
|
||||
{
|
||||
var size = Marshal.SizeOf<T>();
|
||||
Bind();
|
||||
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();
|
||||
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="Buffers\VertexDataAttribute.cs" />
|
||||
<Compile Include="GLWrapper.cs" />
|
||||
<Compile Include="Level\Level.cs" />
|
||||
<Compile Include="Level\TileData.cs" />
|
||||
<Compile Include="Level\TileGroup.cs" />
|
||||
<Compile Include="Mesh.cs" />
|
||||
<Compile Include="ObjVertex.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
|
||||
{
|
||||
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<string, int> _uniforms = 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;
|
||||
Name = name;
|
||||
@@ -79,19 +79,6 @@ namespace Diamond.Shaders
|
||||
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()
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user