Added VertexArray class. Needs more work for buffer attaching mechanism and cannot infer attrib location from attrib name.

This commit is contained in:
2017-03-11 21:08:02 -05:00
parent 2b48366c0a
commit 17d7c75df5
7 changed files with 282 additions and 37 deletions

View 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;
}
}
}

View 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;
}
}
}

View File

@@ -52,6 +52,8 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Attributes\VertexAttribAttribute.cs" />
<Compile Include="Attributes\VertexDataAttribute.cs" />
<Compile Include="Buffer.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="GLObject.cs" />
@@ -59,6 +61,7 @@
<Compile Include="Shaders\Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Shaders\Shader.cs" />
<Compile Include="VertexArray.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="NLog.config">

View File

@@ -15,6 +15,11 @@
fileName="${basedir}/logs/${date:format=yyyMMdd_HHmmss:cached=true}.log"
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}"/>
</targets>

View File

@@ -28,8 +28,9 @@ namespace Diamond.Shaders
}
/// <summary>
/// Use this program. If program is null, use the default program.
/// Use a program.
/// </summary>
/// <param name="program">The program to use, or null to use the default program</param>
public static void Use(Program program)
{
if (program != null && !program.Linked)
@@ -158,7 +159,7 @@ namespace Diamond.Shaders
/// </summary>
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> _uniforms = new Dictionary<string, int>();
@@ -257,7 +258,9 @@ namespace Diamond.Shaders
var program = new Program();
foreach (var shader in shaders)
{
program.Attach(shader);
}
program.Link();

155
Diamond/VertexArray.cs Normal file
View 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
}
}

View File

@@ -5,10 +5,23 @@ using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL4;
using Diamond;
using Diamond.Attributes;
using Buffer = Diamond.Buffer;
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 HexRender(int width, int height)
@@ -20,12 +33,12 @@ namespace hexworld
Y = (DisplayDevice.Default.Height - Height) / 2;
}
private int _triVao;
private Buffer<float> _triVbo;
private VertexArray _triVao;
private Buffer<Vert> _triVbo;
private Program _whitePgm;
private int _recVao;
private Buffer<float> _recVbo;
private VertexArray _recVao;
private Buffer<Vert> _recVbo;
private Program _redPgm;
/// <inheritdoc />
@@ -39,36 +52,30 @@ namespace hexworld
{
_whitePgm = Program.FromShaders(vs, red);
_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 />
@@ -93,11 +100,11 @@ namespace hexworld
GL.Clear(ClearBufferMask.ColorBufferBit);
Program.Current = _redPgm;
GL.BindVertexArray(_triVao);
VertexArray.Current = _triVao;
GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
Program.Current = _whitePgm;
GL.BindVertexArray(_recVao);
VertexArray.Current = _recVao;
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
SwapBuffers();