Remove legacy renderers.

This commit is contained in:
Paul Chote
2014-05-02 18:47:49 +12:00
parent 189f23e442
commit 03c3c3ae9b
37 changed files with 188 additions and 2675 deletions

View File

@@ -0,0 +1,62 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Diagnostics;
using Tao.OpenGl;
namespace OpenRA.Renderer.Sdl2
{
public static class ErrorHandler
{
public enum GlError
{
GL_NO_ERROR = Gl.GL_NO_ERROR,
GL_INVALID_ENUM = Gl.GL_INVALID_ENUM,
GL_INVALID_VALUE = Gl.GL_INVALID_VALUE,
GL_STACK_OVERFLOW = Gl.GL_STACK_OVERFLOW,
GL_STACK_UNDERFLOW = Gl.GL_STACK_UNDERFLOW,
GL_OUT_OF_MEMORY = Gl.GL_OUT_OF_MEMORY,
GL_TABLE_TOO_LARGE = Gl.GL_TABLE_TOO_LARGE,
GL_INVALID_OPERATION = Gl.GL_INVALID_OPERATION,
// Framebuffer errors
GL_FRAMEBUFFER_COMPLETE_EXT = Gl.GL_FRAMEBUFFER_COMPLETE_EXT,
GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT = Gl.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT,
GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT = Gl.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT,
GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT = Gl.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT,
GL_FRAMEBUFFER_UNSUPPORTED_EXT = Gl.GL_FRAMEBUFFER_UNSUPPORTED_EXT,
}
public static void CheckGlError()
{
var n = Gl.glGetError();
if (n != Gl.GL_NO_ERROR)
{
var error = "GL Error: {0}\n{1}".F((GlError)n, new StackTrace());
WriteGraphicsLog(error);
throw new InvalidOperationException("OpenGL Error: See graphics.log for details.");
}
}
public static void WriteGraphicsLog(string message)
{
Log.Write("graphics", message);
Log.Write("graphics", "");
Log.Write("graphics", "OpenGL Information:");
Log.Write("graphics", "Vendor: {0}", Gl.glGetString(Gl.GL_VENDOR));
Log.Write("graphics", "Renderer: {0}", Gl.glGetString(Gl.GL_RENDERER));
Log.Write("graphics", "GL Version: {0}", Gl.glGetString(Gl.GL_VERSION));
Log.Write("graphics", "Shader Version: {0}", Gl.glGetString(Gl.GL_SHADING_LANGUAGE_VERSION));
Log.Write("graphics", "Available extensions:");
Log.Write("graphics", Gl.glGetString(Gl.GL_EXTENSIONS));
}
}
}

View File

@@ -0,0 +1,126 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using OpenRA.Graphics;
using Tao.OpenGl;
namespace OpenRA.Renderer.Sdl2
{
public class FrameBuffer : IFrameBuffer
{
Texture texture;
Size size;
int framebuffer, depth;
public FrameBuffer(Size size)
{
this.size = size;
if (!Exts.IsPowerOf2(size.Width) || !Exts.IsPowerOf2(size.Height))
throw new InvalidDataException("Frame buffer size ({0}x{1}) must be a power of two".F(size.Width, size.Height));
Gl.glGenFramebuffersEXT(1, out framebuffer);
ErrorHandler.CheckGlError();
Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, framebuffer);
ErrorHandler.CheckGlError();
// Color
texture = new Texture();
texture.SetEmpty(size.Width, size.Height);
Gl.glFramebufferTexture2DEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT, Gl.GL_TEXTURE_2D, texture.ID, 0);
ErrorHandler.CheckGlError();
// Depth
Gl.glGenRenderbuffersEXT(1, out depth);
ErrorHandler.CheckGlError();
Gl.glBindRenderbufferEXT(Gl.GL_RENDERBUFFER_EXT, depth);
ErrorHandler.CheckGlError();
Gl.glRenderbufferStorageEXT(Gl.GL_RENDERBUFFER_EXT, Gl.GL_DEPTH_COMPONENT, size.Width, size.Height);
ErrorHandler.CheckGlError();
Gl.glFramebufferRenderbufferEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_DEPTH_ATTACHMENT_EXT, Gl.GL_RENDERBUFFER_EXT, depth);
ErrorHandler.CheckGlError();
// Test for completeness
var status = Gl.glCheckFramebufferStatusEXT(Gl.GL_FRAMEBUFFER_EXT);
if (status != Gl.GL_FRAMEBUFFER_COMPLETE_EXT)
{
var error = "Error creating framebuffer: {0}\n{1}".F((ErrorHandler.GlError)status, new StackTrace());
ErrorHandler.WriteGraphicsLog(error);
throw new InvalidOperationException("OpenGL Error: See graphics.log for details.");
}
// Restore default buffer
Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, 0);
ErrorHandler.CheckGlError();
}
static int[] ViewportRectangle()
{
var v = new int[4];
unsafe
{
fixed (int* ptr = &v[0])
{
IntPtr intPtr = new IntPtr((void*)ptr);
Gl.glGetIntegerv(Gl.GL_VIEWPORT, intPtr);
}
}
ErrorHandler.CheckGlError();
return v;
}
void FinalizeInner()
{
Gl.glDeleteFramebuffersEXT(1, ref framebuffer);
ErrorHandler.CheckGlError();
Gl.glDeleteRenderbuffersEXT(1, ref depth);
ErrorHandler.CheckGlError();
}
~FrameBuffer() { Game.RunAfterTick(FinalizeInner); }
int[] cv = new int[4];
public void Bind()
{
// Cache viewport rect to restore when unbinding
cv = ViewportRectangle();
Gl.glFlush();
ErrorHandler.CheckGlError();
Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, framebuffer);
ErrorHandler.CheckGlError();
Gl.glViewport(0, 0, size.Width, size.Height);
ErrorHandler.CheckGlError();
Gl.glClearColor(0, 0, 0, 0);
ErrorHandler.CheckGlError();
Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
ErrorHandler.CheckGlError();
}
public void Unbind()
{
Gl.glFlush();
ErrorHandler.CheckGlError();
Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, 0);
ErrorHandler.CheckGlError();
Gl.glViewport(cv[0], cv[1], cv[2], cv[3]);
ErrorHandler.CheckGlError();
}
public ITexture Texture { get { return texture; } }
}
}

View File

@@ -0,0 +1,84 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using OpenRA;
using OpenRA.Primitives;
namespace OpenRA.Renderer.Sdl2
{
public static class MultiTapDetection
{
static Cache<Keycode, TapHistory> keyHistoryCache =
new Cache<Keycode, TapHistory>(_ => new TapHistory(DateTime.Now - TimeSpan.FromSeconds(1)));
static Cache<byte, TapHistory> clickHistoryCache =
new Cache<byte, TapHistory>(_ => new TapHistory(DateTime.Now - TimeSpan.FromSeconds(1)));
public static int DetectFromMouse(byte button, int2 xy)
{
return clickHistoryCache[button].GetTapCount(xy);
}
public static int InfoFromMouse(byte button)
{
return clickHistoryCache[button].LastTapCount();
}
public static int DetectFromKeyboard(Keycode key)
{
return keyHistoryCache[key].GetTapCount(int2.Zero);
}
public static int InfoFromKeyboard(Keycode key)
{
return keyHistoryCache[key].LastTapCount();
}
}
class TapHistory
{
public Pair<DateTime, int2> FirstRelease, SecondRelease, ThirdRelease;
public TapHistory(DateTime now)
{
FirstRelease = SecondRelease = ThirdRelease = Pair.New(now, int2.Zero);
}
static bool CloseEnough(Pair<DateTime, int2> a, Pair<DateTime, int2> b)
{
return a.First - b.First < TimeSpan.FromMilliseconds(250)
&& (a.Second - b.Second).Length < 4;
}
public int GetTapCount(int2 xy)
{
FirstRelease = SecondRelease;
SecondRelease = ThirdRelease;
ThirdRelease = Pair.New(DateTime.Now, xy);
if (!CloseEnough(ThirdRelease, SecondRelease))
return 1;
if (!CloseEnough(SecondRelease, FirstRelease))
return 2;
return 3;
}
public int LastTapCount()
{
if (!CloseEnough(ThirdRelease, SecondRelease))
return 1;
if (!CloseEnough(SecondRelease, FirstRelease))
return 2;
return 3;
}
}
}

View File

@@ -44,6 +44,12 @@
<ItemGroup>
<Compile Include="Sdl2Input.cs" />
<Compile Include="Sdl2GraphicsDevice.cs" />
<Compile Include="Shader.cs" />
<Compile Include="ErrorHandler.cs" />
<Compile Include="FrameBuffer.cs" />
<Compile Include="MultiTapDetection.cs" />
<Compile Include="Texture.cs" />
<Compile Include="VertexBuffer.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@@ -51,13 +57,5 @@
<Project>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</Project>
<Name>OpenRA.Game</Name>
</ProjectReference>
<ProjectReference Include="..\OpenRA.Renderer.SdlCommon\OpenRA.Renderer.SdlCommon.csproj">
<Project>{52FD9F0B-B209-4ED7-8A32-AC8033363263}</Project>
<Name>OpenRA.Renderer.SdlCommon</Name>
</ProjectReference>
<ProjectReference Include="..\OpenRA.Renderer.Gl\OpenRA.Renderer.Gl.csproj">
<Project>{E9C01A96-C3E2-4772-825B-A740AC513D31}</Project>
<Name>OpenRA.Renderer.Gl</Name>
</ProjectReference>
</ItemGroup>
</Project>

View File

@@ -13,8 +13,6 @@ using System.Drawing;
using System.Linq;
using OpenRA;
using OpenRA.Graphics;
using OpenRA.Renderer.Glsl;
using OpenRA.Renderer.SdlCommon;
using SDL2;
using Tao.OpenGl;

View File

@@ -9,7 +9,6 @@
#endregion
using System.Text;
using OpenRA.Renderer.SdlCommon;
using SDL2;
namespace OpenRA.Renderer.Sdl2
@@ -117,7 +116,7 @@ namespace OpenRA.Renderer.Sdl2
case SDL.SDL_EventType.SDL_MOUSEWHEEL:
{
// Retain compatibility with existing bogus behavior
// TODO: Implement real scroll behavior after we drop SDL 1.2 support
// TODO: Implement real scroll behavior. We've dropped SDL 1.2 support!
if (e.wheel.y == 0)
break;

View File

@@ -0,0 +1,186 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using Tao.OpenGl;
namespace OpenRA.Renderer.Sdl2
{
public class Shader : IShader
{
readonly Dictionary<string, int> samplers = new Dictionary<string, int>();
readonly Dictionary<int, ITexture> textures = new Dictionary<int, ITexture>();
int program;
public Shader(string name)
{
// Vertex shader
string vertexCode;
using (var file = new StreamReader(GlobalFileSystem.Open("glsl{0}{1}.vert".F(Path.DirectorySeparatorChar, name))))
vertexCode = file.ReadToEnd();
var v = Gl.glCreateShaderObjectARB(Gl.GL_VERTEX_SHADER_ARB);
ErrorHandler.CheckGlError();
Gl.glShaderSourceARB(v, 1, new string[] { vertexCode }, null);
ErrorHandler.CheckGlError();
Gl.glCompileShaderARB(v);
ErrorHandler.CheckGlError();
int success;
Gl.glGetObjectParameterivARB(v, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out success);
ErrorHandler.CheckGlError();
if (success == 0)
throw new InvalidProgramException("Compile error in {0}{1}.vert".F(Path.DirectorySeparatorChar, name));
// Fragment shader
string fragmentCode;
using (var file = new StreamReader(GlobalFileSystem.Open("glsl{0}{1}.frag".F(Path.DirectorySeparatorChar, name))))
fragmentCode = file.ReadToEnd();
var f = Gl.glCreateShaderObjectARB(Gl.GL_FRAGMENT_SHADER_ARB);
ErrorHandler.CheckGlError();
Gl.glShaderSourceARB(f, 1, new string[] { fragmentCode }, null);
ErrorHandler.CheckGlError();
Gl.glCompileShaderARB(f);
ErrorHandler.CheckGlError();
Gl.glGetObjectParameterivARB(f, Gl.GL_OBJECT_COMPILE_STATUS_ARB, out success);
ErrorHandler.CheckGlError();
if (success == 0)
throw new InvalidProgramException("Compile error in glsl{0}{1}.frag".F(Path.DirectorySeparatorChar, name));
// Assemble program
program = Gl.glCreateProgramObjectARB();
ErrorHandler.CheckGlError();
Gl.glAttachObjectARB(program, v);
ErrorHandler.CheckGlError();
Gl.glAttachObjectARB(program, f);
ErrorHandler.CheckGlError();
Gl.glLinkProgramARB(program);
ErrorHandler.CheckGlError();
Gl.glGetObjectParameterivARB(program, Gl.GL_OBJECT_LINK_STATUS_ARB, out success);
ErrorHandler.CheckGlError();
if (success == 0)
throw new InvalidProgramException("Linking error in {0} shader".F(name));
Gl.glUseProgramObjectARB(program);
ErrorHandler.CheckGlError();
int numUniforms;
Gl.glGetObjectParameterivARB(program, Gl.GL_ACTIVE_UNIFORMS, out numUniforms);
ErrorHandler.CheckGlError();
int nextTexUnit = 0;
for (var i = 0; i < numUniforms; i++)
{
int length, size, type;
var sb = new StringBuilder(128);
Gl.glGetActiveUniformARB(program, i, 128, out length, out size, out type, sb);
var sampler = sb.ToString();
ErrorHandler.CheckGlError();
if (type == Gl.GL_SAMPLER_2D_ARB)
{
samplers.Add(sampler, nextTexUnit);
var loc = Gl.glGetUniformLocationARB(program, sampler);
ErrorHandler.CheckGlError();
Gl.glUniform1iARB(loc, nextTexUnit);
ErrorHandler.CheckGlError();
nextTexUnit++;
}
}
}
public void Render(Action a)
{
Gl.glUseProgramObjectARB(program);
// bind the textures
foreach (var kv in textures)
{
Gl.glActiveTextureARB(Gl.GL_TEXTURE0_ARB + kv.Key);
Gl.glBindTexture(Gl.GL_TEXTURE_2D, ((Texture)kv.Value).ID);
}
ErrorHandler.CheckGlError();
a();
ErrorHandler.CheckGlError();
}
public void SetTexture(string name, ITexture t)
{
if (t == null)
return;
int texUnit;
if (samplers.TryGetValue(name, out texUnit))
textures[texUnit] = t;
}
public void SetVec(string name, float x)
{
Gl.glUseProgramObjectARB(program);
ErrorHandler.CheckGlError();
var param = Gl.glGetUniformLocationARB(program, name);
ErrorHandler.CheckGlError();
Gl.glUniform1fARB(param, x);
ErrorHandler.CheckGlError();
}
public void SetVec(string name, float x, float y)
{
Gl.glUseProgramObjectARB(program);
ErrorHandler.CheckGlError();
var param = Gl.glGetUniformLocationARB(program, name);
ErrorHandler.CheckGlError();
Gl.glUniform2fARB(param, x, y);
ErrorHandler.CheckGlError();
}
public void SetVec(string name, float[] vec, int length)
{
var param = Gl.glGetUniformLocationARB(program, name);
ErrorHandler.CheckGlError();
switch (length)
{
case 1: Gl.glUniform1fv(param, 1, vec); break;
case 2: Gl.glUniform2fv(param, 1, vec); break;
case 3: Gl.glUniform3fv(param, 1, vec); break;
case 4: Gl.glUniform4fv(param, 1, vec); break;
default: throw new InvalidDataException("Invalid vector length");
}
ErrorHandler.CheckGlError();
}
public void SetMatrix(string name, float[] mtx)
{
if (mtx.Length != 16)
throw new InvalidDataException("Invalid 4x4 matrix");
Gl.glUseProgramObjectARB(program);
ErrorHandler.CheckGlError();
var param = Gl.glGetUniformLocationARB(program, name);
ErrorHandler.CheckGlError();
Gl.glUniformMatrix4fv(param, 1, Gl.GL_FALSE, mtx);
ErrorHandler.CheckGlError();
}
}
}

View File

@@ -0,0 +1,154 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using OpenRA.Graphics;
using Tao.OpenGl;
namespace OpenRA.Renderer.Sdl2
{
public class Texture : ITexture
{
int texture;
public int ID { get { return texture; } }
Size size;
public Size Size { get { return size; } }
public Texture()
{
Gl.glGenTextures(1, out texture);
ErrorHandler.CheckGlError();
}
public Texture(Bitmap bitmap)
{
Gl.glGenTextures(1, out texture);
ErrorHandler.CheckGlError();
SetData(bitmap);
}
void FinalizeInner() { Gl.glDeleteTextures(1, ref texture); }
~Texture() { Game.RunAfterTick(FinalizeInner); }
void PrepareTexture()
{
ErrorHandler.CheckGlError();
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);
ErrorHandler.CheckGlError();
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
ErrorHandler.CheckGlError();
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
ErrorHandler.CheckGlError();
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE);
ErrorHandler.CheckGlError();
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE);
ErrorHandler.CheckGlError();
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_BASE_LEVEL, 0);
ErrorHandler.CheckGlError();
Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_LEVEL, 0);
ErrorHandler.CheckGlError();
}
public void SetData(byte[] colors, int width, int height)
{
if (!Exts.IsPowerOf2(width) || !Exts.IsPowerOf2(height))
throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height));
size = new Size(width, height);
unsafe
{
fixed (byte* ptr = &colors[0])
{
IntPtr intPtr = new IntPtr((void*)ptr);
PrepareTexture();
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height,
0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr);
ErrorHandler.CheckGlError();
}
}
}
// An array of RGBA
public void SetData(uint[,] colors)
{
int width = colors.GetUpperBound(1) + 1;
int height = colors.GetUpperBound(0) + 1;
if (!Exts.IsPowerOf2(width) || !Exts.IsPowerOf2(height))
throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height));
size = new Size(width, height);
unsafe
{
fixed (uint* ptr = &colors[0, 0])
{
IntPtr intPtr = new IntPtr((void*)ptr);
PrepareTexture();
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height,
0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr);
ErrorHandler.CheckGlError();
}
}
}
public void SetData(Bitmap bitmap)
{
if (!Exts.IsPowerOf2(bitmap.Width) || !Exts.IsPowerOf2(bitmap.Height))
bitmap = new Bitmap(bitmap, bitmap.Size.NextPowerOf2());
size = new Size(bitmap.Width, bitmap.Height);
var bits = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
PrepareTexture();
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, bits.Width, bits.Height,
0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, bits.Scan0); // todo: weird strides
ErrorHandler.CheckGlError();
bitmap.UnlockBits(bits);
}
public byte[] GetData()
{
var data = new byte[4 * size.Width * size.Height];
ErrorHandler.CheckGlError();
Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);
unsafe
{
fixed (byte* ptr = &data[0])
{
IntPtr intPtr = new IntPtr((void*)ptr);
Gl.glGetTexImage(Gl.GL_TEXTURE_2D, 0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, intPtr);
}
}
ErrorHandler.CheckGlError();
return data;
}
public void SetEmpty(int width, int height)
{
if (!Exts.IsPowerOf2(width) || !Exts.IsPowerOf2(height))
throw new InvalidDataException("Non-power-of-two array {0}x{1}".F(width, height));
size = new Size(width, height);
PrepareTexture();
Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, width, height,
0, Gl.GL_BGRA, Gl.GL_UNSIGNED_BYTE, null);
ErrorHandler.CheckGlError();
}
}
}

View File

@@ -0,0 +1,59 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Runtime.InteropServices;
using OpenRA.Graphics;
using Tao.OpenGl;
namespace OpenRA.Renderer.Sdl2
{
public class VertexBuffer<T> : IVertexBuffer<T>
where T : struct
{
static readonly int VertexSize = Marshal.SizeOf(typeof(T));
int buffer;
public VertexBuffer(int size)
{
Gl.glGenBuffersARB(1, out buffer);
ErrorHandler.CheckGlError();
Bind();
Gl.glBufferDataARB(Gl.GL_ARRAY_BUFFER_ARB,
new IntPtr(VertexSize * size),
new T[size],
Gl.GL_DYNAMIC_DRAW_ARB);
ErrorHandler.CheckGlError();
}
public void SetData(T[] data, int length)
{
Bind();
Gl.glBufferSubDataARB(Gl.GL_ARRAY_BUFFER_ARB,
IntPtr.Zero,
new IntPtr(VertexSize * length),
data);
ErrorHandler.CheckGlError();
}
public void Bind()
{
Gl.glBindBufferARB(Gl.GL_ARRAY_BUFFER_ARB, buffer);
ErrorHandler.CheckGlError();
Gl.glVertexPointer(3, Gl.GL_FLOAT, VertexSize, IntPtr.Zero);
ErrorHandler.CheckGlError();
Gl.glTexCoordPointer(4, Gl.GL_FLOAT, VertexSize, new IntPtr(12));
ErrorHandler.CheckGlError();
}
void FinalizeInner() { Gl.glDeleteBuffersARB(1, ref buffer); }
~VertexBuffer() { Game.RunAfterTick(FinalizeInner); }
}
}