removed Mesh, added VertexBuffer

This commit is contained in:
2017-03-03 01:01:26 -05:00
parent 0d34233cb7
commit 3e3b033de6
7 changed files with 280 additions and 235 deletions

View File

@@ -17,7 +17,7 @@ namespace Diamond.Buffers
internal readonly BufferWrap Wrapper;
private readonly VertexDataInfo _vdi;
private readonly int _size;
protected readonly int Size;
/// <summary>
/// The target for this buffer; its type
@@ -38,7 +38,7 @@ namespace Diamond.Buffers
{
Wrapper = wrapper;
Name = name;
_size = Marshal.SizeOf<T>();
Size = Marshal.SizeOf<T>();
_vdi = VertexDataInfo.GetInfo<T>();
}
@@ -46,7 +46,7 @@ namespace Diamond.Buffers
/// Upload data to this buffer
/// </summary>
/// <param name="data">The data to upload</param>
public void Data(T[] data) => Wrapper.Data(_size, data);
public void Data(T[] data) => Wrapper.Data(Size, data);
/// <summary>
/// Upload a range of data to this buffer
@@ -54,7 +54,7 @@ namespace Diamond.Buffers
/// <param name="offset">The range offset</param>
/// <param name="count">The range length</param>
/// <param name="data">The data to upload, offset and length apply to both this and the target</param>
public void Data(int offset, int count, T[] data) => Wrapper.SubData(_size, offset, count, data);
public void Data(int offset, int count, T[] data) => Wrapper.SubData(Size, offset, count, data);
/// <summary>
/// Upload a range of data to this buffer

View File

@@ -64,7 +64,7 @@
<Compile Include="Buffers\VertexDataAttribute.cs" />
<Compile Include="Wrappers\Wrapper.cs" />
<Compile Include="Util\TileData.cs" />
<Compile Include="Util\Mesh.cs" />
<Compile Include="Render\VertexBuffer.cs" />
<Compile Include="Util\ObjVertex.cs" />
<Compile Include="Shaders\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@@ -13,23 +13,15 @@ namespace Diamond.Render
/// <typeparam name="TVertex">The type of data to use as Vertex information</typeparam>
public class RenderGroup<TInstance, TVertex> where TInstance : struct where TVertex : struct
{
/// <summary>
/// The range of instance values to render
/// </summary>
public SubArray<TInstance> Instances;
/// <summary>
/// The range of vertex values to render
/// </summary>
public Mesh<TVertex> Vertices;
public VertexBuffer<TVertex> Vertices;
/// <summary>
/// The buffer to use for instance data
/// The range of instance values to render
/// </summary>
public Buffer<TInstance> InstanceBuffer;
/// <summary>
/// The buffer to use for instance data
/// </summary>
public Buffer<TVertex> VertexBuffer;
public VertexBuffer<TInstance> Instance;
/// <summary>
/// The program to use to render this Rendergroup
@@ -53,9 +45,6 @@ namespace Diamond.Render
{
Program.Use();
InstanceBuffer.PointTo(Program);
VertexBuffer.PointTo(Program);
Texture.Bind(0);
var texLoc = Program.UniformLocation("tex");
@@ -69,7 +58,10 @@ namespace Diamond.Render
if (projLoc.HasValue)
GL.UniformMatrix4(projLoc.Value, false, ref Camera.Projection);
Vertices.DrawInstanced(Instances);
if (Instance != null)
Vertices.DrawInstanced(Instance);
else
Vertices.Draw();
}
}
}

View File

@@ -0,0 +1,203 @@
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
{
public class VertexBuffer<T> : IDisposable where T : struct
{
private Logger Logger = LogManager.GetLogger("VertexBuffer");
public string Name { get; set; }
public Buffer<T> Buffer;
public SubArray<T> Vertices;
public PrimitiveType Primitive;
private static readonly VertexDataInfo tVdi;
static VertexBuffer()
{
tVdi = VertexDataInfo.GetInfo<T>();
}
internal VertexBuffer(Buffer<T> buffer, SubArray<T> vertices, PrimitiveType primitive, string name)
{
Buffer = buffer;
Vertices = vertices;
Primitive = primitive;
Name = name;
}
public void Draw()
{
Buffer.PointTo(Program.Current);
tVdi.EnableVertexPointers();
GL.DrawArrays(Primitive, Vertices.Offset, Vertices.Length);
tVdi.DisableVertexPointers();
}
public void DrawInstanced<TI>(VertexBuffer<TI> instance) where TI : struct
{
var tiVdi = VertexBuffer<TI>.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();
}
}
public static class VertexBuffer
{
public static VertexBuffer<T>[] FromArrays<T>(T[][] arrays, PrimitiveType primitive = PrimitiveType.Triangles,
string name = null) where T : struct
{
var buffer = Buffer.Empty<T>(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw, name);
var vertices = arrays.SelectMany(x => x).ToArray();
buffer.Data(vertices);
var vertBuffers = new List<VertexBuffer<T>>();
var offset = 0;
foreach (var array in arrays)
{
vertBuffers.Add(new VertexBuffer<T>(
buffer,
new SubArray<T>(vertices, offset, array.Length),
primitive, name));
offset += array.Length;
}
return vertBuffers.ToArray();
}
public static VertexBuffer<T>[] FromArrays<T>(IEnumerable<IEnumerable<T>> arrays,
PrimitiveType primitive = PrimitiveType.Triangles, string name = null) where T : struct =>
FromArrays(arrays.Select(x => x.ToArray()).ToArray(), primitive, name);
public static VertexBuffer<ObjVertex>[] FromWavefront(string file)
{
var lines = File.ReadAllLines(file);
var buffer = Buffer<ObjVertex>.Empty(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw,
$"{file} buffer");
var vs = new List<Vector3>();
var vts = new List<Vector2>();
var vns = new List<Vector3>();
var faces = new List<ObjVertex>();
var vertices = new List<ObjVertex>();
var name = file;
var vertBuffers = new List<VertexBuffer<ObjVertex>>();
foreach (var line in lines)
{
if (line.StartsWith("#")) continue;
var items = line.Split(' ');
switch (items[0])
{
case "v":
var v = new Vector3(
float.Parse(items[1]),
float.Parse(items[2]),
float.Parse(items[3]));
vs.Add(v);
break;
case "vt":
var vt = new Vector2(
float.Parse(items[1]),
1 - float.Parse(items[2]));
vts.Add(vt);
break;
case "vn":
var vn = new Vector3(
float.Parse(items[1]),
float.Parse(items[2]),
float.Parse(items[3]));
vns.Add(vn);
break;
case "f":
for (var i = 1; i < 4; i++)
{
var inds = items[i].Split('/');
var vi = inds[0] == "" ? Vector3.Zero : vs[int.Parse(inds[0]) - 1];
var vti = inds[1] == "" ? Vector2.Zero : vts[int.Parse(inds[1]) - 1];
var vni = inds[2] == "" ? Vector3.Zero : vns[int.Parse(inds[2]) - 1];
var f = new ObjVertex(vi, vti, vni);
faces.Add(f);
}
break;
case "o":
if (faces.Count > 0)
{
var count = vertices.Count;
vertices.AddRange(faces);
vertBuffers.Add(new VertexBuffer<ObjVertex>(
buffer,
new SubArray<ObjVertex>(vertices.ToArray(), count, faces.Count),
PrimitiveType.Triangles,
name));
}
name = items[1];
faces.Clear();
break;
default:
break;
}
}
if (faces.Count > 0)
{
var count = vertices.Count;
vertices.AddRange(faces);
vertBuffers.Add(new VertexBuffer<ObjVertex>(
buffer, new SubArray<ObjVertex>(vertices.ToArray(), count, faces.Count),
PrimitiveType.Triangles,
name));
}
var data = vertices.ToArray();
foreach (var vertexBuffer in vertBuffers)
vertexBuffer.Vertices.Array = data;
buffer.Data(vertices.ToArray());
return vertBuffers.ToArray();
}
}
}

View File

@@ -1,146 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Diamond.Buffers;
using NLog;
using OpenTK;
using OpenTK.Graphics.OpenGL4;
namespace Diamond.Util
{
public class Mesh<T> where T : struct
{
private static readonly Logger Logger = LogManager.GetLogger("Mesh");
public SubArray<T> Vertices;
public PrimitiveType Primitive;
public string Name { get; set; }
private static readonly VertexDataInfo tVdi;
static Mesh()
{
tVdi = VertexDataInfo.GetInfo<T>();
}
public Mesh(T[] vertices, PrimitiveType primitive = PrimitiveType.Triangles)
: this(new SubArray<T>(vertices), primitive)
{
}
public Mesh(SubArray<T> vertices, PrimitiveType primitive = PrimitiveType.Triangles)
{
Vertices = vertices;
Primitive = primitive;
}
public void Draw()
{
tVdi.EnableVertexPointers();
GL.DrawArrays(Primitive, Vertices.Offset, Vertices.Length);
tVdi.DisableVertexPointers();
}
public void DrawInstanced<TI>(SubArray<TI> instanceArray) where TI : struct
{
var tiVdi = VertexDataInfo.GetInfo<TI>();
if (tiVdi.Divisor == 0)
{
Logger.Error("Cannot render mesh with instances of type {0} - Divisor is 0", typeof(TI).Name);
}
tVdi.EnableVertexPointers();
tiVdi.EnableVertexPointers();
GL.DrawArraysInstancedBaseInstance(Primitive, Vertices.Offset, Vertices.Length, instanceArray.Length,
instanceArray.Offset);
tVdi.DisableVertexPointers();
tiVdi.DisableVertexPointers();
}
}
public static class Mesh
{
public static Mesh<ObjVertex>[] FromObj(string file, bool join = true)
{
var lines = File.ReadAllLines(file);
var meshes = new List<Mesh<ObjVertex>>();
var name = file;
var vs = new List<Vector3>();
var vts = new List<Vector2>();
var vns = new List<Vector3>();
var faces = new List<ObjVertex>();
foreach (var line in lines)
{
if (line.StartsWith("#")) continue;
var items = line.Split(' ');
switch (items[0])
{
case "v":
var v = new Vector3(
float.Parse(items[1]),
float.Parse(items[2]),
float.Parse(items[3]));
vs.Add(v);
break;
case "vt":
var vt = new Vector2(
float.Parse(items[1]),
1 - float.Parse(items[2]));
vts.Add(vt);
break;
case "vn":
var vn = new Vector3(
float.Parse(items[1]),
float.Parse(items[2]),
float.Parse(items[3]));
vns.Add(vn);
break;
case "f":
for (var i = 1; i < 4; i++)
{
var inds = items[i].Split('/');
var vi = inds[0] == "" ? Vector3.Zero : vs[int.Parse(inds[0]) - 1];
var vti = inds[1] == "" ? Vector2.Zero : vts[int.Parse(inds[1]) - 1];
var vni = inds[2] == "" ? Vector3.Zero : vns[int.Parse(inds[2]) - 1];
var f = new ObjVertex(vi, vti, vni);
faces.Add(f);
}
break;
case "o":
if (faces.Count > 0)
{
meshes.Add(new Mesh<ObjVertex>(faces.ToArray()) {Name = name});
faces.Clear();
}
name = items[1];
break;
}
}
if (faces.Count > 0)
meshes.Add(new Mesh<ObjVertex>(faces.ToArray()) {Name = name});
if (join)
Join(meshes);
return meshes.ToArray();
}
public static T[] Join<T>(params Mesh<T>[] meshes) where T : struct => Join((IEnumerable<Mesh<T>>) meshes);
public static T[] Join<T>(IEnumerable<Mesh<T>> meshes) where T : struct
{
return SubArray.Join(meshes.Select(x => x.Vertices));
}
}
}

View File

@@ -123,58 +123,58 @@ namespace Diamond.Util
/// </summary>
public static class SubArray
{
/// <summary>
/// Make multiple subArrays cover the same array
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="subArrays">The SubArrays to join</param>
/// <returns>The new underlying array</returns>
public static T[] Join<T>(params SubArray<T>[] subArrays) => Join((IEnumerable<SubArray<T>>) subArrays);
/// <summary>
/// Make multiple subArrays cover the same array
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="subArrays">The SubArrays to join</param>
/// <returns>The new underlying array</returns>
public static T[] Join<T>(IEnumerable<SubArray<T>> subArrays)
{
// todo: this breaks in the case: Join(a, b); Join(b, c)
// possibly create "multiarray" class or similar which would manage these operations
// and prevent this case from arising
var subArrList = subArrays.ToList(); // prevent multiple enumeration
HashSet<T[]> uniqueArrays = new HashSet<T[]>();
foreach (var subArray in subArrList)
{
uniqueArrays.Add(subArray.Array);
}
if (uniqueArrays.Count == 0) return new T[0];
if (uniqueArrays.Count == 1) return uniqueArrays.ToArray()[0];
var length = 0;
var offsets = new Dictionary<T[], int>();
foreach (var uniqueArray in uniqueArrays)
{
offsets[uniqueArray] = length;
length += uniqueArray.Length;
}
var array = new T[length];
foreach (var uniqueArray in uniqueArrays)
{
System.Array.ConstrainedCopy(uniqueArray, 0, array, offsets[uniqueArray], uniqueArray.Length);
}
foreach (var subArray in subArrList)
{
subArray.Offset = offsets[subArray.Array];
subArray.Array = array;
}
return array;
}
// /// <summary>
// /// Make multiple subArrays cover the same array
// /// </summary>
// /// <typeparam name="T">The element type</typeparam>
// /// <param name="subArrays">The SubArrays to join</param>
// /// <returns>The new underlying array</returns>
// public static T[] Join<T>(params SubArray<T>[] subArrays) => Join((IEnumerable<SubArray<T>>) subArrays);
//
// /// <summary>
// /// Make multiple subArrays cover the same array
// /// </summary>
// /// <typeparam name="T">The element type</typeparam>
// /// <param name="subArrays">The SubArrays to join</param>
// /// <returns>The new underlying array</returns>
// public static T[] Join<T>(IEnumerable<SubArray<T>> subArrays)
// {
// // todo: this breaks in the case: Join(a, b); Join(b, c)
// // possibly create "multiarray" class or similar which would manage these operations
// // and prevent this case from arising
//
// var subArrList = subArrays.ToList(); // prevent multiple enumeration
//
// HashSet<T[]> uniqueArrays = new HashSet<T[]>();
// foreach (var subArray in subArrList)
// {
// uniqueArrays.Add(subArray.Array);
// }
//
// if (uniqueArrays.Count == 0) return new T[0];
// if (uniqueArrays.Count == 1) return uniqueArrays.ToArray()[0];
//
// var length = 0;
// var offsets = new Dictionary<T[], int>();
// foreach (var uniqueArray in uniqueArrays)
// {
// offsets[uniqueArray] = length;
// length += uniqueArray.Length;
// }
//
// var array = new T[length];
// foreach (var uniqueArray in uniqueArrays)
// {
// System.Array.ConstrainedCopy(uniqueArray, 0, array, offsets[uniqueArray], uniqueArray.Length);
// }
//
// foreach (var subArray in subArrList)
// {
// subArray.Offset = offsets[subArray.Array];
// subArray.Array = array;
// }
//
// return array;
// }
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Diamond.Buffers;
@@ -43,10 +44,10 @@ namespace hexworld
#endregion
private SubArray<TileData> _floorTiles;
private SubArray<TileData> _doorTiles;
private VertexBuffer<TileData> _floorTiles;
private VertexBuffer<TileData> _doorTiles;
private Mesh<ObjVertex> _cubeMesh;
private VertexBuffer<ObjVertex> _cubeMesh;
private Camera _camera;
@@ -86,34 +87,29 @@ namespace hexworld
.Select(arr => new SubArray<TileData>(arr))
.ToArray();
_doorTiles = allTiles[0];
_floorTiles = allTiles[1];
var tileVbo = VertexBuffer.FromArrays(allTiles, 0, "tiles");
_doorTiles = tileVbo[0];
_floorTiles = tileVbo[1];
var cubeMesh = json["models"]
.Select(path => (string) path)
.Select(path => Path.Combine(dir, path))
.Select(path => Mesh.FromObj(path, false))
.Select(VertexBuffer.FromWavefront)
.SelectMany(meshes => meshes)
.First(mesh => mesh.Name == "Cube");
_cubeMesh = cubeMesh;
_tileBuffer = Buffer.FromData(SubArray.Join(_doorTiles, _floorTiles), BufferTarget.ArrayBuffer,
BufferUsageHint.DynamicDraw, "tile");
_meshBuffer = Buffer.FromData(cubeMesh.Vertices.ToArray(), BufferTarget.ArrayBuffer,
BufferUsageHint.StaticDraw, "mesh");
_camera = new Camera();
_renderGroup = new RenderGroup<TileData, ObjVertex>()
{
Camera = _camera,
Vertices = _cubeMesh,
VertexBuffer = _meshBuffer,
Instance = _floorTiles,
Program = _texPgm,
Texture = _grassTex,
InstanceBuffer = _tileBuffer,
Instances = _floorTiles
Vertices = _cubeMesh,
Texture = _grassTex
};
}