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.
This commit is contained in:
2017-02-26 18:51:21 -05:00
parent 7500e0e7a4
commit 02a9a6d662
15 changed files with 346 additions and 119 deletions

47
Diamond/Buffers/Buffer.cs Normal file
View File

@@ -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>(T[] data) where T : struct
{
var size = Marshal.SizeOf<T>();
Bind();
GL.BufferData(Target, (IntPtr) (size * data.Length), data, Usage);
}
public void SubData<T>(SubArray<T> data) where T : struct
{
var size = Marshal.SizeOf<T>();
Bind();
GL.BufferSubData(Target, (IntPtr) (data.Offset * size), (IntPtr) (data.Length * size), data.Array);
}
}
}

105
Diamond/Buffers/SubArray.cs Normal file
View File

@@ -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<T> : IEnumerable<T>
{
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<T> GetEnumerator()
{
for (var i = 0; i < Length; i++)
yield return Array[Offset + i];
}
public static T[] Join<T>(params SubArray<T>[] subArrays) => Join((IEnumerable<SubArray<T>>) subArrays);
public static T[] Join<T>(IEnumerable<SubArray<T>> subArrays)
{
HashSet<T[]> uniqueArrays = new HashSet<T[]>();
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<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 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)}]";
}
}
}

View File

@@ -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<T> : 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<VertexPointerAttribute>();
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();
}
}
}

View File

@@ -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()
{
}
}
}

View File

@@ -44,13 +44,15 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Buffers\Buffer.cs" />
<Compile Include="Buffers\SubArray.cs" />
<Compile Include="Buffers\VertexDataAttribute.cs" />
<Compile Include="GLObject.cs" />
<Compile Include="Shaders\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shaders\Shader.cs" />
<Compile Include="Shaders\ShaderException.cs" />
<Compile Include="Textures\Texture.cs" />
<Compile Include="Buffers\VBO.cs" />
<Compile Include="Buffers\VertexPointerAttribute.cs" />
</ItemGroup>
<ItemGroup>

View File

@@ -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<VertexPointerAttribute>();
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)

View File

@@ -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<int>(new[] {1, 3, 5, 7, 9});
// var s2 = new SubArray<int>(new[] {0, 2, 4, 6, 8});
//
// Console.Out.WriteLine($"s1 = {s1}");
// Console.Out.WriteLine($"s2 = {s2}");
//
// var arr = SubArray<int>.Join(s1, s2);
//
// Console.Out.WriteLine($"arr = {string.Join(", ", arr)}");
// Console.Out.WriteLine($"s1 = {s1}");
// Console.Out.WriteLine($"s2 = {s2}");
//
// Console.ReadKey();
}
}
}

View File

@@ -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<VertexData[]>(File.ReadAllText("cube.json"));
private readonly TileData[] _tilesData =
JsonConvert.DeserializeObject<TileData[]>(File.ReadAllText("tiles.json"));
private Program _pgm;
private Texture _grass;
@@ -33,8 +28,17 @@ namespace hexworld
private Matrix4 _view;
private Matrix4 _proj;
private VBO<TileData> _tileVbo;
private VBO<VertexData> _cubeVbo;
private SubArray<Tile> _grassTiles;
private SubArray<Tile> _stoneTiles;
private SubArray<Vertex> _cubeVertices;
private SubArray<Vertex> _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<VertexData>();
_cubeVbo.Data(_cubeVerts, BufferUsageHint.StaticDraw);
_cubeVbo.AttribPointers(_pgm);
_cubeVertices = new SubArray<Vertex>(
JsonConvert.DeserializeObject<Vertex[]>(File.ReadAllText("data_vert_cubes.json")));
_panelVertices = new SubArray<Vertex>(
JsonConvert.DeserializeObject<Vertex[]>(File.ReadAllText("data_vert_panels.json")));
_tileVbo = new VBO<TileData>();
_tileVbo.Data(_tilesData, BufferUsageHint.DynamicDraw);
_tileVbo.AttribPointers(_pgm);
_grassTiles = new SubArray<Tile>(
JsonConvert.DeserializeObject<Tile[]>(File.ReadAllText("data_tile_grass.json")));
_stoneTiles = new SubArray<Tile>(
JsonConvert.DeserializeObject<Tile[]>(File.ReadAllText("data_tile_stone.json")));
_allTiles = SubArray<Tile>.Join(_stoneTiles, _grassTiles);
_allVertices = SubArray<Vertex>.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();

View File

@@ -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}";
}
}
}

View File

@@ -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}";
}
}
}

View File

@@ -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 } }
]

View File

@@ -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 } },
]

View File

@@ -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 } },
]

View File

@@ -51,14 +51,20 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="TileData.cs" />
<Compile Include="VertexData.cs" />
<Compile Include="Tile.cs" />
<Compile Include="Vertex.cs" />
<Compile Include="HexRender.cs" />
<Compile Include="Driver.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="data_tile_stone.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="data_vert_panels.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="OpenTK.dll.config" />
<None Include="packages.config" />
<None Include="s.fs.glsl">
@@ -67,10 +73,10 @@
<None Include="s.vs.glsl">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="cube.json">
<None Include="data_vert_cubes.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="tiles.json">
<None Include="data_tile_grass.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>