Added VertexArray class. Needs more work for buffer attaching mechanism and cannot infer attrib location from attrib name.
This commit is contained in:
43
Diamond/Attributes/VertexAttribAttribute.cs
Normal file
43
Diamond/Attributes/VertexAttribAttribute.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
|
||||||
|
namespace Diamond.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Use this field as a source for vertex attribute data
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = true)]
|
||||||
|
public sealed class VertexAttribAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The attribute ID to send this value
|
||||||
|
/// </summary>
|
||||||
|
public int Attribute { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of elements for this attribute
|
||||||
|
/// </summary>
|
||||||
|
public int Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this attribute should be normalized
|
||||||
|
/// </summary>
|
||||||
|
public bool Normalized { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The eleemnt type for this attribute
|
||||||
|
/// </summary>
|
||||||
|
public VertexAttribPointerType Type { get; set; } = VertexAttribPointerType.Float;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mark a field as a source for a vertex attribute
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attribute">The attribute ID for this value</param>
|
||||||
|
/// <param name="size">The number of elements for this attribute</param>
|
||||||
|
public VertexAttribAttribute(int attribute, int size)
|
||||||
|
{
|
||||||
|
Attribute = attribute;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Diamond/Attributes/VertexDataAttribute.cs
Normal file
29
Diamond/Attributes/VertexDataAttribute.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Diamond.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Use this struct's contents as vertex attribute information
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
|
||||||
|
public sealed class VertexDataAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The VertexAttribDivisor for all attribs associated with this struct
|
||||||
|
/// </summary>
|
||||||
|
public int Divisor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mark a struct as a source for a VAO's attrib pointer information
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="divisor"></param>
|
||||||
|
public VertexDataAttribute(int divisor = 0)
|
||||||
|
{
|
||||||
|
Divisor = divisor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,8 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Attributes\VertexAttribAttribute.cs" />
|
||||||
|
<Compile Include="Attributes\VertexDataAttribute.cs" />
|
||||||
<Compile Include="Buffer.cs" />
|
<Compile Include="Buffer.cs" />
|
||||||
<Compile Include="Extensions.cs" />
|
<Compile Include="Extensions.cs" />
|
||||||
<Compile Include="GLObject.cs" />
|
<Compile Include="GLObject.cs" />
|
||||||
@@ -59,6 +61,7 @@
|
|||||||
<Compile Include="Shaders\Program.cs" />
|
<Compile Include="Shaders\Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Shaders\Shader.cs" />
|
<Compile Include="Shaders\Shader.cs" />
|
||||||
|
<Compile Include="VertexArray.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="NLog.config">
|
<Content Include="NLog.config">
|
||||||
|
|||||||
@@ -15,6 +15,11 @@
|
|||||||
fileName="${basedir}/logs/${date:format=yyyMMdd_HHmmss:cached=true}.log"
|
fileName="${basedir}/logs/${date:format=yyyMMdd_HHmmss:cached=true}.log"
|
||||||
layout="${fileHeader}: ${message}" />
|
layout="${fileHeader}: ${message}" />
|
||||||
|
|
||||||
|
<target name="traceFile"
|
||||||
|
xsi:type="File"
|
||||||
|
fileName="${basedir}/logs/${date:format=yyyMMdd_HHmmss:cached=true}.trace.log"
|
||||||
|
layout="${fileHeader}: ${message}" />
|
||||||
|
|
||||||
<target xsi:type="Debugger" name="debug" layout="${debugHeader}: ${message}"/>
|
<target xsi:type="Debugger" name="debug" layout="${debugHeader}: ${message}"/>
|
||||||
</targets>
|
</targets>
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ namespace Diamond.Shaders
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use this program. If program is null, use the default program.
|
/// Use a program.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="program">The program to use, or null to use the default program</param>
|
||||||
public static void Use(Program program)
|
public static void Use(Program program)
|
||||||
{
|
{
|
||||||
if (program != null && !program.Linked)
|
if (program != null && !program.Linked)
|
||||||
@@ -158,7 +159,7 @@ namespace Diamond.Shaders
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Use() => Use(this);
|
public void Use() => Use(this);
|
||||||
|
|
||||||
#region Attribute Locations
|
#region Locations
|
||||||
|
|
||||||
private readonly Dictionary<string, int> _attributes = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _attributes = new Dictionary<string, int>();
|
||||||
private readonly Dictionary<string, int> _uniforms = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _uniforms = new Dictionary<string, int>();
|
||||||
@@ -257,7 +258,9 @@ namespace Diamond.Shaders
|
|||||||
var program = new Program();
|
var program = new Program();
|
||||||
|
|
||||||
foreach (var shader in shaders)
|
foreach (var shader in shaders)
|
||||||
|
{
|
||||||
program.Attach(shader);
|
program.Attach(shader);
|
||||||
|
}
|
||||||
|
|
||||||
program.Link();
|
program.Link();
|
||||||
|
|
||||||
|
|||||||
155
Diamond/VertexArray.cs
Normal file
155
Diamond/VertexArray.cs
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Diamond.Attributes;
|
||||||
|
using Diamond.Shaders;
|
||||||
|
using NLog;
|
||||||
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
|
||||||
|
namespace Diamond
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wrap an OpenGL Vertex Array Object
|
||||||
|
/// </summary>
|
||||||
|
public sealed class VertexArray : GLObject
|
||||||
|
{
|
||||||
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
#region Static
|
||||||
|
|
||||||
|
private static VertexArray _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The currently bound VAO, or null if no vao is bound.
|
||||||
|
/// </summary>
|
||||||
|
public static VertexArray Current
|
||||||
|
{
|
||||||
|
get => _current;
|
||||||
|
set => Bind(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bind a VAO to the context
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vao">The vao to bind, or null to unbind the current vao</param>
|
||||||
|
public static void Bind(VertexArray vao)
|
||||||
|
{
|
||||||
|
GL.BindVertexArray(vao?.Id ?? 0);
|
||||||
|
Logger.Trace("Bound {0}", (object) vao ?? "default vao");
|
||||||
|
|
||||||
|
_current = vao;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ctor, Delete()
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
internal VertexArray()
|
||||||
|
: base(GL.GenVertexArray())
|
||||||
|
{
|
||||||
|
Logger.Debug("Created {0}", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Delete()
|
||||||
|
{
|
||||||
|
Logger.Debug("Disposing {0}", this);
|
||||||
|
GL.DeleteVertexArray(Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
#region Queries
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Stored
|
||||||
|
|
||||||
|
private Buffer _elementArrayBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ElementArrayBuffer associated with this VAO
|
||||||
|
/// </summary>
|
||||||
|
public Buffer ElementArrayBuffer
|
||||||
|
{
|
||||||
|
get => _elementArrayBuffer;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Current = this;
|
||||||
|
Buffer.ElementArrayBuffer = _elementArrayBuffer = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attach a VBO to this VAO. Use attributes to infer the
|
||||||
|
/// vertex attrib pointer information
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The struct to use for vertex attrib information. Must be marked with VertexDataAttribute</typeparam>
|
||||||
|
/// <param name="buffer">The buffer to add</param>
|
||||||
|
public void Attach<T>(Buffer<T> buffer) where T : struct
|
||||||
|
{
|
||||||
|
var vda = (VertexDataAttribute) typeof(T)
|
||||||
|
.GetCustomAttributes(typeof(VertexDataAttribute), false)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (vda == null)
|
||||||
|
{
|
||||||
|
Logger.Error("Cannot attach buffer {0} to {1}, {2} is missing VertexDataAttribute", buffer, this,
|
||||||
|
typeof(T).Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Current = this;
|
||||||
|
Buffer.ArrayBuffer = buffer;
|
||||||
|
|
||||||
|
var stride = Marshal.SizeOf<T>();
|
||||||
|
foreach (var field in typeof(T).GetFields())
|
||||||
|
{
|
||||||
|
Logger.Debug("Analyzing {0}", field.Name);
|
||||||
|
var offset = Marshal.OffsetOf<T>(field.Name);
|
||||||
|
foreach (var vai in field.GetCustomAttributes<VertexAttribAttribute>(false))
|
||||||
|
{
|
||||||
|
Logger.Debug(
|
||||||
|
$"Enabling {vai.Attribute}, {vai.Size}, {vai.Type}, {vai.Normalized}, {stride}, {offset}");
|
||||||
|
|
||||||
|
GL.EnableVertexAttribArray(vai.Attribute);
|
||||||
|
GL.VertexAttribPointer(vai.Attribute, vai.Size, vai.Type, vai.Normalized, stride, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bind this vao
|
||||||
|
/// </summary>
|
||||||
|
public void Bind() => Bind(this);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Factory Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an empty vertex array object. This contains no binding information
|
||||||
|
/// by default, and must have any vertex buffer objects attached manually.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new Vertex Array Object, or null if creation failed</returns>
|
||||||
|
public static VertexArray Create()
|
||||||
|
{
|
||||||
|
return new VertexArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,23 @@ using OpenTK;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using OpenTK.Graphics.OpenGL4;
|
using OpenTK.Graphics.OpenGL4;
|
||||||
using Diamond;
|
using Diamond;
|
||||||
|
using Diamond.Attributes;
|
||||||
using Buffer = Diamond.Buffer;
|
using Buffer = Diamond.Buffer;
|
||||||
|
|
||||||
namespace hexworld
|
namespace hexworld
|
||||||
{
|
{
|
||||||
|
[VertexData()]
|
||||||
|
public struct Vert
|
||||||
|
{
|
||||||
|
[VertexAttrib(0, 2)]
|
||||||
|
public Vector2 Position;
|
||||||
|
|
||||||
|
public Vert(float x, float y)
|
||||||
|
{
|
||||||
|
Position = new Vector2(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class HexRender : GameWindow
|
public class HexRender : GameWindow
|
||||||
{
|
{
|
||||||
public HexRender(int width, int height)
|
public HexRender(int width, int height)
|
||||||
@@ -20,12 +33,12 @@ namespace hexworld
|
|||||||
Y = (DisplayDevice.Default.Height - Height) / 2;
|
Y = (DisplayDevice.Default.Height - Height) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int _triVao;
|
private VertexArray _triVao;
|
||||||
private Buffer<float> _triVbo;
|
private Buffer<Vert> _triVbo;
|
||||||
private Program _whitePgm;
|
private Program _whitePgm;
|
||||||
|
|
||||||
private int _recVao;
|
private VertexArray _recVao;
|
||||||
private Buffer<float> _recVbo;
|
private Buffer<Vert> _recVbo;
|
||||||
private Program _redPgm;
|
private Program _redPgm;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -39,36 +52,30 @@ namespace hexworld
|
|||||||
{
|
{
|
||||||
_whitePgm = Program.FromShaders(vs, red);
|
_whitePgm = Program.FromShaders(vs, red);
|
||||||
_redPgm = Program.FromShaders(vs, white);
|
_redPgm = Program.FromShaders(vs, white);
|
||||||
|
|
||||||
_triVbo = Buffer.FromData(new float[]
|
|
||||||
{
|
|
||||||
-.8f, -.8f,
|
|
||||||
+.8f, -.8f,
|
|
||||||
+.0f, +.8f
|
|
||||||
});
|
|
||||||
_triVao = GL.GenVertexArray();
|
|
||||||
GL.BindVertexArray(_triVao);
|
|
||||||
Program.Current = _redPgm;
|
|
||||||
Buffer.ArrayBuffer = _triVbo;
|
|
||||||
GL.EnableVertexAttribArray(0);
|
|
||||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 0, 0);
|
|
||||||
|
|
||||||
_recVbo = Buffer.FromData(new float[]
|
|
||||||
{
|
|
||||||
-.9f, -.5f,
|
|
||||||
+.9f, -.5f,
|
|
||||||
+.9f, +.5f,
|
|
||||||
+.9f, +.5f,
|
|
||||||
-.9f, +.5f,
|
|
||||||
-.9f, -.5f,
|
|
||||||
});
|
|
||||||
_recVao = GL.GenVertexArray();
|
|
||||||
GL.BindVertexArray(_recVao);
|
|
||||||
Program.Current = _whitePgm;
|
|
||||||
Buffer.ArrayBuffer = _recVbo;
|
|
||||||
GL.EnableVertexAttribArray(0);
|
|
||||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_triVbo = Buffer.FromData(new[]
|
||||||
|
{
|
||||||
|
new Vert(-.8f, -.8f),
|
||||||
|
new Vert(+.8f, -.8f),
|
||||||
|
new Vert(+.0f, +.8f)
|
||||||
|
});
|
||||||
|
Program.Current = _redPgm;
|
||||||
|
_triVao = VertexArray.Create();
|
||||||
|
_triVao.Attach(_triVbo);
|
||||||
|
|
||||||
|
_recVbo = Buffer.FromData(new[]
|
||||||
|
{
|
||||||
|
new Vert(-.9f, -.5f),
|
||||||
|
new Vert(+.9f, -.5f),
|
||||||
|
new Vert(+.9f, +.5f),
|
||||||
|
new Vert(+.9f, +.5f),
|
||||||
|
new Vert(-.9f, +.5f),
|
||||||
|
new Vert(-.9f, -.5f)
|
||||||
|
});
|
||||||
|
Program.Current = _whitePgm;
|
||||||
|
_recVao = VertexArray.Create();
|
||||||
|
_recVao.Attach(_recVbo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -93,11 +100,11 @@ namespace hexworld
|
|||||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
Program.Current = _redPgm;
|
Program.Current = _redPgm;
|
||||||
GL.BindVertexArray(_triVao);
|
VertexArray.Current = _triVao;
|
||||||
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
|
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
|
||||||
|
|
||||||
Program.Current = _whitePgm;
|
Program.Current = _whitePgm;
|
||||||
GL.BindVertexArray(_recVao);
|
VertexArray.Current = _recVao;
|
||||||
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
|
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
|
||||||
|
|
||||||
SwapBuffers();
|
SwapBuffers();
|
||||||
|
|||||||
Reference in New Issue
Block a user