Skip to content

Instantly share code, notes, and snippets.

@LordNed
Created June 15, 2015 01:43
Show Gist options
  • Save LordNed/3d74e9963bde5f9cf739 to your computer and use it in GitHub Desktop.
Save LordNed/3d74e9963bde5f9cf739 to your computer and use it in GitHub Desktop.
using OpenTK;
using OpenTK.Graphics.OpenGL;
using System;
namespace WEditor.Rendering
{
public class Mesh
{
public Vector3[] Vertices
{
get { return m_vertices; }
set
{
m_vertices = value;
UpdateAttributeAndBuffers(ShaderAttributeIds.Position, m_vertices);
}
}
public Vector3[] Normals
{
get { return m_normals; }
set
{
m_normals = value;
UpdateAttributeAndBuffers(ShaderAttributeIds.Normal, m_normals);
}
}
public Color[] Color0
{
get { return m_colors0; }
set
{
m_colors0 = value;
UpdateAttributeAndBuffers(ShaderAttributeIds.Color0, m_colors0);
}
}
public Color[] Color1
{
get { return m_colors1; }
set
{
m_colors1 = value;
UpdateAttributeAndBuffers(ShaderAttributeIds.Color1, m_colors1);
}
}
public Vector2[] TexCoord0
{
get { return m_texCoord0; }
set
{
m_texCoord0 = value;
UpdateAttributeAndBuffers(ShaderAttributeIds.TexCoord0, m_texCoord0);
}
}
public Vector2[] TexCoord1
{
get { return m_texCoord1; }
set
{
m_texCoord1 = value;
UpdateAttributeAndBuffers(ShaderAttributeIds.TexCoord1, m_texCoord1);
}
}
public int[] Indexes
{
get { return m_indexes; }
set
{
m_indexes = value;
GL.BindBuffer(BufferTarget.ElementArrayBuffer, m_elementArrayBuffer);
GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(m_indexes.Length * 4), m_indexes, BufferUsageHint.StaticDraw);
}
}
/// <summary> Indicates which vertex attributes are enabled on this mesh. </summary>
private VertexDescription m_vertexDescription;
/// <summary> Separate GL Buffers for each attribute. </summary>
private int[] m_attributeBuffers;
private int m_elementArrayBuffer;
/// <summary> Position Vertices. </summary>
private Vector3[] m_vertices;
private Vector3[] m_normals;
private Color[] m_colors0;
private Color[] m_colors1;
private Vector2[] m_texCoord0;
private Vector2[] m_texCoord1;
private int[] m_indexes;
private int m_maxBufferCount;
public Mesh()
{
m_vertexDescription = new VertexDescription();
m_maxBufferCount = Enum.GetValues(typeof(ShaderAttributeIds)).Length;
m_attributeBuffers = new int[m_maxBufferCount];
m_vertices = new Vector3[0];
m_normals = new Vector3[0];
m_colors0 = new Color[0];
m_colors1 = new Color[0];
m_texCoord0 = new Vector2[0];
m_texCoord1 = new Vector2[0];
// Generate our element array buffer
GL.GenBuffers(1, out m_elementArrayBuffer);
}
public void Bind()
{
for (int i = 0; i < m_maxBufferCount; i++)
{
ShaderAttributeIds attribute = (ShaderAttributeIds)i;
if(m_vertexDescription.AttributeIsEnabled(attribute))
{
GL.BindBuffer(BufferTarget.ArrayBuffer, m_attributeBuffers[(int)attribute]);
GL.EnableVertexAttribArray((int)attribute);
GL.VertexAttribPointer((int)attribute, m_vertexDescription.GetAttributeSize(attribute), m_vertexDescription.GetAttributePointerType(attribute), false, m_vertexDescription.GetStride(attribute), 0);
}
}
// Then Bind our Element Array Buffer so we can actually draw.
GL.BindBuffer(BufferTarget.ElementArrayBuffer, m_elementArrayBuffer);
}
public void Unbind()
{
for (int i = 0; i < m_maxBufferCount; i++)
{
GL.DisableVertexAttribArray(i);
}
}
private void UpdateAttributeAndBuffers<T>(ShaderAttributeIds attribute, T[] data) where T : struct
{
// See if this attribute is already enabled. If it's not already enabled, we need to generate a buffer for it.
if (!m_vertexDescription.AttributeIsEnabled(attribute))
{
GL.GenBuffers(1, out m_attributeBuffers[(int)attribute]);
m_vertexDescription.EnableAttribute(attribute);
}
// Bind the buffer before updating the data.
GL.BindBuffer(BufferTarget.ArrayBuffer, m_attributeBuffers[(int)attribute]);
// Finally, update the data.
int stride = m_vertexDescription.GetStride(attribute);
GL.BufferData<T>(BufferTarget.ArrayBuffer, (IntPtr)(data.Length * stride), data, BufferUsageHint.StaticDraw);
}
}
}
internal void RenderFrame()
{
// Solid Fill the Back Buffer, until I can figure out what's going on with resizing
// windows and partial camera viewport rects.
GL.ClearColor(0f, 0f, 0f, 1f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Enable(EnableCap.ScissorTest);
GL.Enable(EnableCap.DepthTest);
for (int i = 0; i < m_cameraList.Count; i++)
{
/* SETUP THE VIEWPORT FOR THE CAMERA */
Camera camera = m_cameraList[i];
Rect pixelRect = camera.PixelRect;
GL.Viewport((int)pixelRect.X, (int)pixelRect.Y, (int)pixelRect.Width, (int)pixelRect.Height);
GL.Scissor((int)pixelRect.X, (int)pixelRect.Y, (int)pixelRect.Width, (int)pixelRect.Height);
// Clear the backbuffer
Color clearColor = camera.ClearColor;
GL.ClearColor(clearColor.R, clearColor.G, clearColor.B, clearColor.A);
GL.Clear(ClearBufferMask.ColorBufferBit|ClearBufferMask.DepthBufferBit);
Matrix4 viewProjMatrix = camera.ViewMatrix * camera.ProjectionMatrix;
for (int m = 0; m < m_meshList.Count; m++)
{
Mesh mesh = m_meshList[m];
// Bind the Shader
GL.UseProgram(m_shader.ProgramId);
Matrix4 modelMatrix = Matrix4.Identity; //Identity = doesn't change anything when multiplied.
Matrix4 finalMatrix = modelMatrix * viewProjMatrix;
// Bind the VAOs currently associated with this Mesh
mesh.Bind();
// Upload the MVP to the GPU
GL.UniformMatrix4(m_shader.UniformMVP, false, ref finalMatrix);
// Draw our Mesh.
GL.DrawElements(PrimitiveType.Triangles, mesh.Indexes.Length, DrawElementsType.UnsignedInt, 0);
// Unbind the VAOs so that our VAO doesn't leak into the next drawcall.
mesh.Unbind();
}
}
GL.Disable(EnableCap.ScissorTest);
GL.Disable(EnableCap.DepthTest);
// Flush OpenGL.
GL.Flush();
}
using System;
using OpenTK.Graphics.OpenGL;
using System.Collections.Generic;
namespace WEditor.Rendering
{
public class VertexDescription
{
private List<ShaderAttributeIds> m_enabledAttributes;
public VertexDescription()
{
m_enabledAttributes = new List<ShaderAttributeIds>();
}
internal bool AttributeIsEnabled(ShaderAttributeIds attribute)
{
return m_enabledAttributes.Contains(attribute);
}
internal int GetAttributeSize(ShaderAttributeIds attribute)
{
switch (attribute)
{
case ShaderAttributeIds.Position:
case ShaderAttributeIds.Normal:
return 3;
case ShaderAttributeIds.Color0:
case ShaderAttributeIds.Color1:
return 4;
case ShaderAttributeIds.TexCoord0:
case ShaderAttributeIds.TexCoord1:
return 2;
default:
return 0;
}
}
internal VertexAttribPointerType GetAttributePointerType(ShaderAttributeIds attribute)
{
switch (attribute)
{
case ShaderAttributeIds.Position:
case ShaderAttributeIds.Normal:
case ShaderAttributeIds.Color0:
case ShaderAttributeIds.Color1:
case ShaderAttributeIds.TexCoord0:
case ShaderAttributeIds.TexCoord1:
return VertexAttribPointerType.Float;
default:
Console.WriteLine("[VertexDescription] Unsupported ShaderAttributeId: " + attribute);
return VertexAttribPointerType.Float;
}
}
internal int GetStride(ShaderAttributeIds attribute)
{
switch (attribute)
{
case ShaderAttributeIds.Position:
case ShaderAttributeIds.Normal:
return 4 * 3;
case ShaderAttributeIds.Color0:
case ShaderAttributeIds.Color1:
return 4 * 4;
case ShaderAttributeIds.TexCoord0:
case ShaderAttributeIds.TexCoord1:
return 4 * 2;
default:
Console.WriteLine("[VertexDescription] Unsupported ShaderAttributeId: " + attribute);
return 0;
}
}
internal void EnableAttribute(ShaderAttributeIds attribute)
{
m_enabledAttributes.Add(attribute);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment