282 lines
8.9 KiB
C#
282 lines
8.9 KiB
C#
|
using OpenTK.Graphics.OpenGL;
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
namespace Gal.OpenGL
|
||
|
{
|
||
|
public class OpenGLRenderer : IGalRenderer
|
||
|
{
|
||
|
private struct VertexBuffer
|
||
|
{
|
||
|
public int VaoHandle;
|
||
|
public int VboHandle;
|
||
|
|
||
|
public int PrimCount;
|
||
|
}
|
||
|
|
||
|
private struct Texture
|
||
|
{
|
||
|
public int Handle;
|
||
|
}
|
||
|
|
||
|
private List<VertexBuffer> VertexBuffers;
|
||
|
|
||
|
private Texture[] Textures;
|
||
|
|
||
|
private Queue<Action> ActionsQueue;
|
||
|
|
||
|
public long FrameBufferPtr { get; set; }
|
||
|
|
||
|
public OpenGLRenderer()
|
||
|
{
|
||
|
VertexBuffers = new List<VertexBuffer>();
|
||
|
|
||
|
Textures = new Texture[8];
|
||
|
|
||
|
ActionsQueue = new Queue<Action>();
|
||
|
}
|
||
|
|
||
|
public void QueueAction(Action ActionMthd)
|
||
|
{
|
||
|
ActionsQueue.Enqueue(ActionMthd);
|
||
|
}
|
||
|
|
||
|
public void RunActions()
|
||
|
{
|
||
|
while (ActionsQueue.Count > 0)
|
||
|
{
|
||
|
ActionsQueue.Dequeue()();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Render()
|
||
|
{
|
||
|
for (int Index = 0; Index < VertexBuffers.Count; Index++)
|
||
|
{
|
||
|
VertexBuffer Vb = VertexBuffers[Index];
|
||
|
|
||
|
if (Vb.VaoHandle != 0 &&
|
||
|
Vb.PrimCount != 0)
|
||
|
{
|
||
|
GL.BindVertexArray(Vb.VaoHandle);
|
||
|
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
|
||
|
{
|
||
|
if (Index < 0)
|
||
|
{
|
||
|
throw new ArgumentOutOfRangeException(nameof(Index));
|
||
|
}
|
||
|
|
||
|
if (Buffer.Length == 0 || Stride == 0)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
EnsureVbInitialized(Index);
|
||
|
|
||
|
VertexBuffer Vb = VertexBuffers[Index];
|
||
|
|
||
|
Vb.PrimCount = Buffer.Length / Stride;
|
||
|
|
||
|
VertexBuffers[Index] = Vb;
|
||
|
|
||
|
IntPtr Length = new IntPtr(Buffer.Length);
|
||
|
|
||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||
|
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||
|
|
||
|
GL.BindVertexArray(Vb.VaoHandle);
|
||
|
|
||
|
for (int Attr = 0; Attr < 16; Attr++)
|
||
|
{
|
||
|
GL.DisableVertexAttribArray(Attr);
|
||
|
}
|
||
|
|
||
|
foreach (GalVertexAttrib Attrib in Attribs)
|
||
|
{
|
||
|
if (Attrib.Index >= 3) break;
|
||
|
|
||
|
GL.EnableVertexAttribArray(Attrib.Index);
|
||
|
|
||
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
|
||
|
|
||
|
int Size = 0;
|
||
|
|
||
|
switch (Attrib.Size)
|
||
|
{
|
||
|
case GalVertexAttribSize._8:
|
||
|
case GalVertexAttribSize._16:
|
||
|
case GalVertexAttribSize._32:
|
||
|
Size = 1;
|
||
|
break;
|
||
|
case GalVertexAttribSize._8_8:
|
||
|
case GalVertexAttribSize._16_16:
|
||
|
case GalVertexAttribSize._32_32:
|
||
|
Size = 2;
|
||
|
break;
|
||
|
case GalVertexAttribSize._8_8_8:
|
||
|
case GalVertexAttribSize._11_11_10:
|
||
|
case GalVertexAttribSize._16_16_16:
|
||
|
case GalVertexAttribSize._32_32_32:
|
||
|
Size = 3;
|
||
|
break;
|
||
|
case GalVertexAttribSize._8_8_8_8:
|
||
|
case GalVertexAttribSize._10_10_10_2:
|
||
|
case GalVertexAttribSize._16_16_16_16:
|
||
|
case GalVertexAttribSize._32_32_32_32:
|
||
|
Size = 4;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
bool Signed =
|
||
|
Attrib.Type == GalVertexAttribType.Snorm ||
|
||
|
Attrib.Type == GalVertexAttribType.Sint ||
|
||
|
Attrib.Type == GalVertexAttribType.Sscaled;
|
||
|
|
||
|
bool Normalize =
|
||
|
Attrib.Type == GalVertexAttribType.Snorm ||
|
||
|
Attrib.Type == GalVertexAttribType.Unorm;
|
||
|
|
||
|
VertexAttribPointerType Type = 0;
|
||
|
|
||
|
switch (Attrib.Type)
|
||
|
{
|
||
|
case GalVertexAttribType.Snorm:
|
||
|
case GalVertexAttribType.Unorm:
|
||
|
case GalVertexAttribType.Sint:
|
||
|
case GalVertexAttribType.Uint:
|
||
|
case GalVertexAttribType.Uscaled:
|
||
|
case GalVertexAttribType.Sscaled:
|
||
|
{
|
||
|
switch (Attrib.Size)
|
||
|
{
|
||
|
case GalVertexAttribSize._8:
|
||
|
case GalVertexAttribSize._8_8:
|
||
|
case GalVertexAttribSize._8_8_8:
|
||
|
case GalVertexAttribSize._8_8_8_8:
|
||
|
{
|
||
|
Type = Signed
|
||
|
? VertexAttribPointerType.Byte
|
||
|
: VertexAttribPointerType.UnsignedByte;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case GalVertexAttribSize._16:
|
||
|
case GalVertexAttribSize._16_16:
|
||
|
case GalVertexAttribSize._16_16_16:
|
||
|
case GalVertexAttribSize._16_16_16_16:
|
||
|
{
|
||
|
Type = Signed
|
||
|
? VertexAttribPointerType.Short
|
||
|
: VertexAttribPointerType.UnsignedShort;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case GalVertexAttribSize._10_10_10_2:
|
||
|
case GalVertexAttribSize._11_11_10:
|
||
|
case GalVertexAttribSize._32:
|
||
|
case GalVertexAttribSize._32_32:
|
||
|
case GalVertexAttribSize._32_32_32:
|
||
|
case GalVertexAttribSize._32_32_32_32:
|
||
|
{
|
||
|
Type = Signed
|
||
|
? VertexAttribPointerType.Int
|
||
|
: VertexAttribPointerType.UnsignedInt;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case GalVertexAttribType.Float:
|
||
|
{
|
||
|
Type = VertexAttribPointerType.Float;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GL.VertexAttribPointer(
|
||
|
Attrib.Index,
|
||
|
Size,
|
||
|
Type,
|
||
|
Normalize,
|
||
|
Stride,
|
||
|
Attrib.Offset);
|
||
|
}
|
||
|
|
||
|
GL.BindVertexArray(0);
|
||
|
}
|
||
|
|
||
|
public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height)
|
||
|
{
|
||
|
EnsureTexInitialized(Index);
|
||
|
|
||
|
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
|
||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
|
||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||
|
GL.TexImage2D(TextureTarget.Texture2D,
|
||
|
0,
|
||
|
PixelInternalFormat.Rgba,
|
||
|
Width,
|
||
|
Height,
|
||
|
0,
|
||
|
PixelFormat.Rgba,
|
||
|
PixelType.UnsignedByte,
|
||
|
Buffer);
|
||
|
}
|
||
|
|
||
|
public void BindTexture(int Index)
|
||
|
{
|
||
|
GL.ActiveTexture(TextureUnit.Texture0 + Index);
|
||
|
|
||
|
GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
|
||
|
}
|
||
|
|
||
|
private void EnsureVbInitialized(int VbIndex)
|
||
|
{
|
||
|
while (VbIndex >= VertexBuffers.Count)
|
||
|
{
|
||
|
VertexBuffers.Add(new VertexBuffer());
|
||
|
}
|
||
|
|
||
|
VertexBuffer Vb = VertexBuffers[VbIndex];
|
||
|
|
||
|
if (Vb.VaoHandle == 0)
|
||
|
{
|
||
|
Vb.VaoHandle = GL.GenVertexArray();
|
||
|
}
|
||
|
|
||
|
if (Vb.VboHandle == 0)
|
||
|
{
|
||
|
Vb.VboHandle = GL.GenBuffer();
|
||
|
}
|
||
|
|
||
|
VertexBuffers[VbIndex] = Vb;
|
||
|
}
|
||
|
|
||
|
private void EnsureTexInitialized(int TexIndex)
|
||
|
{
|
||
|
Texture Tex = Textures[TexIndex];
|
||
|
|
||
|
if (Tex.Handle == 0)
|
||
|
{
|
||
|
Tex.Handle = GL.GenTexture();
|
||
|
}
|
||
|
|
||
|
Textures[TexIndex] = Tex;
|
||
|
}
|
||
|
}
|
||
|
}
|