diff --git a/hexworld/HexRender.cs b/hexworld/HexRender.cs index faa9103..cf54394 100644 --- a/hexworld/HexRender.cs +++ b/hexworld/HexRender.cs @@ -15,19 +15,19 @@ namespace hexworld { public partial class HexRender : GameWindow { - private Program pgm; + private Program _pgm; // todo: generate texture atlas // or at least embed sub-uvs and materials into json - private Texture grass; + private Texture _grass; - private Texture stone; + private Texture _stone; - private Matrix4 view; - private Matrix4 proj; + private Matrix4 _view; + private Matrix4 _proj; - private VBO tileVbo; - private VBO cubeVbo; + private VBO _tileVbo; + private VBO _cubeVbo; public HexRender(int width, int height) : base(width, height, new GraphicsMode(32, 24, 0, 0)) @@ -38,23 +38,23 @@ namespace hexworld Y = (DisplayDevice.Default.Height - Height) / 2; } - private double t; + private double _t; protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); - t += e.Time; + _t += e.Time; - view = Matrix4.LookAt(10 * Vector3.One, Vector3.Zero, Vector3.UnitZ); - proj = Matrix4.CreateOrthographic(Width / 100f, Height / 100f, -100, 100); + _view = Matrix4.LookAt(10 * Vector3.One, Vector3.Zero, Vector3.UnitZ); + _proj = Matrix4.CreateOrthographic(Width / 100f, Height / 100f, -100, 100); for (var i = 0; i < 16; i++) { var ti = tiles[i]; - tiles[i].Position.Z = (float) (Math.Sin((t + ti.Position.X - ti.Position.Y / 1.5) / 1.5) * .25); + tiles[i].Position.Z = (float) (Math.Sin((_t + ti.Position.X - ti.Position.Y / 1.5) / 1.5) * .25); } - tileVbo.Bind(); + _tileVbo.Bind(); GL.BufferSubData(BufferTarget.ArrayBuffer, (IntPtr) (0), (IntPtr) (16 * 3 * sizeof(float)), tiles); VBO.Unbind(); } @@ -63,44 +63,59 @@ namespace hexworld { base.OnLoad(e); - cubeVbo = new VBO(); - cubeVbo.Data(cubeVerts, BufferUsageHint.StaticDraw); + _cubeVbo = new VBO(); + _cubeVbo.Data(cubeVerts, BufferUsageHint.StaticDraw); - tileVbo = new VBO(); - tileVbo.Data(tiles, BufferUsageHint.DynamicDraw); + _tileVbo = new VBO(); + _tileVbo.Data(tiles, BufferUsageHint.DynamicDraw); - var vs = Shader.FromFile("s.vs.glsl", ShaderType.VertexShader); - var fs = Shader.FromFile("s.fs.glsl", ShaderType.FragmentShader); - pgm = Program.FromShaders(vs, fs); - - if (!vs.Compiled | !fs.Compiled) + using (var vs = Shader.FromFile("s.vs.glsl", ShaderType.VertexShader)) + using (var fs = Shader.FromFile("s.fs.glsl", ShaderType.FragmentShader)) { - Console.Out.WriteLine("Failed to compile shaders:"); - if (!vs.Compiled) - Console.Out.WriteLine("Vertex Shader:\n" + vs.Log.Trim()); - if (!fs.Compiled) - Console.Out.WriteLine("Fragment Shader:\n" + fs.Log.Trim()); - Console.Out.WriteLine("Press any key to exit."); - Console.ReadKey(); - Exit(); - return; + _pgm = Program.FromShaders(vs, fs); + + if (!vs.Compiled | !fs.Compiled) + { + Console.Out.WriteLine("Failed to compile shaders:"); + if (!vs.Compiled) + Console.Out.WriteLine("Vertex Shader:\n" + vs.Log.Trim()); + if (!fs.Compiled) + Console.Out.WriteLine("Fragment Shader:\n" + fs.Log.Trim()); + Console.Out.WriteLine("Press any key to exit."); + Console.ReadKey(); + Exit(); + return; + } } - if (!pgm.LinkStatus) + if (!_pgm.LinkStatus) { Console.Out.WriteLine("Failed to link program:"); - Console.Out.WriteLine(pgm.Log.Trim()); + Console.Out.WriteLine(_pgm.Log.Trim()); Console.Out.WriteLine("Press any key to exit."); Console.ReadKey(); Exit(); return; } - cubeVbo.AttribPointers(pgm); - tileVbo.AttribPointers(pgm); + _cubeVbo.AttribPointers(_pgm); + _tileVbo.AttribPointers(_pgm); - grass = Texture.FromBitmap(new Bitmap("grass.png")); - stone = Texture.FromBitmap(new Bitmap("stone.png")); + _grass = Texture.FromBitmap(new Bitmap("grass.png")); + _stone = Texture.FromBitmap(new Bitmap("stone.png")); + } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + + _pgm.Dispose(); + + _grass.Dispose(); + _stone.Dispose(); + + _tileVbo.Dispose(); + _cubeVbo.Dispose(); } protected override void OnRenderFrame(FrameEventArgs e) @@ -119,25 +134,25 @@ namespace hexworld GL.Enable(EnableCap.CullFace); GL.CullFace(CullFaceMode.Back); - pgm.Use(); - pgm.EnableAllAttribArrays(); + _pgm.Use(); + _pgm.EnableAllAttribArrays(); - grass.Bind(0); - stone.Bind(1); + _grass.Bind(0); + _stone.Bind(1); - GL.Uniform1(pgm.GetUniform("tex"), 0); - GL.UniformMatrix4(pgm.GetUniform("view"), false, ref view); - GL.UniformMatrix4(pgm.GetUniform("proj"), false, ref proj); + GL.Uniform1(_pgm.GetUniform("tex"), 0); + GL.UniformMatrix4(_pgm.GetUniform("view"), false, ref _view); + GL.UniformMatrix4(_pgm.GetUniform("proj"), false, ref _proj); GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, 0, 36, 16, 0); - GL.Uniform1(pgm.GetUniform("tex"), 1); - GL.UniformMatrix4(pgm.GetUniform("view"), false, ref view); - GL.UniformMatrix4(pgm.GetUniform("proj"), false, ref proj); + GL.Uniform1(_pgm.GetUniform("tex"), 1); + GL.UniformMatrix4(_pgm.GetUniform("view"), false, ref _view); + GL.UniformMatrix4(_pgm.GetUniform("proj"), false, ref _proj); GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, 0, 36, 5, 16); - pgm.DisableAllAttribArrays(); + _pgm.DisableAllAttribArrays(); SwapBuffers(); } diff --git a/hexworld/Util/GLObject.cs b/hexworld/Util/GLObject.cs index 5710727..dff5769 100644 --- a/hexworld/Util/GLObject.cs +++ b/hexworld/Util/GLObject.cs @@ -7,7 +7,7 @@ using OpenTK.Graphics.OpenGL4; namespace hexworld.Util { - public abstract class GLObject + public abstract class GLObject : IDisposable { public uint Id { get; protected set; } @@ -16,6 +16,22 @@ namespace hexworld.Util Id = id; } + protected abstract void Delete(); + + private bool _disposed = false; + public void Dispose() + { + if (_disposed) return; + _disposed = true; + Delete(); + GC.SuppressFinalize(this); + } + + ~GLObject() + { + Dispose(); + } + public static explicit operator uint(GLObject o) => o.Id; public static explicit operator int(GLObject o) => (int) o.Id; } diff --git a/hexworld/Util/Program.cs b/hexworld/Util/Program.cs index 9574994..0a97f41 100644 --- a/hexworld/Util/Program.cs +++ b/hexworld/Util/Program.cs @@ -17,6 +17,11 @@ namespace hexworld.Util { } + protected override void Delete() + { + GL.DeleteProgram(Id); + } + public void Attach(Shader shader) => GL.AttachShader(Id, shader.Id); public bool LinkStatus diff --git a/hexworld/Util/Shader.cs b/hexworld/Util/Shader.cs index 55212c7..99d53bf 100644 --- a/hexworld/Util/Shader.cs +++ b/hexworld/Util/Shader.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -39,6 +40,11 @@ namespace hexworld.Util Type = type; } + protected override void Delete() + { + GL.DeleteShader(Id); + } + public bool Compile() { GL.CompileShader(Id); diff --git a/hexworld/Util/Texture.cs b/hexworld/Util/Texture.cs index 12f21c0..7cf5bce 100644 --- a/hexworld/Util/Texture.cs +++ b/hexworld/Util/Texture.cs @@ -22,6 +22,11 @@ namespace hexworld.Util Target = target; } + protected override void Delete() + { + GL.DeleteTexture(Id); + } + public void Bind() { GL.BindTexture(Target, Id); diff --git a/hexworld/Util/VBO.cs b/hexworld/Util/VBO.cs index 8f52ba1..353dfb4 100644 --- a/hexworld/Util/VBO.cs +++ b/hexworld/Util/VBO.cs @@ -23,6 +23,11 @@ namespace hexworld.Util { } + protected override void Delete() + { + GL.DeleteBuffer(Id); + } + public void Bind() { GL.BindBuffer(BufferTarget.ArrayBuffer, Id);