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; internal readonly BufferWrap Wrapper;
private readonly VertexDataInfo _vdi; private readonly VertexDataInfo _vdi;
private readonly int _size; protected readonly int Size;
/// <summary> /// <summary>
/// The target for this buffer; its type /// The target for this buffer; its type
@@ -38,7 +38,7 @@ namespace Diamond.Buffers
{ {
Wrapper = wrapper; Wrapper = wrapper;
Name = name; Name = name;
_size = Marshal.SizeOf<T>(); Size = Marshal.SizeOf<T>();
_vdi = VertexDataInfo.GetInfo<T>(); _vdi = VertexDataInfo.GetInfo<T>();
} }
@@ -46,7 +46,7 @@ namespace Diamond.Buffers
/// Upload data to this buffer /// Upload data to this buffer
/// </summary> /// </summary>
/// <param name="data">The data to upload</param> /// <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> /// <summary>
/// Upload a range of data to this buffer /// Upload a range of data to this buffer
@@ -54,7 +54,7 @@ namespace Diamond.Buffers
/// <param name="offset">The range offset</param> /// <param name="offset">The range offset</param>
/// <param name="count">The range length</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> /// <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> /// <summary>
/// Upload a range of data to this buffer /// Upload a range of data to this buffer

View File

@@ -64,7 +64,7 @@
<Compile Include="Buffers\VertexDataAttribute.cs" /> <Compile Include="Buffers\VertexDataAttribute.cs" />
<Compile Include="Wrappers\Wrapper.cs" /> <Compile Include="Wrappers\Wrapper.cs" />
<Compile Include="Util\TileData.cs" /> <Compile Include="Util\TileData.cs" />
<Compile Include="Util\Mesh.cs" /> <Compile Include="Render\VertexBuffer.cs" />
<Compile Include="Util\ObjVertex.cs" /> <Compile Include="Util\ObjVertex.cs" />
<Compile Include="Shaders\Program.cs" /> <Compile Include="Shaders\Program.cs" />
<Compile Include="Properties\AssemblyInfo.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> /// <typeparam name="TVertex">The type of data to use as Vertex information</typeparam>
public class RenderGroup<TInstance, TVertex> where TInstance : struct where TVertex : struct 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> /// <summary>
/// The range of vertex values to render /// The range of vertex values to render
/// </summary> /// </summary>
public Mesh<TVertex> Vertices; public VertexBuffer<TVertex> Vertices;
/// <summary> /// <summary>
/// The buffer to use for instance data /// The range of instance values to render
/// </summary> /// </summary>
public Buffer<TInstance> InstanceBuffer; public VertexBuffer<TInstance> Instance;
/// <summary>
/// The buffer to use for instance data
/// </summary>
public Buffer<TVertex> VertexBuffer;
/// <summary> /// <summary>
/// The program to use to render this Rendergroup /// The program to use to render this Rendergroup
@@ -53,9 +45,6 @@ namespace Diamond.Render
{ {
Program.Use(); Program.Use();
InstanceBuffer.PointTo(Program);
VertexBuffer.PointTo(Program);
Texture.Bind(0); Texture.Bind(0);
var texLoc = Program.UniformLocation("tex"); var texLoc = Program.UniformLocation("tex");
@@ -69,7 +58,10 @@ namespace Diamond.Render
if (projLoc.HasValue) if (projLoc.HasValue)
GL.UniformMatrix4(projLoc.Value, false, ref Camera.Projection); 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> /// </summary>
public static class SubArray public static class SubArray
{ {
/// <summary> // /// <summary>
/// Make multiple subArrays cover the same array // /// Make multiple subArrays cover the same array
/// </summary> // /// </summary>
/// <typeparam name="T">The element type</typeparam> // /// <typeparam name="T">The element type</typeparam>
/// <param name="subArrays">The SubArrays to join</param> // /// <param name="subArrays">The SubArrays to join</param>
/// <returns>The new underlying array</returns> // /// <returns>The new underlying array</returns>
public static T[] Join<T>(params SubArray<T>[] subArrays) => Join((IEnumerable<SubArray<T>>) subArrays); // public static T[] Join<T>(params SubArray<T>[] subArrays) => Join((IEnumerable<SubArray<T>>) subArrays);
//
/// <summary> // /// <summary>
/// Make multiple subArrays cover the same array // /// Make multiple subArrays cover the same array
/// </summary> // /// </summary>
/// <typeparam name="T">The element type</typeparam> // /// <typeparam name="T">The element type</typeparam>
/// <param name="subArrays">The SubArrays to join</param> // /// <param name="subArrays">The SubArrays to join</param>
/// <returns>The new underlying array</returns> // /// <returns>The new underlying array</returns>
public static T[] Join<T>(IEnumerable<SubArray<T>> subArrays) // public static T[] Join<T>(IEnumerable<SubArray<T>> subArrays)
{ // {
// todo: this breaks in the case: Join(a, b); Join(b, c) // // todo: this breaks in the case: Join(a, b); Join(b, c)
// possibly create "multiarray" class or similar which would manage these operations // // possibly create "multiarray" class or similar which would manage these operations
// and prevent this case from arising // // and prevent this case from arising
//
var subArrList = subArrays.ToList(); // prevent multiple enumeration // var subArrList = subArrays.ToList(); // prevent multiple enumeration
//
HashSet<T[]> uniqueArrays = new HashSet<T[]>(); // HashSet<T[]> uniqueArrays = new HashSet<T[]>();
foreach (var subArray in subArrList) // foreach (var subArray in subArrList)
{ // {
uniqueArrays.Add(subArray.Array); // uniqueArrays.Add(subArray.Array);
} // }
//
if (uniqueArrays.Count == 0) return new T[0]; // if (uniqueArrays.Count == 0) return new T[0];
if (uniqueArrays.Count == 1) return uniqueArrays.ToArray()[0]; // if (uniqueArrays.Count == 1) return uniqueArrays.ToArray()[0];
//
var length = 0; // var length = 0;
var offsets = new Dictionary<T[], int>(); // var offsets = new Dictionary<T[], int>();
foreach (var uniqueArray in uniqueArrays) // foreach (var uniqueArray in uniqueArrays)
{ // {
offsets[uniqueArray] = length; // offsets[uniqueArray] = length;
length += uniqueArray.Length; // length += uniqueArray.Length;
} // }
//
var array = new T[length]; // var array = new T[length];
foreach (var uniqueArray in uniqueArrays) // foreach (var uniqueArray in uniqueArrays)
{ // {
System.Array.ConstrainedCopy(uniqueArray, 0, array, offsets[uniqueArray], uniqueArray.Length); // System.Array.ConstrainedCopy(uniqueArray, 0, array, offsets[uniqueArray], uniqueArray.Length);
} // }
//
foreach (var subArray in subArrList) // foreach (var subArray in subArrList)
{ // {
subArray.Offset = offsets[subArray.Array]; // subArray.Offset = offsets[subArray.Array];
subArray.Array = array; // subArray.Array = array;
} // }
//
return array; // return array;
} // }
} }
} }

View File

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