Fewer array copies in FromWavefront, use multiple rendergroups in hexrender

This commit is contained in:
2017-03-03 01:53:20 -05:00
parent 3e3b033de6
commit 5a3561a635
3 changed files with 106 additions and 156 deletions

View File

@@ -107,96 +107,93 @@ namespace Diamond.Render
public static VertexBuffer<ObjVertex>[] FromWavefront(string file)
{
var lines = File.ReadAllLines(file);
var lines = File.ReadAllLines(file).Where(l => !l.StartsWith("#")).Select(l => l.Split(' ')).ToArray();
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)
// get all positional data
var vs = lines
.Where(items => items[0] == "v") // only "v" lines
.Select(items => new Vector3( // get a vector3 from the values
float.Parse(items[1]),
float.Parse(items[2]),
float.Parse(items[3])))
.ToArray();
// get all uv data
var vts = lines
.Where(items => items[0] == "vt") // only "vt" lines
.Select(items => new Vector2( // get a vector2 from the values
float.Parse(items[1]),
1 - float.Parse(items[2]))) // flip along y
.ToArray();
// get all normal data
var vns = lines
.Where(items => items[0] == "vn") // only "vn" lines
.Select(items => new Vector3( // get a vector3 from the values
float.Parse(items[1]),
float.Parse(items[2]),
float.Parse(items[3])))
.ToArray();
// get all vertex data
var vertices = lines
.Where(items => items[0] == "f") // only "f" liens
.Select(items => items.Skip(1)) // skip the "f" item
.Select(items => items // get each vertex from the triangle
.Select(inds => inds.Split('/'))) // split items into indices
.SelectMany(inds => inds) // collapse nested index array into array of indexes
.Select(inds => new ObjVertex( // get vertexdata from the value data at each index
inds[0] == "" ? Vector3.Zero : vs[int.Parse(inds[0]) - 1],
inds[1] == "" ? Vector2.Zero : vts[int.Parse(inds[1]) - 1],
inds[2] == "" ? Vector3.Zero : vns[int.Parse(inds[2]) - 1]))
.ToArray();
buffer.Data(vertices); // upload vertex data to the buffer
var offset = 0; // offset of each vertexbuffer
var count = 0; // length of each vertexbuffer
foreach (var items in lines.Where(items => items[0] == "o" || items[0] == "f"))
{
if (line.StartsWith("#")) continue;
var items = line.Split(' ');
switch (items[0])
if (items[0] != "f")
{
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 (count > 0)
{
vertBuffers.Add(new VertexBuffer<ObjVertex>(
buffer,
new SubArray<ObjVertex>(vertices, offset, count),
PrimitiveType.Triangles,
name));
}
// reset for next vbo and move offset to the end of this one
name = items[1];
offset += count;
count = 0;
}
else
{
count += items.Length - 1; // size of current vbo increases by that many vertices
}
}
if (faces.Count > 0)
// at the last vbo, or only vbo.
if (count > 0)
{
var count = vertices.Count;
vertices.AddRange(faces);
vertBuffers.Add(new VertexBuffer<ObjVertex>(
buffer, new SubArray<ObjVertex>(vertices.ToArray(), count, faces.Count),
buffer,
new SubArray<ObjVertex>(vertices, offset, 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

@@ -117,64 +117,4 @@ namespace Diamond.Util
#endregion
}
/// <summary>
/// Class for static SubArray operations
/// </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;
// }
}
}

View File

@@ -19,17 +19,16 @@ namespace hexworld
{
#region Fields
#region GLObjects
#region Disposables
private Program _texPgm;
private Texture _doorTex;
private Texture _grassTex;
private Texture _stoneTex;
private Buffer<ObjVertex> _meshBuffer;
private Buffer<TileData> _tileBuffer;
private RenderGroup<TileData, ObjVertex> _renderGroup;
private Dictionary<string, VertexBuffer<ObjVertex>> _meshVbos;
private VertexBuffer<TileData>[] _tileVbos;
protected override void OnClosed(EventArgs e)
{
@@ -37,17 +36,19 @@ namespace hexworld
_doorTex?.Dispose();
_grassTex?.Dispose();
_stoneTex?.Dispose();
_meshBuffer?.Dispose();
_tileBuffer?.Dispose();
foreach (var vbo in _meshVbos.Values)
vbo?.Dispose();
foreach (var vbo in _tileVbos)
vbo?.Dispose();
}
#endregion
private VertexBuffer<TileData> _floorTiles;
private VertexBuffer<TileData> _doorTiles;
private VertexBuffer<ObjVertex> _cubeMesh;
private List<RenderGroup<TileData, ObjVertex>> _renderGroups;
// private RenderGroup<TileData, ObjVertex> _renderGroup;
private Camera _camera;
@@ -72,6 +73,7 @@ namespace hexworld
_doorTex = Texture.FromFile("res/door.png");
_grassTex = Texture.FromFile("res/grass.png");
_stoneTex = Texture.FromFile("res/stone.png");
var dir = "res";
@@ -87,30 +89,38 @@ namespace hexworld
.Select(arr => new SubArray<TileData>(arr))
.ToArray();
var tileVbo = VertexBuffer.FromArrays(allTiles, 0, "tiles");
_tileVbos = VertexBuffer.FromArrays(allTiles, 0, "tiles");
_doorTiles = tileVbo[0];
_floorTiles = tileVbo[1];
var cubeMesh = json["models"]
var vertexBuffers = json["models"]
.Select(path => (string) path)
.Select(path => Path.Combine(dir, path))
.Select(VertexBuffer.FromWavefront)
.SelectMany(meshes => meshes)
.First(mesh => mesh.Name == "Cube");
.ToArray();
_cubeMesh = cubeMesh;
_meshVbos = vertexBuffers.ToDictionary(vbo => vbo.Name, vbo => vbo);
_camera = new Camera();
_renderGroup = new RenderGroup<TileData, ObjVertex>()
_renderGroups = new List<RenderGroup<TileData, ObjVertex>>();
_renderGroups.Add(new RenderGroup<TileData, ObjVertex>()
{
Camera = _camera,
Instance = _floorTiles,
Vertices = _meshVbos["Cube"],
Instance = _tileVbos[0],
Program = _texPgm,
Vertices = _cubeMesh,
Texture = _grassTex
};
Texture = _stoneTex,
Camera = _camera,
});
_renderGroups.Add(new RenderGroup<TileData, ObjVertex>()
{
Vertices = _meshVbos["Cube"],
Instance = _tileVbos[1],
Program = _texPgm,
Texture = _grassTex,
Camera = _camera,
});
}
protected override void OnUpdateFrame(FrameEventArgs e)
@@ -138,7 +148,10 @@ namespace hexworld
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
_renderGroup.Draw();
foreach (var renderGroup in _renderGroups)
{
renderGroup.Draw();
}
SwapBuffers();
}