From 88ab90f186db25ff289a4262896bab76405d26b4 Mon Sep 17 00:00:00 2001 From: David Allemang Date: Wed, 1 Mar 2017 16:30:54 -0500 Subject: [PATCH] Added documentation to all GLObject types --- Diamond/Buffers/Buffer.cs | 63 ++++++++++++++++++++++ Diamond/Diamond.csproj | 3 +- Diamond/GLObject.cs | 28 +++++++++- Diamond/Shaders/Program.cs | 82 +++++++++++++++++++++++++---- Diamond/Shaders/Shader.cs | 55 ++++++++++++++++--- Diamond/Shaders/ShaderException.cs | 33 ------------ Diamond/Textures/Texture.cs | 32 +++++++++-- Diamond/{Level => Util}/TileData.cs | 2 +- hexworld/HexRender.cs | 1 - 9 files changed, 240 insertions(+), 59 deletions(-) delete mode 100644 Diamond/Shaders/ShaderException.cs rename Diamond/{Level => Util}/TileData.cs (94%) diff --git a/Diamond/Buffers/Buffer.cs b/Diamond/Buffers/Buffer.cs index aefe9be..1aa2ae9 100644 --- a/Diamond/Buffers/Buffer.cs +++ b/Diamond/Buffers/Buffer.cs @@ -8,6 +8,10 @@ using OpenTK.Graphics.OpenGL4; namespace Diamond.Buffers { + /// + /// Manages an OpenGL Buffer object + /// + /// The type of data used for this buffer public class Buffer : GLObject where T : struct { private readonly BufferWrap _buffer; @@ -16,8 +20,15 @@ namespace Diamond.Buffers private readonly int _size; + /// + /// The target for this buffer; its type + /// public BufferTarget Target => _buffer.Target; + /// + /// The usage hint for this buffer. Use StaticDraw for one-time uploads to + /// vertex buffers, and DynamicDraw for repeated uploads to vertex buffers. + /// public BufferUsageHint Usage { get => _buffer.Usage; @@ -32,12 +43,31 @@ namespace Diamond.Buffers _vdi = VertexDataInfo.GetInfo(); } + /// + /// Upload data to this buffer + /// + /// The data to upload public void Data(T[] data) => _buffer.Data(_size, data); + /// + /// Upload a range of data to this buffer + /// + /// The range offset + /// The range length + /// The data to upload, offset and length apply to both this and the target public void Data(int offset, int count, T[] data) => _buffer.SubData(_size, offset, count, data); + /// + /// Upload a range of data to this buffer + /// + /// The data to upload public void Data(SubArray data) => Data(data.Offset, data.Length, data.Array); + /// + /// Point this buffer to a program's vertex attributes. T must have [VertexDataAttribute], and all fields + /// of T must have [VertexPointerAttribute] to infer vertex pointer locations. + /// + /// The program to point this buffer to public void PointTo(Program program) { if (_vdi == null) @@ -60,6 +90,13 @@ namespace Diamond.Buffers ? $"Buffer<{typeof(T).Name}> {Target} ({Id})" : $"Buffer<{typeof(T).Name}> {Target} {Name} ({Id})"; + /// + /// Create an empty buffer of this type + /// + /// The buffer target + /// The initial usage hint + /// The name of this GLObject + /// The buffer, or null if initialization failed internal static Buffer Empty(BufferTarget target, BufferUsageHint usage, string name) { var wrapper = new BufferWrap(target, usage); @@ -70,6 +107,14 @@ namespace Diamond.Buffers return service; } + /// + /// Create a buffer of this type and upload data + /// + /// The data to upload + /// The buffer target + /// The initial usage hint + /// The name of this GLObject + /// The buffer, or null if initialization failed internal static Buffer FromData(T[] data, BufferTarget target, BufferUsageHint usage, string name = null) { var service = Empty(target, usage, name); @@ -80,11 +125,29 @@ namespace Diamond.Buffers } } + /// + /// Class for static Buffer operations and public factory methods + /// public static class Buffer { + /// + /// Create an empty buffer of this type + /// + /// The buffer target + /// The initial usage hint + /// The name of this GLObject + /// The buffer, or null if initialization failed public static Buffer Empty(BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw, string name = null) where T : struct => Buffer.Empty(target, usage, name); + /// + /// Create a buffer of this type and upload data + /// + /// The data to upload + /// The buffer target + /// The initial usage hint + /// The name of this GLObject + /// The buffer, or null if initialization failed public static Buffer FromData(T[] data, BufferTarget target, BufferUsageHint usage = BufferUsageHint.StaticDraw, string name = null) where T : struct => Buffer.FromData(data, target, usage, name); diff --git a/Diamond/Diamond.csproj b/Diamond/Diamond.csproj index 16be66b..a02a020 100644 --- a/Diamond/Diamond.csproj +++ b/Diamond/Diamond.csproj @@ -60,13 +60,12 @@ - + - diff --git a/Diamond/GLObject.cs b/Diamond/GLObject.cs index 7fce728..d784304 100644 --- a/Diamond/GLObject.cs +++ b/Diamond/GLObject.cs @@ -4,17 +4,33 @@ using NLog; namespace Diamond { + /// + /// Provide managed access to OpenGL objects + /// public abstract class GLObject : IDisposable { + /// + /// Logger for all GLObjects + /// protected static readonly Logger Logger = LogManager.GetLogger("GLObject"); - private bool _disposed; - + /// + /// Name of this GLObject used for identification + /// public string Name { get; protected set; } = "GLObject"; + /// + /// Underlying managed wrapper to this OpenGL object + /// internal abstract Wrapper Wrapper { get; } + + /// + /// The OpenGL name of this object + /// public int Id => Wrapper.Id; + #region IDisposable + protected virtual void Dispose(bool disposing) { if (_disposed) @@ -29,6 +45,10 @@ namespace Diamond _disposed = true; } + #region Implemented + + private bool _disposed; + public void Dispose() { Dispose(true); @@ -39,5 +59,9 @@ namespace Diamond { Dispose(false); } + + #endregion + + #endregion } } \ No newline at end of file diff --git a/Diamond/Shaders/Program.cs b/Diamond/Shaders/Program.cs index 23e5dae..90aad0a 100644 --- a/Diamond/Shaders/Program.cs +++ b/Diamond/Shaders/Program.cs @@ -6,14 +6,22 @@ using OpenTK.Graphics.OpenGL4; namespace Diamond.Shaders { + /// + /// Manages an OpenGL Program object + /// public class Program : GLObject { private readonly ProgramWrap _program; internal override Wrapper Wrapper => _program; + /// + /// The currently active program. Manually invoking glUseProgram will break this. + /// public static Program Current { get; private set; } + // keep a cache of uniform and attributes to prevent repeated queries private readonly Dictionary _uniforms = new Dictionary(); + private readonly Dictionary _attributes = new Dictionary(); internal Program(ProgramWrap program, string name) @@ -22,24 +30,42 @@ namespace Diamond.Shaders Name = name; } + // todo change these to not use int? - possibly use TryGet, or return negative value if not present + + /// + /// Get the location of a uniform + /// + /// The name of the uniform + /// The location, or no value if uniform not present public int? UniformLocation(string name) { if (_uniforms.ContainsKey(name)) return _uniforms[name]; return null; } + /// + /// Get the location of an attribute + /// + /// The name of the attribute + /// The location, or no value if attribute not present public int? AttributeLocation(string name) { if (_attributes.ContainsKey(name)) return _attributes[name]; return null; } + /// + /// Use this Program to render. Also updates Program.Current + /// public void Use() { GL.UseProgram(Id); Current = this; } + /// + /// Use the default shader to render + /// //? Could create static Program instance which wraps the default shader // ie Shader.Default.Use() // would also allow sending arrays to the default attribs like gl_Vertex etc. @@ -49,6 +75,10 @@ namespace Diamond.Shaders Current = null; } + /// + /// Helper method to try to link this program + /// + /// private bool Link() { _uniforms.Clear(); @@ -68,6 +98,10 @@ namespace Diamond.Shaders return true; } + /// + /// Helper method to attach a shader to this program + /// + /// The shader to attach private void Attach(Shader shader) { _program.Attach((ShaderWrap) shader.Wrapper); @@ -75,16 +109,23 @@ namespace Diamond.Shaders public override string ToString() => $"Program \'{Name}\' ({Id})"; - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - } - #region Factory Methods + /// + /// Create a program from compiled shaders + /// + /// The name of this GLObject + /// The shaders to use in this program + /// The linked program, or null if initialization failed public static Program FromShaders(string name, params Shader[] shaders) => FromShaders(name, (IEnumerable) shaders); + /// + /// Create a program from compiled shaders + /// + /// The name of this GLObject + /// The shaders to use in this program + /// The linked program, or null if initialization failed public static Program FromShaders(string name, IEnumerableshaders) { if (shaders == null) @@ -110,9 +151,9 @@ namespace Diamond.Shaders service.Attach(shader); } - service.Link(); + var linked = service.Link(); - if (!wrapper.Linked) + if (!linked) { Logger.Warn("Failed to link {0}", service); Logger.Debug("InfoLog for {0}", service); @@ -125,9 +166,18 @@ namespace Diamond.Shaders return service; } - + /// + /// Create a program from compiled shaders + /// + /// The shaders to use in this program + /// The linked program, or null if initialization failed public static Program FromShaders(params Shader[] shaders) => FromShaders((IEnumerable) shaders); + /// + /// Create a program from compiled shaders + /// + /// The shaders to use in this program + /// The linked program, or null if initialization failed public static Program FromShaders(IEnumerable shaders) { var shaderList = shaders.ToList(); // prevent multiple enumeration @@ -136,14 +186,26 @@ namespace Diamond.Shaders return FromShaders(name, shaderList); } + /// + /// Create shaders from glsl source files, and create a program using them. + /// Shader types must be inferrable from file extensions. + /// + /// The glsl source files + /// The linked program, or null if initialization faileds public static Program FromFiles(params string[] paths) { - var shaders = paths.Select(Shader.FromFile).ToList(); + if (paths == null) + { + Logger.Warn("Cannot create a program from no shaders."); + return null; + } + + var shaders = paths.Select(path => Shader.FromFile(path)).ToList(); var program = FromShaders(shaders); foreach (var shader in shaders) - shader.Dispose(); + shader?.Dispose(); return program; } diff --git a/Diamond/Shaders/Shader.cs b/Diamond/Shaders/Shader.cs index 05ebbe7..18d672a 100644 --- a/Diamond/Shaders/Shader.cs +++ b/Diamond/Shaders/Shader.cs @@ -6,12 +6,22 @@ using OpenTK.Graphics.OpenGL4; namespace Diamond.Shaders { + /// + /// Manges a OpenGL Shader object + /// public class Shader : GLObject { private readonly ShaderWrap _shader; internal override Wrapper Wrapper => _shader; + /// + /// The source used to create this shader + /// public string Source { get; } + + /// + /// The type of this shader + /// public ShaderType Type { get; } internal Shader(ShaderWrap shader, string source, ShaderType type, string name) @@ -26,14 +36,24 @@ namespace Diamond.Shaders #region Factory Methods + // Used to infer shader type based on file extension private static readonly Dictionary Extensions = new Dictionary { [".vs"] = ShaderType.VertexShader, [".vert"] = ShaderType.VertexShader, [".fs"] = ShaderType.FragmentShader, [".frag"] = ShaderType.FragmentShader, + [".gs"] = ShaderType.GeometryShader, + [".geom"] = ShaderType.GeometryShader, }; - + + /// + /// Create and compile a shader from glsl source code + /// + /// The glsl source + /// The type of shader to create + /// The name of this GLObject + /// The compiled Shader, or null if initialization failed public static Shader FromSource(string source, ShaderType type, string name = "Shader") { var wrapper = new ShaderWrap(type); @@ -57,7 +77,14 @@ namespace Diamond.Shaders return service; } - public static Shader FromFile(string path, ShaderType type) + /// + /// Create and compile a shader from a glsl source file + /// + /// The path to the glsl source file + /// The type of the shader to create + /// The name of this GLObject + /// + public static Shader FromFile(string path, ShaderType type, string name = null) { if (!File.Exists(path)) { @@ -65,11 +92,21 @@ namespace Diamond.Shaders return null; } - var name = Path.GetFileNameWithoutExtension(path); + if (name == null) + name = Path.GetFileNameWithoutExtension(path); + return FromSource(File.ReadAllText(path), type, name); } - public static Shader FromFile(string path) + /// + /// Create and compile a shader from a glsl source file. Shader type is inferred from file extension. + /// Extension must be .vs, .vert, .fs, .frag, .gs, or .geom. This can optionally be followed by .glsl or .txt, + /// but the shader type extension must be present. + /// + /// The path to the glsl source file + /// The name of this GLObject + /// The compiled shader, or null if initialization failed or shader type cannot be inferred + public static Shader FromFile(string path, string name = null) { if (!File.Exists(path)) { @@ -78,12 +115,14 @@ namespace Diamond.Shaders } var ext = Path.GetExtension(path); - var name = Path.GetFileNameWithoutExtension(path); + var fileName = Path.GetFileNameWithoutExtension(path); + // get sub-extension if real extension is not valid if (ext != null) if (!Extensions.ContainsKey(ext)) - ext = Path.GetExtension(name); + ext = Path.GetExtension(fileName); + // if no extension, no sub-extension, or invalid sub-extension if (ext == null || !Extensions.ContainsKey(ext)) { Logger.Warn("Could not infer shader type from glsl file name {0}", path); @@ -91,8 +130,10 @@ namespace Diamond.Shaders } var type = Extensions[ext]; + if (name == null) + name = fileName; - return FromFile(path, type); + return FromFile(path, type, name); } #endregion diff --git a/Diamond/Shaders/ShaderException.cs b/Diamond/Shaders/ShaderException.cs deleted file mode 100644 index 361816e..0000000 --- a/Diamond/Shaders/ShaderException.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace Diamond.Shaders -{ - /// - /// Exception relating to Shader and Program operations. - /// - [Serializable] - public class ShaderException : Exception - { - public ShaderException() - { - } - - public ShaderException(string message) - : base(message) - { - } - - public ShaderException(string message, Exception inner) - : base(message, inner) - { - } - - protected ShaderException( - SerializationInfo info, - StreamingContext context) - : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/Diamond/Textures/Texture.cs b/Diamond/Textures/Texture.cs index cbe28d3..a5c9eb7 100644 --- a/Diamond/Textures/Texture.cs +++ b/Diamond/Textures/Texture.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.Drawing.Imaging; +using System.IO; using Diamond.Wrappers; using NLog; using OpenTK.Graphics.OpenGL4; @@ -7,6 +8,9 @@ using PixelFormat = OpenTK.Graphics.OpenGL4.PixelFormat; namespace Diamond.Textures { + /// + /// Manages a OpenGL Texture object + /// public class Texture : GLObject { private readonly TextureWrap _texture; @@ -18,15 +22,26 @@ namespace Diamond.Textures Name = name; } + /// + /// This textures target; how it is used + /// public TextureTarget Target => _texture.Target; - public void Bind() => _texture.Bind(); + /// + /// Bind this texture to a particular unit + /// public void Bind(int unit) => _texture.Bind(unit); public override string ToString() => Name == null ? $"{Target} ({Id})" : $"{Target} \'{Name}\' ({Id})"; #region Factory Methods + /// + /// Create a texture object and upload bitmap data to it + /// + /// The image to upload + /// The name of this GLObject + /// The initialized Texture, or null if initialsation failed public static Texture FromBitmap(Bitmap bmp, string name = null) { var wrapper = new TextureWrap(TextureTarget.Texture2D); @@ -35,6 +50,8 @@ namespace Diamond.Textures Logger.Debug("Created Texture {0}", service); wrapper.Bind(); + + // todo: expose texture parameters to enable setting different filters wrapper.TexParameter(TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Nearest); wrapper.TexParameter(TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Nearest); @@ -47,9 +64,18 @@ namespace Diamond.Textures return service; } - public static Texture FromFile(string path) + /// + /// Create a texture and upload the contents of an image file to it + /// + /// The path to the file + /// The name of this GLObject + /// The initialized Texture, or null if instantiation failed + public static Texture FromFile(string path, string name = null) { - return FromBitmap(new Bitmap(path)); + if (name == null) + name = Path.GetFileNameWithoutExtension(path); + + return FromBitmap(new Bitmap(path), name); } #endregion diff --git a/Diamond/Level/TileData.cs b/Diamond/Util/TileData.cs similarity index 94% rename from Diamond/Level/TileData.cs rename to Diamond/Util/TileData.cs index d857b7b..2af7f99 100644 --- a/Diamond/Level/TileData.cs +++ b/Diamond/Util/TileData.cs @@ -1,7 +1,7 @@ using Diamond.Buffers; using OpenTK; -namespace Diamond.Level +namespace Diamond.Util { [VertexData(Divisor = 1)] public struct TileData diff --git a/hexworld/HexRender.cs b/hexworld/HexRender.cs index 4ac30d4..889c509 100644 --- a/hexworld/HexRender.cs +++ b/hexworld/HexRender.cs @@ -2,7 +2,6 @@ using System.IO; using System.Linq; using Diamond.Buffers; -using Diamond.Level; using Diamond.Shaders; using Diamond.Textures; using Diamond.Util;