From 5a3561a6359ac6904602a1d99662dbb47e835f71 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Fri, 3 Mar 2017 01:53:20 -0500 Subject: [PATCH] Fewer array copies in FromWavefront, use multiple rendergroups in hexrender --- Diamond/Render/VertexBuffer.cs | 139 ++++++++++++++++----------------- Diamond/Util/SubArray.cs | 60 -------------- hexworld/HexRender.cs | 63 +++++++++------ 3 files changed, 106 insertions(+), 156 deletions(-) diff --git a/Diamond/Render/VertexBuffer.cs b/Diamond/Render/VertexBuffer.cs index cc072d6..c32bea4 100644 --- a/Diamond/Render/VertexBuffer.cs +++ b/Diamond/Render/VertexBuffer.cs @@ -107,96 +107,93 @@ namespace Diamond.Render public static VertexBuffer[] 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.Empty(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw, $"{file} buffer"); - var vs = new List(); - var vts = new List(); - var vns = new List(); - var faces = new List(); - var vertices = new List(); - var name = file; var vertBuffers = new List>(); - 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( - buffer, - new SubArray(vertices.ToArray(), count, faces.Count), - PrimitiveType.Triangles, - name)); - } - name = items[1]; - faces.Clear(); - break; - default: - break; + if (count > 0) + { + vertBuffers.Add(new VertexBuffer( + buffer, + new SubArray(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( - buffer, new SubArray(vertices.ToArray(), count, faces.Count), + buffer, + new SubArray(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(); } } diff --git a/Diamond/Util/SubArray.cs b/Diamond/Util/SubArray.cs index dd10975..066a3a9 100644 --- a/Diamond/Util/SubArray.cs +++ b/Diamond/Util/SubArray.cs @@ -117,64 +117,4 @@ namespace Diamond.Util #endregion } - - /// - /// Class for static SubArray operations - /// - public static class SubArray - { -// /// -// /// Make multiple subArrays cover the same array -// /// -// /// The element type -// /// The SubArrays to join -// /// The new underlying array -// public static T[] Join(params SubArray[] subArrays) => Join((IEnumerable>) subArrays); -// -// /// -// /// Make multiple subArrays cover the same array -// /// -// /// The element type -// /// The SubArrays to join -// /// The new underlying array -// public static T[] Join(IEnumerable> 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 uniqueArrays = new HashSet(); -// 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(); -// 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; -// } - } } \ No newline at end of file diff --git a/hexworld/HexRender.cs b/hexworld/HexRender.cs index 02fe5d1..9e6e3b7 100644 --- a/hexworld/HexRender.cs +++ b/hexworld/HexRender.cs @@ -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 _meshBuffer; - private Buffer _tileBuffer; - - private RenderGroup _renderGroup; + private Dictionary> _meshVbos; + private VertexBuffer[] _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 _floorTiles; - private VertexBuffer _doorTiles; - - private VertexBuffer _cubeMesh; + private List> _renderGroups; +// private RenderGroup _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(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() + _renderGroups = new List>(); + + _renderGroups.Add(new RenderGroup() { - Camera = _camera, - Instance = _floorTiles, + Vertices = _meshVbos["Cube"], + Instance = _tileVbos[0], Program = _texPgm, - Vertices = _cubeMesh, - Texture = _grassTex - }; + Texture = _stoneTex, + Camera = _camera, + }); + + _renderGroups.Add(new RenderGroup() + { + 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(); }