From 02a9a6d66256d0f4dccdce4c8b560836e4d05951 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Sun, 26 Feb 2017 18:51:21 -0500 Subject: [PATCH] Replaced VBO with Buffer and SubArray. Program now recieves Buffer, rather than VBO receiving Program. Added VertexDataAttribute for vertex structs. Split json files to test this functionality. --- Diamond/Buffers/Buffer.cs | 47 ++++++++ Diamond/Buffers/SubArray.cs | 105 ++++++++++++++++++ Diamond/Buffers/VBO.cs | 79 ------------- Diamond/Buffers/VertexDataAttribute.cs | 16 +++ Diamond/Diamond.csproj | 4 +- Diamond/Shaders/Program.cs | 41 ++++++- hexworld/Driver.cs | 15 +++ hexworld/HexRender.cs | 74 +++++++----- hexworld/{TileData.cs => Tile.cs} | 10 +- hexworld/{VertexData.cs => Vertex.cs} | 10 +- hexworld/{tiles.json => data_tile_grass.json} | 5 - hexworld/data_tile_stone.json | 7 ++ hexworld/{cube.json => data_vert_cubes.json} | 0 hexworld/data_vert_panels.json | 38 +++++++ hexworld/hexworld.csproj | 14 ++- 15 files changed, 346 insertions(+), 119 deletions(-) create mode 100644 Diamond/Buffers/Buffer.cs create mode 100644 Diamond/Buffers/SubArray.cs delete mode 100644 Diamond/Buffers/VBO.cs create mode 100644 Diamond/Buffers/VertexDataAttribute.cs rename hexworld/{TileData.cs => Tile.cs} (57%) rename hexworld/{VertexData.cs => Vertex.cs} (64%) rename hexworld/{tiles.json => data_tile_grass.json} (76%) create mode 100644 hexworld/data_tile_stone.json rename hexworld/{cube.json => data_vert_cubes.json} (100%) create mode 100644 hexworld/data_vert_panels.json diff --git a/Diamond/Buffers/Buffer.cs b/Diamond/Buffers/Buffer.cs new file mode 100644 index 0000000..b917bbf --- /dev/null +++ b/Diamond/Buffers/Buffer.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using OpenTK.Graphics.OpenGL4; + +namespace Diamond.Buffers +{ + public class Buffer : GLObject + { + public readonly BufferTarget Target; + public readonly BufferUsageHint Usage; + + public Buffer(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw) + : base((uint) GL.GenBuffer()) + { + Target = target; + Usage = usage; + } + + public void Bind() + { + GL.BindBuffer(Target, Id); + } + + protected override void Delete() + { + GL.DeleteBuffer(Id); + } + + public void Data(T[] data) where T : struct + { + var size = Marshal.SizeOf(); + Bind(); + GL.BufferData(Target, (IntPtr) (size * data.Length), data, Usage); + } + + public void SubData(SubArray data) where T : struct + { + var size = Marshal.SizeOf(); + Bind(); + GL.BufferSubData(Target, (IntPtr) (data.Offset * size), (IntPtr) (data.Length * size), data.Array); + } + } +} \ No newline at end of file diff --git a/Diamond/Buffers/SubArray.cs b/Diamond/Buffers/SubArray.cs new file mode 100644 index 0000000..9249399 --- /dev/null +++ b/Diamond/Buffers/SubArray.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing.Drawing2D; +using System.Linq; +using OpenTK.Graphics.ES20; + +namespace Diamond.Buffers +{ + public class SubArray : IEnumerable + { + public T[] Array; + public int Offset; + public int Length; + + public T this[int i] + { + get + { + if (i < 0 || i >= Length) + throw new IndexOutOfRangeException("Index out of bounds of subarray"); + return Array[i + Offset]; + } + set + { + if (i < 0 || i >= Length) + throw new IndexOutOfRangeException("Index out of bounds of subarray."); + Array[i + Offset] = value; + } + } + + public SubArray(T[] array) : this(array, 0, array.Length) + { + } + + public SubArray(T[] array, int offset, int length) + { + Array = array; + Offset = offset; + Length = length; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + for (var i = 0; i < Length; i++) + yield return Array[Offset + i]; + } + + public static T[] Join(params SubArray[] subArrays) => Join((IEnumerable>) subArrays); + + public static T[] Join(IEnumerable> subArrays) + { + HashSet uniqueArrays = new HashSet(); + foreach (var subArray in subArrays) + { + 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 subArrays) + { + subArray.Offset = offsets[subArray.Array]; + subArray.Array = array; + } + + return array; + } + + public T[] ToArray() + { + var arr = new T[Length]; + System.Array.ConstrainedCopy(Array, Offset, arr, 0, Length); + return arr; + } + + public override string ToString() + { + if (Length == 0) + return "[ ]"; + + return $"[{string.Join(", ", this)}]"; + } + } +} \ No newline at end of file diff --git a/Diamond/Buffers/VBO.cs b/Diamond/Buffers/VBO.cs deleted file mode 100644 index b89b7c9..0000000 --- a/Diamond/Buffers/VBO.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Diamond.Shaders; -using OpenTK.Graphics.OpenGL4; - -namespace Diamond.Buffers -{ - public static class VBO - { - public static void Unbind() - { - GL.BindBuffer(BufferTarget.ArrayBuffer, 0); - } - } - - public class VBO : GLObject where T : struct - { - public VBO() - : base((uint) GL.GenBuffer()) - { - } - - protected override void Delete() - { - GL.DeleteBuffer(Id); - } - - public void Bind() - { - GL.BindBuffer(BufferTarget.ArrayBuffer, Id); - } - - public void Data(T[] data, BufferUsageHint usage = BufferUsageHint.StaticDraw) - { - Bind(); - var size = Marshal.SizeOf(typeof(T)); - GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr) (size * data.Length), data, usage); - VBO.Unbind(); - } - - private static readonly int Stride; - private static readonly VertexPointerAttribute[] Attributes; - - static VBO() - { - var attribList = new List(); - Stride = Marshal.SizeOf(typeof(T)); - - foreach (var fieldInfo in typeof(T).GetFields()) - { - var attrs = fieldInfo.GetCustomAttributes(typeof(VertexPointerAttribute), false); - if (attrs.Length == 0) continue; - - var offset = (int) Marshal.OffsetOf(typeof(T), fieldInfo.Name); - foreach (var attr in attrs) - { - var vpa = (VertexPointerAttribute) attr; - vpa.Offset = offset; - attribList.Add(vpa); - } - } - - Attributes = attribList.ToArray(); - } - - public void AttribPointers(Program pgm) - { - Bind(); - foreach (var attr in Attributes) - { - if (!pgm.TryGetAttribute(attr.Name, out int loc)) continue; - GL.VertexAttribPointer(loc, attr.Size, attr.Type, attr.Normalized, Stride, attr.Offset); - GL.VertexAttribDivisor(loc, attr.Divisor); - } - VBO.Unbind(); - } - } -} \ No newline at end of file diff --git a/Diamond/Buffers/VertexDataAttribute.cs b/Diamond/Buffers/VertexDataAttribute.cs new file mode 100644 index 0000000..98cb70f --- /dev/null +++ b/Diamond/Buffers/VertexDataAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Diamond.Buffers +{ + [AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)] + public sealed class VertexDataAttribute : Attribute + { + public VertexDataAttribute() + { + } + } +} \ No newline at end of file diff --git a/Diamond/Diamond.csproj b/Diamond/Diamond.csproj index 3ba5464..f73a22d 100644 --- a/Diamond/Diamond.csproj +++ b/Diamond/Diamond.csproj @@ -44,13 +44,15 @@ + + + - diff --git a/Diamond/Shaders/Program.cs b/Diamond/Shaders/Program.cs index e575320..7a000e5 100644 --- a/Diamond/Shaders/Program.cs +++ b/Diamond/Shaders/Program.cs @@ -1,6 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; +using Diamond.Buffers; using OpenTK.Graphics.OpenGL4; +using Buffer = Diamond.Buffers.Buffer; namespace Diamond.Shaders { @@ -84,6 +88,41 @@ namespace Diamond.Shaders return id; } + public void SetAttribPointers(Buffer buff, Type vertexType) + { + if (vertexType.GetCustomAttributes(typeof(VertexDataAttribute), false).Length == 0) + { + throw new ShaderException($"Cannot attach buffer {buff} to program {this}" + + $" with vertex {vertexType} because it has no" + + $" VertexData attribute."); + } + + var attribList = new List(); + var Stride = Marshal.SizeOf(vertexType); + + foreach (var fieldInfo in vertexType.GetFields()) + { + var attrs = fieldInfo.GetCustomAttributes(typeof(VertexPointerAttribute), false); + if (attrs.Length == 0) continue; + + var offset = (int) Marshal.OffsetOf(vertexType, fieldInfo.Name); + foreach (var attr in attrs) + { + var vpa = (VertexPointerAttribute) attr; + vpa.Offset = offset; + attribList.Add(vpa); + } + } + + buff.Bind(); + foreach (var attr in attribList) + { + if (!TryGetAttribute(attr.Name, out int loc)) continue; + GL.VertexAttribPointer(loc, attr.Size, attr.Type, attr.Normalized, Stride, attr.Offset); + GL.VertexAttribDivisor(loc, attr.Divisor); + } + } + public void EnableAllAttribArrays() { foreach (var loc in attributes.Values) diff --git a/hexworld/Driver.cs b/hexworld/Driver.cs index 24e9c4a..2a0606a 100644 --- a/hexworld/Driver.cs +++ b/hexworld/Driver.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Diamond.Buffers; using Newtonsoft.Json; using OpenTK; @@ -15,6 +16,20 @@ namespace hexworld public static void Main(string[] args) { using (var gw = new HexRender(1280, 720)) gw.Run(); + +// var s1 = new SubArray(new[] {1, 3, 5, 7, 9}); +// var s2 = new SubArray(new[] {0, 2, 4, 6, 8}); +// +// Console.Out.WriteLine($"s1 = {s1}"); +// Console.Out.WriteLine($"s2 = {s2}"); +// +// var arr = SubArray.Join(s1, s2); +// +// Console.Out.WriteLine($"arr = {string.Join(", ", arr)}"); +// Console.Out.WriteLine($"s1 = {s1}"); +// Console.Out.WriteLine($"s2 = {s2}"); +// +// Console.ReadKey(); } } } \ No newline at end of file diff --git a/hexworld/HexRender.cs b/hexworld/HexRender.cs index 81ec166..20e0995 100644 --- a/hexworld/HexRender.cs +++ b/hexworld/HexRender.cs @@ -14,17 +14,12 @@ using Newtonsoft.Json; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL4; +using Buffer = Diamond.Buffers.Buffer; namespace hexworld { public class HexRender : GameWindow { - private readonly VertexData[] _cubeVerts = - JsonConvert.DeserializeObject(File.ReadAllText("cube.json")); - - private readonly TileData[] _tilesData = - JsonConvert.DeserializeObject(File.ReadAllText("tiles.json")); - private Program _pgm; private Texture _grass; @@ -33,8 +28,17 @@ namespace hexworld private Matrix4 _view; private Matrix4 _proj; - private VBO _tileVbo; - private VBO _cubeVbo; + private SubArray _grassTiles; + private SubArray _stoneTiles; + + private SubArray _cubeVertices; + private SubArray _panelVertices; + + private Tile[] _allTiles; + private Vertex[] _allVertices; + + private Buffer _tileBuffer; + private Buffer _vertexBuffer; private double _time; @@ -56,16 +60,18 @@ namespace hexworld _view = Matrix4.LookAt(10 * Vector3.One, Vector3.Zero, Vector3.UnitZ); _proj = Matrix4.CreateOrthographic(Width / 100f, Height / 100f, -100, 100); - // wavy blocks around perimeter - for (var i = 0; i < 16; i++) + for (var i = 0; i < _grassTiles.Length; i++) { - var ti = _tilesData[i]; - _tilesData[i].Position.Z = (float) (Math.Sin((_time + ti.Position.X - ti.Position.Y / 1.5) / 1.5) * .25); + var ti = _grassTiles[i]; + ti.Position.Z = (float) (Math.Sin((_time + ti.Position.X - ti.Position.Y / 1.5) / 1.5) * .25); + _grassTiles[i] = ti; } - _tileVbo.Bind(); - GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr) (0), (IntPtr) (16 * 3 * sizeof(float)), _tilesData); - VBO.Unbind(); + _tileBuffer.SubData(_grassTiles); + + _tileBuffer.Bind(); + GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr) (5 * 3 * sizeof(float)), + (IntPtr) (16 * 3 * sizeof(float)), _grassTiles.ToArray()); } protected override void OnLoad(EventArgs e) @@ -94,13 +100,27 @@ namespace hexworld } } - _cubeVbo = new VBO(); - _cubeVbo.Data(_cubeVerts, BufferUsageHint.StaticDraw); - _cubeVbo.AttribPointers(_pgm); + _cubeVertices = new SubArray( + JsonConvert.DeserializeObject(File.ReadAllText("data_vert_cubes.json"))); + _panelVertices = new SubArray( + JsonConvert.DeserializeObject(File.ReadAllText("data_vert_panels.json"))); - _tileVbo = new VBO(); - _tileVbo.Data(_tilesData, BufferUsageHint.DynamicDraw); - _tileVbo.AttribPointers(_pgm); + _grassTiles = new SubArray( + JsonConvert.DeserializeObject(File.ReadAllText("data_tile_grass.json"))); + _stoneTiles = new SubArray( + JsonConvert.DeserializeObject(File.ReadAllText("data_tile_stone.json"))); + + _allTiles = SubArray.Join(_stoneTiles, _grassTiles); + _allVertices = SubArray.Join(_panelVertices, _cubeVertices); + + _tileBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.DynamicDraw); + _tileBuffer.Data(_allTiles); + + _vertexBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw); + _vertexBuffer.Data(_allVertices); + + _pgm.SetAttribPointers(_tileBuffer, typeof(Tile)); + _pgm.SetAttribPointers(_vertexBuffer, typeof(Vertex)); _grass = Texture.FromBitmap(new Bitmap("grass.png")); _stone = Texture.FromBitmap(new Bitmap("stone.png")); @@ -112,8 +132,8 @@ namespace hexworld _pgm.Dispose(); - _tileVbo.Dispose(); - _cubeVbo.Dispose(); + _tileBuffer.Dispose(); + _vertexBuffer.Dispose(); _grass.Dispose(); _stone.Dispose(); @@ -145,13 +165,17 @@ namespace hexworld GL.UniformMatrix4(_pgm.GetUniform("view"), false, ref _view); GL.UniformMatrix4(_pgm.GetUniform("proj"), false, ref _proj); - GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, 0, 36, 16, 0); + GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, + _cubeVertices.Offset, _cubeVertices.Length, + _grassTiles.Length, _grassTiles.Offset); GL.Uniform1(_pgm.GetUniform("tex"), 1); GL.UniformMatrix4(_pgm.GetUniform("view"), false, ref _view); GL.UniformMatrix4(_pgm.GetUniform("proj"), false, ref _proj); - GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, 0, 36, 5, 16); + GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, + _panelVertices.Offset, _panelVertices.Length, + _stoneTiles.Length, _stoneTiles.Offset); _pgm.DisableAllAttribArrays(); diff --git a/hexworld/TileData.cs b/hexworld/Tile.cs similarity index 57% rename from hexworld/TileData.cs rename to hexworld/Tile.cs index 78abcd8..28cd83a 100644 --- a/hexworld/TileData.cs +++ b/hexworld/Tile.cs @@ -4,15 +4,21 @@ using OpenTK; namespace hexworld { - public struct TileData + [VertexData] + public struct Tile { [JsonProperty("pos")] [VertexPointer("glbpos", 3, Divisor = 1)] public Vector3 Position; - public TileData(Vector3 position) + public Tile(Vector3 position) { Position = position; } + + public override string ToString() + { + return $"{nameof(Position)}: {Position}"; + } } } \ No newline at end of file diff --git a/hexworld/VertexData.cs b/hexworld/Vertex.cs similarity index 64% rename from hexworld/VertexData.cs rename to hexworld/Vertex.cs index 9f869e3..d205eb6 100644 --- a/hexworld/VertexData.cs +++ b/hexworld/Vertex.cs @@ -4,7 +4,8 @@ using OpenTK; namespace hexworld { - public struct VertexData + [VertexData] + public struct Vertex { [JsonProperty("pos")] [VertexPointer("locpos", 3)] @@ -18,11 +19,16 @@ namespace hexworld [VertexPointer("norm", 3)] public Vector3 Normal; - public VertexData(Vector3 position, Vector2 uv, Vector3 normal) + public Vertex(Vector3 position, Vector2 uv, Vector3 normal) { Position = position; UV = uv; Normal = normal; } + + public override string ToString() + { + return $"{nameof(Position)}: {Position}, {nameof(UV)}: {UV}, {nameof(Normal)}: {Normal}"; + } } } \ No newline at end of file diff --git a/hexworld/tiles.json b/hexworld/data_tile_grass.json similarity index 76% rename from hexworld/tiles.json rename to hexworld/data_tile_grass.json index 207b544..ae3b19b 100644 --- a/hexworld/tiles.json +++ b/hexworld/data_tile_grass.json @@ -15,9 +15,4 @@ { "pos": { "x": 0, "y": 2, "z": 0 } }, { "pos": { "x": 1, "y": -2, "z": 0 } }, { "pos": { "x": 1, "y": 2, "z": 0 } }, - { "pos": { "x": 0, "y": 0, "z": 1 } }, - { "pos": { "x": 0, "y": 1, "z": 1 } }, - { "pos": { "x": 0, "y": -1, "z": 1 } }, - { "pos": { "x": -1, "y": 0, "z": 1 } }, - { "pos": { "x": 1, "y": 0, "z": 1 } } ] \ No newline at end of file diff --git a/hexworld/data_tile_stone.json b/hexworld/data_tile_stone.json new file mode 100644 index 0000000..254eb42 --- /dev/null +++ b/hexworld/data_tile_stone.json @@ -0,0 +1,7 @@ +[ + { "pos": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": 0, "y": 1, "z": 1 } }, + { "pos": { "x": 0, "y": -1, "z": 1 } }, + { "pos": { "x": -1, "y": 0, "z": 1 } }, + { "pos": { "x": 1, "y": 0, "z": 1 } }, +] \ No newline at end of file diff --git a/hexworld/cube.json b/hexworld/data_vert_cubes.json similarity index 100% rename from hexworld/cube.json rename to hexworld/data_vert_cubes.json diff --git a/hexworld/data_vert_panels.json b/hexworld/data_vert_panels.json new file mode 100644 index 0000000..1a724dc --- /dev/null +++ b/hexworld/data_vert_panels.json @@ -0,0 +1,38 @@ +[ + { "pos": { "x": .5, "y": .5, "z": .3 }, "uv": { "x": 1, "y": .3 }, "norm": { "x": 1, "y": 0, "z": 0 } }, + { "pos": { "x": .5, "y": .5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": 1, "y": 0, "z": 0 } }, + { "pos": { "x": .5, "y": -.5, "z": .5 }, "uv": { "x": .5, "y": .2 }, "norm": { "x": 1, "y": 0, "z": 0 } }, + { "pos": { "x": .5, "y": -.5, "z": .5 }, "uv": { "x": .5, "y": .2 }, "norm": { "x": 1, "y": 0, "z": 0 } }, + { "pos": { "x": .5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": 1, "y": 0, "z": 0 } }, + { "pos": { "x": .5, "y": .5, "z": .3 }, "uv": { "x": 1, "y": .3 }, "norm": { "x": 1, "y": 0, "z": 0 } }, + { "pos": { "x": -.5, "y": .5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": -1, "y": 0, "z": 0 } }, + { "pos": { "x": -.5, "y": .5, "z": .3 }, "uv": { "x": 1, "y": .3 }, "norm": { "x": -1, "y": 0, "z": 0 } }, + { "pos": { "x": -.5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": -1, "y": 0, "z": 0 } }, + { "pos": { "x": -.5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": -1, "y": 0, "z": 0 } }, + { "pos": { "x": -.5, "y": -.5, "z": .5 }, "uv": { "x": .5, "y": .2 }, "norm": { "x": -1, "y": 0, "z": 0 } }, + { "pos": { "x": -.5, "y": .5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": -1, "y": 0, "z": 0 } }, + { "pos": { "x": .5, "y": .5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": -.5, "y": .5, "z": .3 }, "uv": { "x": 1, "y": .3 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": -.5, "y": .5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": -.5, "y": .5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": .5, "y": .5, "z": .5 }, "uv": { "x": .5, "y": .2 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": .5, "y": .5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": .5, "y": -.5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": -.5, "y": -.5, "z": .5 }, "uv": { "x": .5, "y": .2 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": -.5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": -.5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .3 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": .5, "y": -.5, "z": .3 }, "uv": { "x": 1, "y": .3 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": .5, "y": -.5, "z": .5 }, "uv": { "x": 1, "y": .2 }, "norm": { "x": 0, "y": 1, "z": 0 } }, + { "pos": { "x": .5, "y": .5, "z": .5 }, "uv": { "x": .5, "y": 0 }, "norm": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": -.5, "y": .5, "z": .5 }, "uv": { "x": 0, "y": 0 }, "norm": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": -.5, "y": -.5, "z": .5 }, "uv": { "x": 0, "y": .5 }, "norm": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": -.5, "y": -.5, "z": .5 }, "uv": { "x": 0, "y": .5 }, "norm": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": .5, "y": -.5, "z": .5 }, "uv": { "x": .5, "y": .5 }, "norm": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": .5, "y": .5, "z": .5 }, "uv": { "x": .5, "y": .0 }, "norm": { "x": 0, "y": 0, "z": 1 } }, + { "pos": { "x": .5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .5 }, "norm": { "x": 0, "y": 0, "z": -1 } }, + { "pos": { "x": -.5, "y": -.5, "z": .3 }, "uv": { "x": 0, "y": .5 }, "norm": { "x": 0, "y": 0, "z": -1 } }, + { "pos": { "x": -.5, "y": .5, "z": .3 }, "uv": { "x": 0, "y": 0 }, "norm": { "x": 0, "y": 0, "z": -1 } }, + { "pos": { "x": -.5, "y": .5, "z": .3 }, "uv": { "x": 0, "y": 0 }, "norm": { "x": 0, "y": 0, "z": -1 } }, + { "pos": { "x": .5, "y": .5, "z": .3 }, "uv": { "x": .5, "y": 0 }, "norm": { "x": 0, "y": 0, "z": -1 } }, + { "pos": { "x": .5, "y": -.5, "z": .3 }, "uv": { "x": .5, "y": .5 }, "norm": { "x": 0, "y": 0, "z": -1 } }, +] \ No newline at end of file diff --git a/hexworld/hexworld.csproj b/hexworld/hexworld.csproj index 62595a0..77915c6 100644 --- a/hexworld/hexworld.csproj +++ b/hexworld/hexworld.csproj @@ -51,14 +51,20 @@ - - + + + + Always + + + Always + @@ -67,10 +73,10 @@ Always - + Always - + Always