diff --git a/Engine/src/Asset/Font/Font.cs b/Engine/src/Asset/Font/Font.cs
index 99c7d7f..02e1b0c 100644
--- a/Engine/src/Asset/Font/Font.cs
+++ b/Engine/src/Asset/Font/Font.cs
@@ -4,16 +4,46 @@ using OpenTK.Mathematics;
namespace Engine.Asset.Font;
+///
+/// Represents a font loaded from a texture atlas and metadata.
+///
public class Font
{
+ ///
+ /// The static texture atlas used for rendering the font.
+ ///
public StaticTexture AtlasTexture { get; }
+
+ ///
+ /// The metadata associated with the font.
+ ///
public Metadata.Metadata Metadata { get; }
+
+ ///
+ /// The unit range of the font, calculated from the distance range and the atlas size.
+ ///
public Vector2 UnitRange { get; }
+ ///
+ /// A dictionary mapping Unicode code points to glyphs.
+ ///
private readonly Dictionary _glyphs = new();
+
+ ///
+ /// A dictionary mapping Unicode code points to glyph data.
+ ///
private readonly Dictionary _glyphData = new();
+
+ ///
+ /// A dictionary mapping pairs of Unicode code points to kerning data.
+ ///
private readonly Dictionary<(int, int), Kerning> _kernings = new();
+ ///
+ /// Initializes a new instance of the class with the specified texture atlas and metadata.
+ ///
+ /// The static texture atlas for the font.
+ /// The metadata for the font.
public Font(StaticTexture parAtlasTexture, Metadata.Metadata parMetadata)
{
AtlasTexture = parAtlasTexture;
@@ -25,26 +55,52 @@ public class Font
LoadKernings();
}
+ ///
+ /// Retrieves the glyph associated with the specified Unicode value.
+ ///
+ /// The Unicode value of the glyph.
+ /// The glyph for the specified Unicode value, or null if not found.
public Glyph? GetGlyph(int parUnicode)
{
return _glyphs.GetValueOrDefault(parUnicode);
}
+ ///
+ /// Retrieves the glyph data associated with the specified Unicode value.
+ ///
+ /// The Unicode value of the glyph.
+ /// The glyph data for the specified Unicode value, or null if not found.
public GlyphData? GetGlyphData(int parUnicode)
{
return _glyphData.GetValueOrDefault(parUnicode);
}
+ ///
+ /// Retrieves the kerning information between two specified Unicode values.
+ ///
+ /// The Unicode value of the first character.
+ /// The Unicode value of the second character.
+ /// The kerning information, or null if not found.
public Kerning? GetKerning(int parUnicode1, int parUnicode2)
{
return _kernings.GetValueOrDefault((parUnicode1, parUnicode2));
}
+ ///
+ /// Creates an iterator for traversing through the specified text using the font.
+ ///
+ /// The text to iterate over.
+ /// An iterator for the text.
public FontIterator Iterator(string parText)
{
return new FontIterator(this, parText);
}
+ ///
+ /// Measures the size of the specified text when rendered using the font.
+ ///
+ /// The text to measure.
+ /// The size of the text in .
public Vector2 Measure(string parText)
{
var fontIterator = Iterator(parText);
@@ -53,6 +109,9 @@ public class Font
return new Vector2(fontIterator.MaxWidth, fontIterator.MaxHeight);
}
+ ///
+ /// Loads the glyphs from the metadata into the font with their associated data.
+ ///
private void LoadGlyphs()
{
foreach (var glyph in Metadata.Glyphs)
@@ -68,6 +127,9 @@ public class Font
}
}
+ ///
+ /// Loads the kerning information from the metadata into the font.
+ ///
private void LoadKernings()
{
foreach (var kerning in Metadata.Kerning)
@@ -76,11 +138,26 @@ public class Font
}
}
+ ///
+ /// Represents the data associated with a single glyph in the font.
+ ///
public record GlyphData
{
+ ///
+ /// The positions of the glyph's vertices.
+ ///
public Vector2[] Positions { get; }
+
+ ///
+ /// The texture UV coordinates for the glyph's vertices.
+ ///
public Vector2[] UVs { get; }
+ ///
+ /// Initializes a new instance of the record with the given metadata and glyph.
+ ///
+ /// The font metadata.
+ /// The glyph for which to create data.
public GlyphData(in Metadata.Metadata parMetadata, in Glyph parGlyph)
{
var size = new Vector2(parMetadata.Atlas.Width, parMetadata.Atlas.Height);
diff --git a/Engine/src/Asset/Font/FontIterator.cs b/Engine/src/Asset/Font/FontIterator.cs
index 002eda6..2351802 100644
--- a/Engine/src/Asset/Font/FontIterator.cs
+++ b/Engine/src/Asset/Font/FontIterator.cs
@@ -3,26 +3,71 @@ using OpenTK.Mathematics;
namespace Engine.Asset.Font;
+///
+/// An iterator that traverses through the characters of a given text using a font, calculating the glyph data, positions, and kerning.
+///
public class FontIterator : IEnumerable
{
+ ///
+ /// The maximum width encountered while measuring the text.
+ ///
public float MaxWidth { get; private set; }
+
+ ///
+ /// The maximum height encountered while measuring the text.
+ ///
public float MaxHeight { get; private set; }
+ ///
+ /// The font to use for text iteration.
+ ///
private readonly Font _font;
+
+ ///
+ /// The text to iterate over.
+ ///
private readonly string _text;
+ ///
+ /// The current index in the text.
+ ///
private int _currentIndex;
+
+ ///
+ /// The previous Unicode code point.
+ ///
private int _previousCodepoint = -1;
+
+ ///
+ /// The number of characters on the current line.
+ ///
private int _lineCharCount;
+
+ ///
+ /// The current cursor position.
+ ///
private Vector2 _cursor = Vector2.Zero;
+
+ ///
+ /// The current kerning offset.
+ ///
private Vector2 _kerning = Vector2.Zero;
+ ///
+ /// Initializes a new instance of the class with the specified font and text.
+ ///
+ /// The font to use for rendering.
+ /// The text to iterate over.
public FontIterator(Font parFont, string parText)
{
_font = parFont;
_text = parText;
}
+ ///
+ /// Returns an enumerator that iterates through the next glyph data for the text.
+ ///
+ /// An enumerator for the next glyph data in the text.
public IEnumerator GetEnumerator()
{
while (_currentIndex < _text.Length)
@@ -80,21 +125,38 @@ public class FontIterator : IEnumerable
}
}
+ ///
+ /// Returns a non-generic enumerator for the .
+ ///
+ /// A non-generic enumerator for the font iterator.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
+ ///
+ /// Determines if the provided codepoint represents a line break character.
+ ///
+ /// The codepoint to check.
+ /// true if the codepoint represents a line break, otherwise false.
private static bool IsLineBreak(int parCodepoint)
{
return parCodepoint == '\n';
}
+ ///
+ /// Determines if the provided codepoint represents a tab character.
+ ///
+ /// The codepoint to check.
+ /// true if the codepoint represents a tab character, otherwise false.
private static bool IsTab(int parCodepoint)
{
return parCodepoint == '\t';
}
+ ///
+ /// Handles the tab character by advancing the cursor position to the next tab stop.
+ ///
private void Tab()
{
var spaceGlyph = _font.GetGlyph(' ');
@@ -107,6 +169,9 @@ public class FontIterator : IEnumerable
_cursor.X += missingSpaces * spaceGlyph.Advance;
}
+ ///
+ /// Handles a line break by resetting the cursor position and updating the line height.
+ ///
private void LineBreak()
{
_kerning = Vector2.Zero;
@@ -116,5 +181,8 @@ public class FontIterator : IEnumerable
_previousCodepoint = -1;
}
+ ///
+ /// Contains the data for the next glyph in the iteration, including its positions, texture UVs, and offset.
+ ///
public record NextGlyphData(Vector2[] Positions, Vector2[] UVs, Vector2 Offset);
}
\ No newline at end of file
diff --git a/Engine/src/Asset/Font/Metadata/Atlas.cs b/Engine/src/Asset/Font/Metadata/Atlas.cs
index 27d249a..6049bf2 100644
--- a/Engine/src/Asset/Font/Metadata/Atlas.cs
+++ b/Engine/src/Asset/Font/Metadata/Atlas.cs
@@ -2,26 +2,44 @@
namespace Engine.Asset.Font.Metadata;
+///
+/// Represents the texture atlas used for font rendering.
+///
[JsonSerializable(typeof(Atlas))]
[Serializable]
public record Atlas
{
+ ///
+ /// The distance range for the atlas.
+ ///
[JsonPropertyName("distanceRange")]
[JsonInclude]
public float DistanceRange { get; private set; }
+ ///
+ /// The size of the atlas.
+ ///
[JsonPropertyName("size")]
[JsonInclude]
public float Size { get; private set; }
+ ///
+ /// The width of the atlas.
+ ///
[JsonPropertyName("width")]
[JsonInclude]
public int Width { get; private set; }
+ ///
+ /// The height of the atlas.
+ ///
[JsonPropertyName("height")]
[JsonInclude]
public int Height { get; private set; }
+ ///
+ /// The Y-origin of the atlas.
+ ///
[JsonPropertyName("yOrigin")]
[JsonInclude]
public string YOrigin { get; private set; }
diff --git a/Engine/src/Asset/Font/Metadata/Bounds.cs b/Engine/src/Asset/Font/Metadata/Bounds.cs
index 56428a7..d4e8f9f 100644
--- a/Engine/src/Asset/Font/Metadata/Bounds.cs
+++ b/Engine/src/Asset/Font/Metadata/Bounds.cs
@@ -2,22 +2,37 @@
namespace Engine.Asset.Font.Metadata;
+///
+/// Defines the bounds of a font glyph in the coordinate space.
+///
[JsonSerializable(typeof(Bounds))]
[Serializable]
public record Bounds
{
+ ///
+ /// The left boundary of the bounds.
+ ///
[JsonPropertyName("left")]
[JsonInclude]
public float Left { get; private set; }
+ ///
+ /// The bottom boundary of the bounds.
+ ///
[JsonPropertyName("bottom")]
[JsonInclude]
public float Bottom { get; private set; }
+ ///
+ /// The right boundary of the bounds.
+ ///
[JsonPropertyName("right")]
[JsonInclude]
public float Right { get; private set; }
+ ///
+ /// The top boundary of the bounds.
+ ///
[JsonPropertyName("top")]
[JsonInclude]
public float Top { get; private set; }
diff --git a/Engine/src/Asset/Font/Metadata/Glyph.cs b/Engine/src/Asset/Font/Metadata/Glyph.cs
index 6eef68a..840e53f 100644
--- a/Engine/src/Asset/Font/Metadata/Glyph.cs
+++ b/Engine/src/Asset/Font/Metadata/Glyph.cs
@@ -2,22 +2,37 @@
namespace Engine.Asset.Font.Metadata;
+///
+/// Represents a single glyph in the font with associated metadata.
+///
[JsonSerializable(typeof(Glyph))]
[Serializable]
public record Glyph
{
+ ///
+ /// The Unicode code point of the glyph.
+ ///
[JsonPropertyName("unicode")]
[JsonInclude]
public int Unicode { get; private set; }
+ ///
+ /// The advance width of the glyph.
+ ///
[JsonPropertyName("advance")]
[JsonInclude]
public float Advance { get; private set; }
+ ///
+ /// The bounds of the glyph in the plane.
+ ///
[JsonPropertyName("planeBounds")]
[JsonInclude]
public Bounds? PlaneBounds { get; private set; }
+ ///
+ /// The bounds of the glyph in the atlas.
+ ///
[JsonPropertyName("atlasBounds")]
[JsonInclude]
public Bounds? AtlasBounds { get; private set; }
diff --git a/Engine/src/Asset/Font/Metadata/Kerning.cs b/Engine/src/Asset/Font/Metadata/Kerning.cs
index 5ce8680..43bc469 100644
--- a/Engine/src/Asset/Font/Metadata/Kerning.cs
+++ b/Engine/src/Asset/Font/Metadata/Kerning.cs
@@ -2,18 +2,30 @@
namespace Engine.Asset.Font.Metadata;
+///
+/// Represents kerning information between two characters in the font.
+///
[JsonSerializable(typeof(Kerning))]
[Serializable]
public record Kerning
{
+ ///
+ /// The Unicode value of the first character in the kerning pair.
+ ///
[JsonPropertyName("unicode1")]
[JsonInclude]
public int Unicode1 { get; private set; }
+ ///
+ /// The Unicode value of the second character in the kerning pair.
+ ///
[JsonPropertyName("unicode2")]
[JsonInclude]
public int Unicode2 { get; private set; }
+ ///
+ /// The amount of kerning (adjustment) between the two characters.
+ ///
[JsonPropertyName("advance")]
[JsonInclude]
public float Advance { get; private set; }
diff --git a/Engine/src/Asset/Font/Metadata/Metadata.cs b/Engine/src/Asset/Font/Metadata/Metadata.cs
index 979a5d2..ccd9ea6 100644
--- a/Engine/src/Asset/Font/Metadata/Metadata.cs
+++ b/Engine/src/Asset/Font/Metadata/Metadata.cs
@@ -2,22 +2,37 @@
namespace Engine.Asset.Font.Metadata;
+///
+/// Represents metadata for a font, including atlas, metrics, glyphs, and kerning.
+///
[JsonSerializable(typeof(Metadata))]
[Serializable]
public record Metadata
{
+ ///
+ /// The atlas information for the font.
+ ///
[JsonPropertyName("atlas")]
[JsonInclude]
public Atlas Atlas { get; private set; }
+ ///
+ /// The metrics of the font.
+ ///
[JsonPropertyName("metrics")]
[JsonInclude]
public Metrics Metrics { get; private set; }
+ ///
+ /// The array of glyphs in the font.
+ ///
[JsonPropertyName("glyphs")]
[JsonInclude]
public Glyph[] Glyphs { get; private set; }
+ ///
+ /// The array of kerning pairs for the font.
+ ///
[JsonPropertyName("kerning")]
[JsonInclude]
public Kerning[] Kerning { get; private set; }
diff --git a/Engine/src/Asset/Font/Metadata/Metrics.cs b/Engine/src/Asset/Font/Metadata/Metrics.cs
index a38641f..678e64f 100644
--- a/Engine/src/Asset/Font/Metadata/Metrics.cs
+++ b/Engine/src/Asset/Font/Metadata/Metrics.cs
@@ -2,30 +2,51 @@
namespace Engine.Asset.Font.Metadata;
+///
+/// Represents the metrics for a font, including size and line height.
+///
[JsonSerializable(typeof(Metrics))]
[Serializable]
public record Metrics
{
+ ///
+ /// The em size of the font.
+ ///
[JsonPropertyName("emSize")]
[JsonInclude]
public float EmSize { get; private set; }
+ ///
+ /// The line height of the font.
+ ///
[JsonPropertyName("lineHeight")]
[JsonInclude]
public float LineHeight { get; private set; }
+ ///
+ /// The ascender height of the font.
+ ///
[JsonPropertyName("ascender")]
[JsonInclude]
public float Ascender { get; private set; }
+ ///
+ /// The descender height of the font.
+ ///
[JsonPropertyName("descender")]
[JsonInclude]
public float Descender { get; private set; }
+ ///
+ /// The Y-coordinate of the underline.
+ ///
[JsonPropertyName("underlineY")]
[JsonInclude]
public float UnderlineY { get; private set; }
+ ///
+ /// The thickness of the underline in the font.
+ ///
[JsonPropertyName("underlineThickness")]
public float UnderlineThickness { get; private set; }
}
\ No newline at end of file
diff --git a/Engine/src/Asset/Image.cs b/Engine/src/Asset/Image.cs
index 3678b8d..0480ae6 100644
--- a/Engine/src/Asset/Image.cs
+++ b/Engine/src/Asset/Image.cs
@@ -3,12 +3,34 @@ using Engine.Graphics.Texture;
namespace Engine.Asset;
+///
+/// Represents an image containing pixels of a specified type.
+/// The image stores pixel data in a 2D array and provides methods for converting it into textures.
+///
public class Image where T : struct, IPixel
{
+ ///
+ /// The width of the image, in pixels.
+ ///
public int Width { get; }
+
+ ///
+ /// The height of the image, in pixels.
+ ///
public int Height { get; }
+
+ ///
+ /// The 2D array of pixels representing the image's content.
+ /// Each element in the array is of type .
+ ///
public T[,] Pixels { get; }
+ ///
+ /// Initializes a new instance of the class with specified width and height.
+ /// Allocates a 2D array to hold pixel data.
+ ///
+ /// The width of the image in pixels.
+ /// The height of the image in pixels.
public Image(int parWidth, int parHeight)
{
Width = parWidth;
@@ -16,8 +38,18 @@ public class Image where T : struct, IPixel
Pixels = new T[parHeight, parWidth];
}
+ ///
+ /// Indexer to access individual pixels in the image by their Y (row) and X (column) coordinates.
+ ///
+ /// The Y coordinate (row) of the pixel.
+ /// The X coordinate (column) of the pixel.
+ /// The pixel at the specified coordinates.
public T this[int parY, int parX] => Pixels[parY, parX];
+ ///
+ /// Converts the image into a dynamic texture that can be uploaded to the GPU.
+ ///
+ /// A representing the image.
public DynamicTexture ToDynamicTexture()
{
var texture = DynamicTexture.Create(Width, Height);
@@ -25,6 +57,11 @@ public class Image where T : struct, IPixel
return texture;
}
+ ///
+ /// Converts the image into a static texture that can be uploaded to the GPU.
+ /// Static textures are optimized for performance but cannot be updated after creation.
+ ///
+ /// A representing the image.
public StaticTexture ToStaticTexture()
{
var texture = StaticTexture.Create(Width, Height);
diff --git a/Engine/src/Asset/Mesh/Loader/IMeshLoader.cs b/Engine/src/Asset/Mesh/Loader/IMeshLoader.cs
index b62a427..8ac0a09 100644
--- a/Engine/src/Asset/Mesh/Loader/IMeshLoader.cs
+++ b/Engine/src/Asset/Mesh/Loader/IMeshLoader.cs
@@ -1,9 +1,23 @@
namespace Engine.Asset.Mesh.Loader;
+///
+/// Defines the interface for a mesh loader that can load meshes from a given stream.
+///
public interface IMeshLoader
{
+ ///
+ /// Loads a mesh from the provided text reader with optional parameters.
+ ///
+ /// The text reader to read the mesh data from.
+ /// Optional parameters to control the mesh loading behavior.
+ /// The loaded mesh.
public Mesh LoadMesh(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default);
+ ///
+ /// Optimizes the provided mesh by removing duplicate vertices and reusing indices.
+ ///
+ /// The mesh to optimize.
+ /// A new optimized mesh.
internal static Mesh Optimize(Mesh parMesh)
{
var optimizedMesh = new Mesh();
diff --git a/Engine/src/Asset/Mesh/Loader/MeshLoaderParameters.cs b/Engine/src/Asset/Mesh/Loader/MeshLoaderParameters.cs
index 995be3e..b283bb6 100644
--- a/Engine/src/Asset/Mesh/Loader/MeshLoaderParameters.cs
+++ b/Engine/src/Asset/Mesh/Loader/MeshLoaderParameters.cs
@@ -1,12 +1,33 @@
namespace Engine.Asset.Mesh.Loader;
+///
+/// Specifies options for mesh loading behavior, such as loading normals, UVs, and optimization.
+///
[Flags]
public enum MeshLoaderParameters
{
+ ///
+ /// No options selected.
+ ///
None = 0,
+
+ ///
+ /// Load normals for the mesh.
+ ///
LoadNormals = 1 << 0,
+
+ ///
+ /// Load UVs for the mesh.
+ ///
LoadUVs = 1 << 1,
+
+ ///
+ /// Optimize the mesh by removing duplicate vertices and reusing indices.
+ ///
Optimize = 1 << 2,
+ ///
+ /// Default set of options: load normals, load UVs, and optimize the mesh.
+ ///
Default = LoadNormals | LoadUVs | Optimize
}
\ No newline at end of file
diff --git a/Engine/src/Asset/Mesh/Loader/ObjMeshLoader.cs b/Engine/src/Asset/Mesh/Loader/ObjMeshLoader.cs
index 727a98c..def48a2 100644
--- a/Engine/src/Asset/Mesh/Loader/ObjMeshLoader.cs
+++ b/Engine/src/Asset/Mesh/Loader/ObjMeshLoader.cs
@@ -3,19 +3,40 @@ using OpenTK.Mathematics;
namespace Engine.Asset.Mesh.Loader;
+///
+/// A mesh loader for loading meshes from OBJ file format.
+///
public class ObjMeshLoader : IMeshLoader
{
+ ///
+ /// The singleton instance of the .
+ ///
private static readonly ObjMeshLoader INSTANCE = new();
+ ///
+ /// Initializes a new instance of the class.
+ ///
private ObjMeshLoader()
{
}
+ ///
+ /// Loads a mesh from the provided text reader in the OBJ format with optional parameters.
+ ///
+ /// The text reader to read the OBJ data from.
+ /// Optional parameters to control the mesh loading behavior.
+ /// The loaded mesh.
public static Mesh Load(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
{
return INSTANCE.LoadMesh(parReader, parParameters);
}
+ ///
+ /// Loads a mesh from the provided text reader in the OBJ format with optional parameters.
+ ///
+ /// The text reader to read the OBJ data from.
+ /// Optional parameters to control the mesh loading behavior.
+ /// The loaded mesh.
public Mesh LoadMesh(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
{
var mesh = new Mesh();
diff --git a/Engine/src/Asset/Mesh/Loader/StlMeshLoader.cs b/Engine/src/Asset/Mesh/Loader/StlMeshLoader.cs
index 75683d7..93a3e2d 100644
--- a/Engine/src/Asset/Mesh/Loader/StlMeshLoader.cs
+++ b/Engine/src/Asset/Mesh/Loader/StlMeshLoader.cs
@@ -3,19 +3,40 @@ using OpenTK.Mathematics;
namespace Engine.Asset.Mesh.Loader;
+///
+/// A mesh loader for loading meshes from STL file format.
+///
public class StlMeshLoader : IMeshLoader
{
+ ///
+ /// The singleton instance of the .
+ ///
private static readonly StlMeshLoader INSTANCE = new();
+ ///
+ /// Initializes a new instance of the class.
+ ///
private StlMeshLoader()
{
}
+ ///
+ /// Loads a mesh from the provided text reader in the STL format with optional parameters.
+ ///
+ /// The text reader to read the STL data from.
+ /// Optional parameters to control the mesh loading behavior.
+ /// The loaded mesh.
public static Mesh Load(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
{
return INSTANCE.LoadMesh(parReader, parParameters);
}
+ ///
+ /// Loads a mesh from the provided text reader in the STL format with optional parameters.
+ ///
+ /// The text reader to read the STL data from.
+ /// Optional parameters to control the mesh loading behavior.
+ /// The loaded mesh.
public Mesh LoadMesh(TextReader parReader, MeshLoaderParameters parParameters = MeshLoaderParameters.Default)
{
var mesh = new Mesh();
diff --git a/Engine/src/Asset/Mesh/Mesh.cs b/Engine/src/Asset/Mesh/Mesh.cs
index de994b3..90962f1 100644
--- a/Engine/src/Asset/Mesh/Mesh.cs
+++ b/Engine/src/Asset/Mesh/Mesh.cs
@@ -4,26 +4,68 @@ using OpenTK.Mathematics;
namespace Engine.Asset.Mesh;
+///
+/// Represents a 3D mesh consisting of vertices and indices used for rendering.
+///
public class Mesh
{
+ ///
+ /// A read-only list of indices representing the mesh's geometry.
+ ///
public IReadOnlyList Indices => _indices;
+
+ ///
+ /// A read-only list of vertices representing the mesh's geometry.
+ ///
public IReadOnlyList Vertices => _vertices;
+ ///
+ /// Internal list of indices representing the mesh's geometry.
+ ///
internal IList IndicesInternal => _indices;
+
+ ///
+ /// Internal list of vertices representing the mesh's geometry.
+ ///
internal IList VerticesInternal => _vertices;
+ ///
+ /// List of indices representing the mesh's geometry.
+ ///
private readonly List _indices = [];
+
+ ///
+ /// List of vertices representing the mesh's geometry.
+ ///
private readonly List _vertices = [];
+ ///
+ /// Computes a hash code for the mesh based on its vertices and indices.
+ ///
+ /// The hash code for the mesh.
public override int GetHashCode()
{
return HashCode.Combine(Indices, Vertices);
}
+ ///
+ /// Represents a vertex in a mesh, including position, normal, and UV coordinates.
+ ///
public record struct Vertex : IVertex
{
+ ///
+ /// The position of the vertex in 3D space.
+ ///
[Vertex(VertexAttribType.Float, 3)] public Vector3 _position;
+
+ ///
+ /// The normal of the vertex for lighting calculations.
+ ///
[Vertex(VertexAttribType.Float, 3)] public Vector3 _normal;
+
+ ///
+ /// The texture coordinates (UVs) of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 2)] public Vector2 _uv;
}
}
\ No newline at end of file
diff --git a/Engine/src/Engine.cs b/Engine/src/Engine.cs
index 3f1a289..c21964d 100644
--- a/Engine/src/Engine.cs
+++ b/Engine/src/Engine.cs
@@ -20,17 +20,49 @@ using Debug = Engine.Graphics.Debug;
namespace Engine;
+///
+/// Represents the main engine class responsible for managing resources, rendering, input, and scenes.
+///
public sealed class Engine
{
+ ///
+ /// The input handler of the engine.
+ ///
public IInputHandler? InputHandler { get; internal set; }
+
+ ///
+ /// The scene manager for managing and updating scenes.
+ ///
public SceneManager SceneManager { get; } = new();
+
+ ///
+ /// The resource manager responsible for asset management.
+ ///
public IResourceManager AssetResourceManager { get; }
+
+ ///
+ /// The path to the data folder used by the engine.
+ ///
public string DataFolder { get; }
+ ///
+ /// The singleton instance of the engine.
+ ///
internal static Engine Instance { get; private set; } = null!;
+
+ ///
+ /// The resource manager for engine-specific resources.
+ ///
internal ResourceManager EngineResourceManager { get; }
+
+ ///
+ /// The renderer responsible for managing rendering operations.
+ ///
internal Renderer Renderer { get; }
+ ///
+ /// The presenter responsible for displaying rendered content.
+ ///
internal IPresenter? Presenter
{
get => _presenter;
@@ -38,26 +70,54 @@ public sealed class Engine
{
if (_presenter != null)
{
- _presenter.Resize -= PresenterResize;
+ _presenter.OnResize -= PresenterResize;
}
_presenter = value;
if (_presenter != null)
{
- _presenter.Resize += PresenterResize;
+ _presenter.OnResize += PresenterResize;
}
}
}
+ ///
+ /// The application window that holds rendering context.
+ ///
internal Window Window { get; }
+ ///
+ /// The logger instance used by the engine.
+ ///
private readonly ILogger _logger;
+
+ ///
+ /// The lock used to synchronize scene access.
+ ///
private readonly object _sceneLock = new();
+ ///
+ /// The presenter used to display rendered content.
+ ///
private IPresenter? _presenter;
+
+ ///
+ /// The thread used to run the update loop.
+ ///
private Thread? _updateThread;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The width of the rendering window.
+ /// The height of the rendering window.
+ /// Indicates whether the engine should run in headless mode.
+ /// The title of the application window.
+ /// The path to the asset folder.
+ /// The path to the data folder.
+ /// The logger instance to use for logging.
+ /// Thrown if an engine instance is already running.
public Engine(int parWidth, int parHeight, bool parHeadless, string parTitle, string parAssetFolder,
string parDataFolder,
ILogger parLogger)
@@ -96,6 +156,31 @@ public sealed class Engine
Window = new Window(this, Renderer.NativeWindow, parHeadless);
}
+ ///
+ /// Starts the engine's update and render threads.
+ ///
+ public void Run()
+ {
+ _updateThread = new Thread(RunUpdate) { Name = "UpdateThread" };
+ _updateThread.Start();
+
+ RunRender();
+
+ _updateThread.Join();
+ }
+
+ ///
+ /// Closes the engine and stops all running threads.
+ ///
+ public void Close()
+ {
+ Presenter?.Exit();
+ }
+
+ ///
+ /// Creates and initializes the engine resource manager.
+ ///
+ /// The initialized resource manager.
private static ResourceManager CreateEngineResourceManager()
{
var memoryStreamProvider = new MemoryResourceStreamProvider();
@@ -109,6 +194,11 @@ public sealed class Engine
return resourceManager;
}
+ ///
+ /// Creates and initializes the asset resource manager.
+ ///
+ /// The path to the asset folder.
+ /// The initialized resource manager.
private static ResourceManager CreateAssetResourceManager(string parAssetFolder)
{
var filesystemStreamProvider = new FilesystemResourceStreamProvider(parAssetFolder);
@@ -119,6 +209,10 @@ public sealed class Engine
return resourceManager;
}
+ ///
+ /// Registers the default loaders for the resource manager.
+ ///
+ /// The resource manager to register loaders for.
private static void RegisterDefaultLoaders(ResourceManager parResourceManager)
{
parResourceManager.RegisterLoader(new ProgramLoader());
@@ -128,21 +222,9 @@ public sealed class Engine
parResourceManager.RegisterLoader(new FontLoader());
}
- public void Run()
- {
- _updateThread = new Thread(RunUpdate) { Name = "UpdateThread" };
- _updateThread.Start();
-
- RunRender();
-
- _updateThread.Join();
- }
-
- public void Close()
- {
- Presenter?.Exit();
- }
-
+ ///
+ /// Runs the render loop for the engine.
+ ///
private void RunRender()
{
while (!Presenter?.IsExiting ?? false)
@@ -184,6 +266,9 @@ public sealed class Engine
}
}
+ ///
+ /// Runs the update loop for the engine.
+ ///
private void RunUpdate()
{
var timer = Stopwatch.StartNew();
@@ -211,6 +296,10 @@ public sealed class Engine
}
}
+ ///
+ /// Handles the presenter resize event to adjust the renderer's viewport.
+ ///
+ /// The resize event arguments.
private void PresenterResize(ResizeEventArgs parEventArgs)
{
if (parEventArgs.Width == 0 || parEventArgs.Height == 0)
diff --git a/Engine/src/EngineBuilder.cs b/Engine/src/EngineBuilder.cs
index 9661744..ea4af0f 100644
--- a/Engine/src/EngineBuilder.cs
+++ b/Engine/src/EngineBuilder.cs
@@ -7,36 +7,99 @@ using Serilog.Sinks.SystemConsole.Themes;
namespace Engine;
+///
+/// Provides a builder for creating and configuring an instance of the class.
+///
public sealed class EngineBuilder
{
+ ///
+ /// The title of the application window.
+ ///
private string _title = "";
+
+ ///
+ /// Indicates whether the engine should run in headless mode.
+ ///
private bool _headless;
+
+ ///
+ /// The width of the rendering window.
+ ///
private int _width = 1;
+
+ ///
+ /// The height of the rendering window.
+ ///
private int _height = 1;
+
+ ///
+ /// The path to the asset folder.
+ ///
private string _assetFolder = "./asset";
+
+ ///
+ /// The path to the data folder.
+ ///
private string _dataFolder = "./data";
+ ///
+ /// The input handler factory.
+ ///
private Func? _inputHandlerFunc;
+
+ ///
+ /// The presenter factory.
+ ///
private Func? _presenterFunc;
// Logging
+ ///
+ /// Indicates whether to log to the console.
+ ///
private bool _logToConsole;
+
+ ///
+ /// Indicates whether to log to a file.
+ ///
private bool _logToFile;
+
+ ///
+ /// The path to the log file.
+ ///
private string? _logFilePath;
+
+ ///
+ /// The log level.
+ ///
private LogEventLevel _logLevel = LogEventLevel.Information;
+ ///
+ /// Sets the title of the engine window.
+ ///
+ /// The title to use for the engine window.
+ /// The current instance of for chaining.
public EngineBuilder Title(string parTitle)
{
_title = parTitle;
return this;
}
+ ///
+ /// Configures the engine to run in headless mode.
+ ///
+ /// Indicates whether to enable headless mode. Defaults to true.
+ /// The current instance of for chaining.
public EngineBuilder Headless(bool parHeadless = true)
{
_headless = parHeadless;
return this;
}
+ ///
+ /// Sets the width of the engine window.
+ ///
+ /// The width in pixels. Must be greater than zero.
+ /// The current instance of for chaining.
public EngineBuilder Width(int parWidth)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parWidth);
@@ -45,6 +108,11 @@ public sealed class EngineBuilder
return this;
}
+ ///
+ /// Sets the height of the engine window.
+ ///
+ /// The height in pixels. Must be greater than zero.
+ /// The current instance of for chaining.
public EngineBuilder Height(int parHeight)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parHeight);
@@ -53,36 +121,68 @@ public sealed class EngineBuilder
return this;
}
+ ///
+ /// Sets the folder path for assets used by the engine.
+ ///
+ /// The folder path containing asset files.
+ /// The current instance of for chaining.
public EngineBuilder AssetFolder(string parAssetFolder)
{
_assetFolder = parAssetFolder;
return this;
}
+ ///
+ /// Sets the folder path for data files used by the engine.
+ ///
+ /// The folder path containing data files.
+ /// The current instance of for chaining.
public EngineBuilder DataFolder(string parDataFolder)
{
_dataFolder = parDataFolder;
return this;
}
+ ///
+ /// Specifies the input handler to be used by the engine.
+ ///
+ /// A function that creates an input handler for the engine.
+ /// The current instance of for chaining.
public EngineBuilder InputHandler(Func parInputHandlerFunc)
{
_inputHandlerFunc = parInputHandlerFunc;
return this;
}
+ ///
+ /// Specifies the presenter to be used by the engine.
+ ///
+ /// A function that creates a presenter for the engine.
+ /// The current instance of for chaining.
public EngineBuilder Presenter(Func parPresenterFunc)
{
_presenterFunc = parPresenterFunc;
return this;
}
+ ///
+ /// Configures logging to output to the console.
+ ///
+ /// Indicates whether to enable console logging. Defaults to true.
+ /// The current instance of for chaining.
public EngineBuilder LogToConsole(bool parLogToConsole = true)
{
_logToConsole = parLogToConsole;
return this;
}
+ ///
+ /// Configures logging to output to a file.
+ ///
+ /// Indicates whether to enable file logging. Defaults to true.
+ /// The path of the log file. Cannot be null if file logging is enabled.
+ /// The current instance of for chaining.
+ /// Thrown if is null when is true.
public EngineBuilder LogToFile(bool parLogToFile = true, string? parLogFilePath = null)
{
if (parLogToFile && parLogFilePath == null)
@@ -95,12 +195,21 @@ public sealed class EngineBuilder
return this;
}
+ ///
+ /// Sets the minimum log level for logging.
+ ///
+ /// The minimum level of log events to capture.
+ /// The current instance of for chaining.
public EngineBuilder LogLevel(LogEventLevel parLogLevel)
{
_logLevel = parLogLevel;
return this;
}
+ ///
+ /// Builds and returns a new instance of the class based on the configured settings.
+ ///
+ /// A fully configured instance of .
public Engine Build()
{
var logger = BuildLogger();
@@ -121,6 +230,10 @@ public sealed class EngineBuilder
return engine;
}
+ ///
+ /// Configures and builds a logger based on the current logging settings.
+ ///
+ /// A configured instance of .
private Logger BuildLogger()
{
const string template =
diff --git a/Engine/src/Graphics/Buffer/IndexBuffer.cs b/Engine/src/Graphics/Buffer/IndexBuffer.cs
index 3873442..100076c 100644
--- a/Engine/src/Graphics/Buffer/IndexBuffer.cs
+++ b/Engine/src/Graphics/Buffer/IndexBuffer.cs
@@ -3,10 +3,21 @@ using Serilog;
namespace Engine.Graphics.Buffer;
+///
+/// Represents an OpenGL index buffer, used for storing indices for rendering.
+///
public class IndexBuffer : OpenGlObject
{
+ ///
+ /// The number of indices in the buffer.
+ ///
internal int Count { get; }
+ ///
+ /// Initializes a new index buffer with a specified number of elements.
+ ///
+ /// The number of indices the buffer will store.
+ /// Optional storage flags for the buffer.
public IndexBuffer(int parCount, BufferStorageFlags parFlags = BufferStorageFlags.None)
{
Count = parCount;
@@ -20,6 +31,11 @@ public class IndexBuffer : OpenGlObject
}
+ ///
+ /// Initializes a new index buffer with the provided data.
+ ///
+ /// The data to populate the buffer with.
+ /// Optional storage flags for the buffer.
public IndexBuffer(uint[] parData, BufferStorageFlags parFlags = BufferStorageFlags.None)
{
Count = parData.Length;
@@ -32,11 +48,21 @@ public class IndexBuffer : OpenGlObject
Log.Debug("Index buffer {Handle} created with {Count} elements", Handle, Count);
}
+ ///
+ /// Uploads data to the buffer starting at offset 0.
+ ///
+ /// The data to upload.
public void UploadData(uint[] parData)
{
UploadData(0, parData);
}
+ ///
+ /// Uploads data to the buffer at the specified offset.
+ ///
+ /// The offset (in elements) where data should be uploaded.
+ /// The data to upload.
+ /// Thrown if the offset is invalid or the data exceeds buffer size.
public void UploadData(int parOffset, uint[] parData)
{
if (parOffset < 0)
@@ -52,16 +78,19 @@ public class IndexBuffer : OpenGlObject
GL.NamedBufferSubData(Handle, parOffset, parData.Length * sizeof(uint), parData);
}
+ ///
internal override void Bind()
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
}
+ ///
internal override void Unbind()
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
}
+ ///
protected override void Destroy()
{
GL.DeleteBuffer(Handle);
diff --git a/Engine/src/Graphics/Buffer/Vertex/IVertex.cs b/Engine/src/Graphics/Buffer/Vertex/IVertex.cs
index ee7d3a4..6632b70 100644
--- a/Engine/src/Graphics/Buffer/Vertex/IVertex.cs
+++ b/Engine/src/Graphics/Buffer/Vertex/IVertex.cs
@@ -4,18 +4,38 @@ using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Buffer.Vertex;
+///
+/// Interface for a vertex structure used in graphics buffers.
+/// Provides methods for reflecting on vertex fields and checking their validity.
+///
public interface IVertex
{
+ ///
+ /// Retrieves the fields of a type implementing .
+ ///
+ /// The type to retrieve the fields for.
+ /// An ordered enumerable of for the fields in the type.
public static IOrderedEnumerable GetFields()
{
return GetFields(typeof(T));
}
+ ///
+ /// Retrieves the fields of a specified type implementing .
+ ///
+ /// The type to retrieve the fields for.
+ /// An ordered enumerable of for the fields in the type.
public static IOrderedEnumerable GetFields(Type parType)
{
return parType.GetFields(BindingFlags.Public | BindingFlags.Instance).OrderBy(parF => parF.MetadataToken);
}
+ ///
+ /// Validates if a type is a valid .
+ /// Checks if all fields are value types, have attributes, and match their size.
+ ///
+ /// The type to validate.
+ /// True if the type is valid, otherwise false.
public static bool IsValid(Type parType)
{
if (!parType.IsValueType || !parType.IsAssignableTo(typeof(IVertex)))
@@ -50,6 +70,11 @@ public interface IVertex
return totalSize == Marshal.SizeOf(parType);
}
+ ///
+ /// Gets the size of a vertex attribute based on its OpenGL type.
+ ///
+ /// The OpenGL type of the attribute.
+ /// The size of the attribute in bytes.
public static int AttributeSize(VertexAttribType parType)
{
return parType switch
diff --git a/Engine/src/Graphics/Buffer/Vertex/VertexAttribute.cs b/Engine/src/Graphics/Buffer/Vertex/VertexAttribute.cs
index 630af55..89888cd 100644
--- a/Engine/src/Graphics/Buffer/Vertex/VertexAttribute.cs
+++ b/Engine/src/Graphics/Buffer/Vertex/VertexAttribute.cs
@@ -2,14 +2,40 @@
namespace Engine.Graphics.Buffer.Vertex;
+///
+/// Attribute used to describe a vertex field.
+/// Provides details about the attribute's type, component count, normalization, and repetition.
+///
[AttributeUsage(AttributeTargets.Field)]
public class VertexAttribute : Attribute
{
+ ///
+ /// OpenGL type of the vertex attribute.
+ ///
public VertexAttribType Type { get; }
+
+ ///
+ /// Number of components in the vertex attribute.
+ ///
public int ComponentCount { get; }
+
+ ///
+ /// Whether the vertex attribute is normalized.
+ ///
public bool Normalized { get; }
+
+ ///
+ /// Number of times the vertex attribute is repeated.
+ ///
public int RepeatCount { get; }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The OpenGL type of the vertex attribute.
+ /// The number of components in the vertex attribute.
+ /// The repeat count for the vertex attribute.
+ /// Whether the attribute is normalized.
public VertexAttribute(VertexAttribType parType, int parComponentCount = 1, int parRepeatCount = 1,
bool parNormalized = false
)
diff --git a/Engine/src/Graphics/Buffer/VertexArray.cs b/Engine/src/Graphics/Buffer/VertexArray.cs
index 37aa18a..1abd00f 100644
--- a/Engine/src/Graphics/Buffer/VertexArray.cs
+++ b/Engine/src/Graphics/Buffer/VertexArray.cs
@@ -6,10 +6,19 @@ using Serilog;
namespace Engine.Graphics.Buffer;
+///
+/// Represents a vertex array object in OpenGL, managing vertex buffer bindings and configurations.
+///
public class VertexArray : OpenGlObject
{
+ ///
+ /// Stores the enabled attribute flags for this vertex array.
+ ///
private int _enabledAttributes;
+ ///
+ /// Initializes a new instance of the class, creating an OpenGL vertex array object.
+ ///
public VertexArray()
{
GL.CreateVertexArrays(1, out int handle);
@@ -18,6 +27,10 @@ public class VertexArray : OpenGlObject
Log.Debug("Vertex array {Handle} created", Handle);
}
+ ///
+ /// Binds an index buffer to this vertex array.
+ ///
+ /// The index buffer to bind.
public void BindIndexBuffer(IndexBuffer parBuffer)
{
GL.VertexArrayElementBuffer(Handle, parBuffer.Handle);
@@ -25,6 +38,13 @@ public class VertexArray : OpenGlObject
Log.Debug("Index buffer {Buffer} bound to vertex array {Handle}", parBuffer.Handle, Handle);
}
+ ///
+ /// Binds a vertex buffer to this vertex array and configures its vertex attributes.
+ ///
+ /// The type of the vertex buffer, which must implement the interface.
+ /// The vertex buffer to bind.
+ /// The binding index for the vertex buffer. Defaults to 0.
+ /// The divisor for instancing, which controls how often the vertex data is used. Defaults to 0.
public void BindVertexBuffer(VertexBuffer parBuffer, int parBindingIndex = 0, int parDivisor = 0)
where T : struct, IVertex
{
@@ -52,6 +72,13 @@ public class VertexArray : OpenGlObject
parBuffer.Handle, Handle, parBindingIndex, parDivisor);
}
+ ///
+ /// Configures a vertex attribute for a vertex array.
+ ///
+ /// The vertex attribute to configure.
+ /// The base location for the attribute.
+ /// The base offset for the attribute.
+ /// The binding index for the attribute.
private void SetupAttribute(VertexAttribute parAttribute, int parBaseLocation, int parBaseOffset, int parBindingIndex)
{
var size = parAttribute.ComponentCount * IVertex.AttributeSize(parAttribute.Type);
@@ -69,16 +96,19 @@ public class VertexArray : OpenGlObject
}
}
+ ///
internal override void Bind()
{
GL.BindVertexArray(Handle);
}
+ ///
internal override void Unbind()
{
GL.BindVertexArray(0);
}
+ ///
protected override void Destroy()
{
GL.DeleteVertexArray(Handle);
diff --git a/Engine/src/Graphics/Buffer/VertexBuffer.cs b/Engine/src/Graphics/Buffer/VertexBuffer.cs
index db85b13..6995606 100644
--- a/Engine/src/Graphics/Buffer/VertexBuffer.cs
+++ b/Engine/src/Graphics/Buffer/VertexBuffer.cs
@@ -5,13 +5,29 @@ using Serilog;
namespace Engine.Graphics.Buffer;
+///
+/// Represents an OpenGL vertex buffer for storing vertex data.
+///
+/// The vertex structure type implementing .
public class VertexBuffer : OpenGlObject
where T : struct, IVertex
{
+ ///
+ /// The number of vertices in the buffer.
+ ///
internal int Count { get; }
+ ///
+ /// The size of a single vertex in bytes.
+ ///
private readonly int _stride = Marshal.SizeOf();
+ ///
+ /// Initializes a new vertex buffer with a specified number of elements.
+ ///
+ /// The number of vertices the buffer will store.
+ /// Optional storage flags for the buffer.
+ /// Thrown if the type is not a valid vertex type or the count is invalid.
public VertexBuffer(int parCount, BufferStorageFlags parFlags = BufferStorageFlags.None)
{
if (!IVertex.IsValid(typeof(T)))
@@ -34,6 +50,12 @@ public class VertexBuffer : OpenGlObject
Log.Debug("Vertex buffer {Handle} created with {Count} elements of type {Type}", Handle, Count, typeof(T).Name);
}
+ ///
+ /// Initializes a new vertex buffer with the provided data.
+ ///
+ /// The data to populate the buffer with.
+ /// Optional storage flags for the buffer.
+ /// Thrown if the type is not a valid vertex type or the data is invalid.
public VertexBuffer(T[] parData, BufferStorageFlags parFlags = BufferStorageFlags.None)
{
if (!IVertex.IsValid(typeof(T)))
@@ -56,16 +78,32 @@ public class VertexBuffer : OpenGlObject
Log.Debug("Vertex buffer {Handle} created with {Count} elements of type {Type}", Handle, Count, typeof(T).Name);
}
+ ///
+ /// Uploads data to the buffer starting at offset 0.
+ ///
+ /// The data to upload.
public void UploadData(T[] parData)
{
UploadData(0, parData, parData.Length);
}
+ ///
+ /// Uploads data to the buffer starting at offset 0 with a specified count.
+ ///
+ /// The data to upload.
+ /// The number of elements to upload.
public void UploadData(T[] parData, int parCount)
{
UploadData(0, parData, parCount);
}
+ ///
+ /// Uploads data to the buffer at the specified offset.
+ ///
+ /// The offset (in elements) where data should be uploaded.
+ /// The data to upload.
+ /// The number of elements to upload.
+ /// Thrown if parameters are invalid or data exceeds buffer size.
public void UploadData(int parOffset, T[] parData, int parCount)
{
if (parOffset < 0)
@@ -91,16 +129,19 @@ public class VertexBuffer : OpenGlObject
GL.NamedBufferSubData(Handle, parOffset * _stride, parCount * _stride, parData);
}
+ ///
internal override void Bind()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
}
+ ///
internal override void Unbind()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
}
+ ///
protected override void Destroy()
{
GL.DeleteBuffer(Handle);
diff --git a/Engine/src/Graphics/Camera/ICamera.cs b/Engine/src/Graphics/Camera/ICamera.cs
index a4f42a1..a762226 100644
--- a/Engine/src/Graphics/Camera/ICamera.cs
+++ b/Engine/src/Graphics/Camera/ICamera.cs
@@ -2,9 +2,23 @@
namespace Engine.Graphics.Camera;
+///
+/// Defines the interface for camera functionality, including projection and view matrices.
+///
public interface ICamera
{
+ ///
+ /// The matrix representing the camera's view transformation.
+ ///
Matrix4 View { get; }
+
+ ///
+ /// The matrix representing the camera's projection transformation.
+ ///
Matrix4 Projection { get; }
+
+ ///
+ /// The dimensions of the screen in pixels.
+ ///
Vector2i ScreenSize { get; internal set; }
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Camera/ScreenspaceCamera.cs b/Engine/src/Graphics/Camera/ScreenspaceCamera.cs
index 2587f5d..f0bbcd5 100644
--- a/Engine/src/Graphics/Camera/ScreenspaceCamera.cs
+++ b/Engine/src/Graphics/Camera/ScreenspaceCamera.cs
@@ -2,9 +2,17 @@
namespace Engine.Graphics.Camera;
+///
+/// Represents a camera that uses a screenspace projection.
+///
public class ScreenspaceCamera : ICamera
{
+ ///
public Matrix4 View => Matrix4.Identity;
+
+ ///
public Matrix4 Projection => Matrix4.Identity;
+
+ ///
public Vector2i ScreenSize { get; set; }
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Debug.cs b/Engine/src/Graphics/Debug.cs
index 4fd7957..27643cc 100644
--- a/Engine/src/Graphics/Debug.cs
+++ b/Engine/src/Graphics/Debug.cs
@@ -6,31 +6,59 @@ using Serilog.Events;
namespace Engine.Graphics;
+///
+/// Provides debugging utilities for OpenGL and integrates with RenderDoc for frame capturing.
+///
internal static class Debug
{
+ ///
+ /// The RenderDoc API instance for capturing and debugging GPU frames.
+ ///
private static RenderDoc _renderDocApi;
+ ///
+ /// Configures OpenGL debugging and enables debug output.
+ ///
public static void Setup()
{
GL.Enable(EnableCap.DebugOutput);
GL.DebugMessageCallback(DebugCallback, IntPtr.Zero);
}
+ ///
+ /// Initializes RenderDoc support for capturing GPU frames.
+ ///
public static void InitializeRenderDoc()
{
RenderDoc.Load(out _renderDocApi);
}
+ ///
+ /// Starts a new RenderDoc frame capture.
+ ///
public static void RenderDocStartFrame()
{
// _renderDocApi.API.StartFrameCapture(IntPtr.Zero, IntPtr.Zero);
}
+ ///
+ /// Ends the current RenderDoc frame capture.
+ ///
public static void RenderDocEndFrame()
{
// _renderDocApi.API.EndFrameCapture(IntPtr.Zero, IntPtr.Zero);
}
+ ///
+ /// Callback for handling OpenGL debug messages.
+ ///
+ /// The source of the debug message.
+ /// The type of the debug message.
+ /// The identifier of the debug message.
+ /// The severity of the debug message.
+ /// The length of the debug message string.
+ /// A pointer to the debug message string.
+ /// A pointer to user-defined data.
private static void DebugCallback(DebugSource parSource, DebugType parType, int parId, DebugSeverity parSeverity,
int parLength,
IntPtr parMessage, IntPtr parUserParam)
@@ -73,6 +101,11 @@ internal static class Debug
);
}
+ ///
+ /// Maps OpenGL debug severity levels to Serilog logging levels.
+ ///
+ /// The severity of the OpenGL debug message.
+ /// The corresponding Serilog log level.
private static LogEventLevel GetLogLevel(DebugSeverity parSeverity)
{
return parSeverity switch
diff --git a/Engine/src/Graphics/Framebuffer/Framebuffer.cs b/Engine/src/Graphics/Framebuffer/Framebuffer.cs
index be9563f..f4c0233 100644
--- a/Engine/src/Graphics/Framebuffer/Framebuffer.cs
+++ b/Engine/src/Graphics/Framebuffer/Framebuffer.cs
@@ -5,8 +5,15 @@ using Serilog;
namespace Engine.Graphics.Framebuffer;
+///
+/// Represents an OpenGL framebuffer object, which manages a collection of attachments,
+/// such as color and depth buffers, and provides functionality for binding, resizing, and checking status.
+///
public class Framebuffer : OpenGlObject
{
+ ///
+ /// The width of the framebuffer.
+ ///
public int Width
{
get => _width;
@@ -18,6 +25,9 @@ public class Framebuffer : OpenGlObject
}
}
+ ///
+ /// The height of the framebuffer.
+ ///
public int Height
{
get => _height;
@@ -29,13 +39,32 @@ public class Framebuffer : OpenGlObject
}
}
+ ///
+ /// Retrieves the internal texture attached to the framebuffer at the color attachment point.
+ ///
internal Texture.Texture? TextureInternal => GetAttachment(FramebufferAttachment.ColorAttachment0);
+ ///
+ /// A collection of framebuffer attachments, mapped by their attachment point.
+ ///
private readonly IDictionary _attachments;
+ ///
+ /// The width of the framebuffer.
+ ///
private int _width;
+
+ ///
+ /// The height of the framebuffer.
+ ///
private int _height;
+ ///
+ /// Initializes a new instance of the class with the specified width, height, and attachments.
+ ///
+ /// The width of the framebuffer.
+ /// The height of the framebuffer.
+ /// A dictionary of attachments to associate with the framebuffer.
internal Framebuffer(int parWidth, int parHeight,
IDictionary parAttachments)
{
@@ -58,11 +87,23 @@ public class Framebuffer : OpenGlObject
}
}
+ ///
+ /// Creates a builder for creating a new framebuffer with the specified width and height.
+ ///
+ /// The width of the framebuffer.
+ /// The height of the framebuffer.
+ /// A that can be used to customize the framebuffer.
public static FramebufferBuilder Builder(int parWidth, int parHeight)
{
return new FramebufferBuilder(parWidth, parHeight);
}
+ ///
+ /// Retrieves the attachment of the specified type from the framebuffer.
+ ///
+ /// The type of the attachment to retrieve.
+ /// The attachment point to retrieve the attachment from.
+ /// The attachment if found, otherwise null.
internal T? GetAttachment(FramebufferAttachment parAttachment) where T : IFramebufferAttachment
{
if (!_attachments.TryGetValue(parAttachment, out var attachmentValue))
@@ -78,6 +119,11 @@ public class Framebuffer : OpenGlObject
return default;
}
+ ///
+ /// Resizes the framebuffer and all its attachments to the specified width and height.
+ ///
+ /// The new width of the framebuffer.
+ /// The new height of the framebuffer.
public void Resize(int parWidth, int parHeight)
{
if (Width == parWidth && Height == parHeight)
@@ -96,16 +142,19 @@ public class Framebuffer : OpenGlObject
Log.Debug("Framebuffer {Handle} resized to {Width}x{Height}", Handle, parWidth, parHeight);
}
+ ///
internal override void Bind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);
}
+ ///
internal override void Unbind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
+ ///
protected override void Destroy()
{
GL.DeleteFramebuffer(Handle);
diff --git a/Engine/src/Graphics/Framebuffer/FramebufferBuilder.cs b/Engine/src/Graphics/Framebuffer/FramebufferBuilder.cs
index 0f8c0ef..cebbc4c 100644
--- a/Engine/src/Graphics/Framebuffer/FramebufferBuilder.cs
+++ b/Engine/src/Graphics/Framebuffer/FramebufferBuilder.cs
@@ -4,13 +4,52 @@ using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Framebuffer;
-public class FramebufferBuilder(int parWidth, int parHeight)
+///
+/// A builder class used to construct framebuffers with custom attachments, such as color and depth buffers.
+///
+public class FramebufferBuilder
{
+ ///
+ /// The width of the framebuffer.
+ ///
+ private readonly int _width;
+
+ ///
+ /// The height of the framebuffer.
+ ///
+ private readonly int _height;
+
+ ///
+ /// A list of attachments to be added to the framebuffer.
+ ///
private readonly List _attachments = [];
+
+ ///
+ /// A set of used attachment points.
+ ///
private readonly HashSet _usedAttachments = [];
+ ///
+ /// The current color attachment point.
+ ///
private FramebufferAttachment _currentColorAttachment = FramebufferAttachment.ColorAttachment0;
+ ///
+ /// Initializes a new instance of the class with the specified width and height.
+ ///
+ /// The width of the framebuffer.
+ /// The height of the framebuffer.
+ public FramebufferBuilder(int parWidth, int parHeight)
+ {
+ _width = parWidth;
+ _height = parHeight;
+ }
+
+ ///
+ /// Adds a color attachment to the framebuffer.
+ ///
+ /// The pixel format to use for the color attachment.
+ /// The builder instance for method chaining.
public FramebufferBuilder AddColorAttachment()
where T : struct, IPixel
{
@@ -30,6 +69,10 @@ public class FramebufferBuilder(int parWidth, int parHeight)
});
}
+ ///
+ /// Adds a depth attachment to the framebuffer.
+ ///
+ /// The builder instance for method chaining.
public FramebufferBuilder AddDepthAttachment()
{
return AddAttachment(new RenderbufferAttachmentSpecification
@@ -39,6 +82,26 @@ public class FramebufferBuilder(int parWidth, int parHeight)
});
}
+ ///
+ /// Builds the framebuffer based on the current configuration.
+ ///
+ /// A new instance.
+ public Framebuffer Build()
+ {
+ var attachments = _attachments
+ .ToDictionary(
+ parAttachment => parAttachment.FramebufferAttachment,
+ parAttachment => parAttachment.Create(_width, _height)
+ );
+
+ return new Framebuffer(_width, _height, attachments);
+ }
+
+ ///
+ /// Adds a custom attachment to the framebuffer.
+ ///
+ /// The attachment specification to add.
+ /// The builder instance for method chaining.
private FramebufferBuilder AddAttachment(AttachmentSpecification parAttachment)
{
if (_usedAttachments.Contains(parAttachment.FramebufferAttachment))
@@ -53,43 +116,67 @@ public class FramebufferBuilder(int parWidth, int parHeight)
return this;
}
- public Framebuffer Build()
- {
- var attachments = _attachments
- .ToDictionary(
- parAttachment => parAttachment.FramebufferAttachment,
- parAttachment => parAttachment.Create(parWidth, parHeight)
- );
-
- return new Framebuffer(parWidth, parHeight, attachments);
- }
-
+ ///
+ /// Represents a specification for a texture attachment in a framebuffer.
+ ///
private class TextureAttachmentSpecification : AttachmentSpecification
{
+ ///
+ /// The pixel format for the texture attachment.
+ ///
public PixelFormat PixelFormat { get; init; }
+
+ ///
+ /// The pixel type for the texture attachment.
+ ///
public PixelType PixelType { get; init; }
+
+ ///
+ /// The internal format for the texture attachment.
+ ///
public PixelInternalFormat PixelInternalFormat { get; init; }
+ ///
public override DynamicTexture Create(int parWidth, int parHeight)
{
return new DynamicTexture(parWidth, parHeight, PixelFormat, PixelType, PixelInternalFormat);
}
}
+ ///
+ /// Represents a specification for a renderbuffer attachment in a framebuffer.
+ ///
private class RenderbufferAttachmentSpecification : AttachmentSpecification
{
+ ///
+ /// The storage format for the renderbuffer attachment.
+ ///
public RenderbufferStorage RenderbufferStorage { get; init; }
+ ///
public override Renderbuffer Create(int parWidth, int parHeight)
{
return new Renderbuffer(parWidth, parHeight, RenderbufferStorage);
}
}
+ ///
+ /// Represents a base class for framebuffer attachment specifications.
+ /// Provides common functionality for creating attachments like textures or renderbuffers.
+ ///
private abstract class AttachmentSpecification
{
+ ///
+ /// The attachment point for the framebuffer.
+ ///
public FramebufferAttachment FramebufferAttachment { get; init; }
+ ///
+ /// Creates a new attachment for the framebuffer based on the specific type of attachment.
+ ///
+ /// The width of the attachment.
+ /// The height of the attachment.
+ /// An instance of that represents the created attachment.
public abstract IFramebufferAttachment Create(int parWidth, int parHeight);
}
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Framebuffer/IFramebufferAttachment.cs b/Engine/src/Graphics/Framebuffer/IFramebufferAttachment.cs
index 7533667..eab44b8 100644
--- a/Engine/src/Graphics/Framebuffer/IFramebufferAttachment.cs
+++ b/Engine/src/Graphics/Framebuffer/IFramebufferAttachment.cs
@@ -2,11 +2,27 @@
namespace Engine.Graphics.Framebuffer;
+///
+/// Interface representing a framebuffer attachment, providing methods to attach, resize, and manage the attachment's OpenGL handle.
+///
internal interface IFramebufferAttachment
{
+ ///
+ /// The handle that uniquely identifies the OpenGL object.
+ ///
int Handle { get; }
+ ///
+ /// Resizes the framebuffer attachment to the specified width and height.
+ ///
+ /// The new width of the framebuffer attachment.
+ /// The new height of the framebuffer attachment.
void Resize(int parWidth, int parHeight);
+ ///
+ /// Attaches the framebuffer attachment to a specified framebuffer and attachment point.
+ ///
+ /// The framebuffer to attach to.
+ /// The attachment point of the framebuffer to attach to.
void Attach(Framebuffer parFramebuffer, FramebufferAttachment parAttachment);
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Framebuffer/Renderbuffer.cs b/Engine/src/Graphics/Framebuffer/Renderbuffer.cs
index 87db622..b51f17b 100644
--- a/Engine/src/Graphics/Framebuffer/Renderbuffer.cs
+++ b/Engine/src/Graphics/Framebuffer/Renderbuffer.cs
@@ -2,13 +2,32 @@
namespace Engine.Graphics.Framebuffer;
+///
+/// Represents a renderbuffer object in OpenGL, which can be used as an attachment to a framebuffer.
+///
public class Renderbuffer : OpenGlObject, IFramebufferAttachment
{
+ ///
+ /// The width of the renderbuffer.
+ ///
public int Width { get; private set; }
+
+ ///
+ /// The height of the renderbuffer.
+ ///
public int Height { get; private set; }
+ ///
+ /// The format of the renderbuffer (e.g., depth, stencil, or color).
+ ///
private readonly RenderbufferStorage _format;
+ ///
+ /// Initializes a new instance of the class with specified dimensions and format.
+ ///
+ /// The width of the renderbuffer.
+ /// The height of the renderbuffer.
+ /// The format of the renderbuffer (storage format).
public Renderbuffer(int parWidth, int parHeight, RenderbufferStorage parFormat)
{
Width = parWidth;
@@ -21,6 +40,7 @@ public class Renderbuffer : OpenGlObject, IFramebufferAttachment
GL.NamedRenderbufferStorage(Handle, _format, Width, Height);
}
+ ///
public void Resize(int parWidth, int parHeight)
{
if (Width == parWidth && Height == parHeight)
@@ -34,21 +54,25 @@ public class Renderbuffer : OpenGlObject, IFramebufferAttachment
GL.NamedRenderbufferStorage(Handle, _format, Width, Height);
}
+ ///
public void Attach(Framebuffer parFramebuffer, FramebufferAttachment parAttachment)
{
GL.NamedFramebufferRenderbuffer(parFramebuffer.Handle, parAttachment, RenderbufferTarget.Renderbuffer, Handle);
}
+ ///
internal override void Bind()
{
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Handle);
}
+ ///
internal override void Unbind()
{
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
}
+ ///
protected override void Destroy()
{
GL.DeleteRenderbuffer(Handle);
diff --git a/Engine/src/Graphics/GenericRenderer.cs b/Engine/src/Graphics/GenericRenderer.cs
index 8cdf3a2..c019ab7 100644
--- a/Engine/src/Graphics/GenericRenderer.cs
+++ b/Engine/src/Graphics/GenericRenderer.cs
@@ -7,21 +7,62 @@ using OpenTK.Mathematics;
namespace Engine.Graphics;
+///
+/// A generic renderer that supports rendering quads, meshes, and text.
+///
public class GenericRenderer : IRenderer
{
+ ///
+ /// Provides functionality to render quads.
+ ///
public QuadRenderer QuadRenderer => _quadRenderer ??= new QuadRenderer(_engine, 1024 * 8);
+
+ ///
+ /// Provides functionality to render any type of mesh.
+ ///
public AnyMeshRenderer AnyMeshRenderer => _anyMeshRenderer ??= new AnyMeshRenderer(_engine, 1024);
+
+ ///
+ /// Provides functionality to render text.
+ ///
public TextRenderer TextRenderer => _textRenderer ??= new TextRenderer(_engine, 1024 * 8);
+ ///
+ /// The framebuffer used for rendering.
+ ///
internal readonly Framebuffer.Framebuffer _framebuffer;
+ ///
+ /// The engine instance associated with this renderer.
+ ///
private readonly Engine _engine;
+ ///
+ /// The quad renderer instance, lazily initialized.
+ ///
private QuadRenderer? _quadRenderer;
+
+ ///
+ /// The mesh renderer instance, lazily initialized.
+ ///
private AnyMeshRenderer? _anyMeshRenderer;
+
+ ///
+ /// The text renderer instance, lazily initialized.
+ ///
private TextRenderer? _textRenderer;
+
+ ///
+ /// Indicates whether the frame has been started.
+ ///
private bool _frameStarted;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The engine instance to use for rendering.
+ /// The initial width of the framebuffer.
+ /// The initial height of the framebuffer.
public GenericRenderer(Engine parEngine, int parWidth, int parHeight)
{
_engine = parEngine;
@@ -32,11 +73,13 @@ public class GenericRenderer : IRenderer
.Build();
}
+ ///
public void StartFrame()
{
_frameStarted = true;
}
+ ///
public void EndFrame(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix)
{
if (!_frameStarted)
@@ -72,6 +115,7 @@ public class GenericRenderer : IRenderer
_frameStarted = false;
}
+ ///
public void Resize(int parWidth, int parHeight)
{
_framebuffer.Resize(parWidth, parHeight);
diff --git a/Engine/src/Graphics/IPresenter.cs b/Engine/src/Graphics/IPresenter.cs
index 30e9a53..b05c827 100644
--- a/Engine/src/Graphics/IPresenter.cs
+++ b/Engine/src/Graphics/IPresenter.cs
@@ -4,14 +4,39 @@ using OpenTK.Windowing.Common;
namespace Engine.Graphics;
+///
+/// Defines an interface for a presenter that handles updates, rendering, and presentation.
+///
public interface IPresenter : IUpdate, IRender
{
- public event Action Resize;
+ ///
+ /// Occurs when the presenter is resized.
+ ///
+ public event Action OnResize;
+ ///
+ /// Gets the current width of the presenter.
+ ///
public int Width { get; }
+
+ ///
+ /// Gets the current height of the presenter.
+ ///
public int Height { get; }
+
+ ///
+ /// Gets a value indicating whether the presenter is exiting.
+ ///
public bool IsExiting { get; }
+ ///
+ /// Presents a texture to the rendering surface.
+ ///
+ /// The texture to present.
public void Present(IConstTexture parTexture);
+
+ ///
+ /// Signals the presenter to exit.
+ ///
public void Exit();
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/IRenderer.cs b/Engine/src/Graphics/IRenderer.cs
index fef02c3..1c9f9f6 100644
--- a/Engine/src/Graphics/IRenderer.cs
+++ b/Engine/src/Graphics/IRenderer.cs
@@ -2,10 +2,27 @@
namespace Engine.Graphics;
+///
+/// Interface defining the essential functionality for a renderer.
+///
internal interface IRenderer
{
+ ///
+ /// Prepares the renderer for a new frame.
+ ///
public void StartFrame();
+
+ ///
+ /// Finalizes the rendering pipeline for the current frame.
+ ///
+ /// The projection matrix to use for rendering.
+ /// The view matrix to use for rendering.
public void EndFrame(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix);
+ ///
+ /// Resizes the renderer to accommodate changes in viewport dimensions.
+ ///
+ /// The new width of the viewport.
+ /// The new height of the viewport.
public void Resize(int parWidth, int parHeight);
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/OpenGLObject.cs b/Engine/src/Graphics/OpenGLObject.cs
index 97a6266..5459f7b 100644
--- a/Engine/src/Graphics/OpenGLObject.cs
+++ b/Engine/src/Graphics/OpenGLObject.cs
@@ -2,15 +2,34 @@
namespace Engine.Graphics;
+///
+/// Represents an abstract OpenGL object with a handle for managing GPU resources.
+///
public abstract class OpenGlObject
{
+ ///
+ /// The handle that uniquely identifies the OpenGL object.
+ ///
public int Handle { get; protected set; } = -1;
+ ///
+ /// Binds the OpenGL object for rendering or other operations.
+ ///
internal abstract void Bind();
+
+ ///
+ /// Unbinds the OpenGL object, restoring the previous state.
+ ///
internal abstract void Unbind();
+ ///
+ /// Releases the GPU resources associated with the OpenGL object.
+ ///
protected abstract void Destroy();
+ ///
+ /// Finalizer to ensure the OpenGL object is destroyed and resources are freed.
+ ///
~OpenGlObject()
{
if (Handle == -1)
diff --git a/Engine/src/Graphics/Pipeline/RenderLayer.cs b/Engine/src/Graphics/Pipeline/RenderLayer.cs
index d70df6f..d6cf375 100644
--- a/Engine/src/Graphics/Pipeline/RenderLayer.cs
+++ b/Engine/src/Graphics/Pipeline/RenderLayer.cs
@@ -1,32 +1,64 @@
namespace Engine.Graphics.Pipeline;
+///
+/// Represents a render layer in the rendering pipeline, providing a way to order and compare render layers.
+///
public class RenderLayer : IComparable
{
+ ///
+ /// The default render layer, with a priority of 0.
+ ///
public static readonly RenderLayer DEFAULT = new("default", 0);
+
+ ///
+ /// The overlay render layer, with a priority of 1.
+ ///
public static readonly RenderLayer OVERLAY = new("overlay", 1);
+
+ ///
+ /// The HUD render layer, with a priority of 2.
+ ///
public static readonly RenderLayer HUD = new("hud", 2);
+
+ ///
+ /// A read-only list of all render layers.
+ ///
public static readonly IReadOnlyList ALL = new List { DEFAULT, OVERLAY, HUD }.AsReadOnly();
+ ///
+ /// The name of the render layer.
+ ///
public string Name { get; }
+ ///
+ /// The priority of the render layer.
+ ///
private readonly int _order;
+ ///
+ /// Initializes a new instance of the class with the specified name and priority.
+ ///
+ /// The name of the render layer.
+ /// The priority of the render layer.
private RenderLayer(string parName, int parOrder)
{
Name = parName;
_order = parOrder;
}
+ ///
public int CompareTo(RenderLayer? parOther)
{
return parOther == null ? 1 : _order.CompareTo(parOther._order);
}
+ ///
public override string ToString()
{
return Name;
}
+ ///
public override int GetHashCode()
{
return Name.GetHashCode();
diff --git a/Engine/src/Graphics/Pixel/IPixel.cs b/Engine/src/Graphics/Pixel/IPixel.cs
index 9c4e1b4..c0a2046 100644
--- a/Engine/src/Graphics/Pixel/IPixel.cs
+++ b/Engine/src/Graphics/Pixel/IPixel.cs
@@ -2,11 +2,29 @@ using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Pixel;
+///
+/// Defines the basic structure for a pixel type, which includes information
+/// about the pixel's format, type, internal format, and sized internal format.
+///
public interface IPixel
{
- PixelFormat Format { get; }
- PixelType Type { get; }
+ ///
+ /// The format of the pixel (e.g., Red, RGB, RGBA).
+ ///
+ public PixelFormat Format { get; }
- PixelInternalFormat InternalFormat { get; }
- SizedInternalFormat SizedInternalFormat { get; }
+ ///
+ /// The type of the pixel data (e.g., UnsignedByte).
+ ///
+ public PixelType Type { get; }
+
+ ///
+ /// The internal format for the pixel (e.g., R8, RGB8, etc.).
+ ///
+ public PixelInternalFormat InternalFormat { get; }
+
+ ///
+ /// The sized internal format for the pixel (e.g., R8, RGB8, etc.).
+ ///
+ public SizedInternalFormat SizedInternalFormat { get; }
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Pixel/R8.cs b/Engine/src/Graphics/Pixel/R8.cs
index 751cc38..1eb42ff 100644
--- a/Engine/src/Graphics/Pixel/R8.cs
+++ b/Engine/src/Graphics/Pixel/R8.cs
@@ -3,14 +3,27 @@ using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Pixel;
+///
+/// Represents a single-channel red pixel with an 8-bit format.
+/// Implements the interface for defining pixel properties.
+///
[StructLayout(LayoutKind.Sequential)]
public struct R8 : IPixel
{
+ ///
public PixelFormat Format => PixelFormat.Red;
+
+ ///
public PixelType Type => PixelType.UnsignedByte;
+ ///
public PixelInternalFormat InternalFormat => PixelInternalFormat.R8;
+
+ ///
public SizedInternalFormat SizedInternalFormat => SizedInternalFormat.R8;
+ ///
+ /// The red channel of the pixel.
+ ///
public byte R;
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Pixel/Rgb8.cs b/Engine/src/Graphics/Pixel/Rgb8.cs
index fd40fa9..1a4116d 100644
--- a/Engine/src/Graphics/Pixel/Rgb8.cs
+++ b/Engine/src/Graphics/Pixel/Rgb8.cs
@@ -6,15 +6,33 @@ namespace Engine.Graphics.Pixel;
[StructLayout(LayoutKind.Sequential)]
public struct Rgb8 : IPixel
{
+ ///
public PixelFormat Format => PixelFormat.Rgb;
+
+ ///
public PixelType Type => PixelType.UnsignedByte;
+ ///
public PixelInternalFormat InternalFormat => PixelInternalFormat.Rgb8;
+
+ ///
public SizedInternalFormat SizedInternalFormat => SizedInternalFormat.Rgb8;
+ ///
+ /// The red channel of the pixel.
+ ///
public byte R;
+
+ ///
+ /// The green channel of the pixel.
+ ///
public byte G;
+
+ ///
+ /// The blue channel of the pixel.
+ ///
public byte B;
+ ///
public override string ToString() => $"{R}, {G}, {B}";
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Pixel/Rgba8.cs b/Engine/src/Graphics/Pixel/Rgba8.cs
index 437af22..49bb7e9 100644
--- a/Engine/src/Graphics/Pixel/Rgba8.cs
+++ b/Engine/src/Graphics/Pixel/Rgba8.cs
@@ -3,19 +3,45 @@ using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Pixel;
+///
+/// Represents a four-channel RGBA pixel with an 8-bit format for each channel.
+/// Implements the interface for defining pixel properties.
+///
[StructLayout(LayoutKind.Sequential)]
public struct Rgba8 : IPixel
{
+ ///
public PixelFormat Format => PixelFormat.Rgba;
+
+ ///
public PixelType Type => PixelType.UnsignedByte;
+ ///
public PixelInternalFormat InternalFormat => PixelInternalFormat.Rgba8;
+
+ ///
public SizedInternalFormat SizedInternalFormat => SizedInternalFormat.Rgba8;
+ ///
+ /// The red channel of the pixel.
+ ///
public byte R;
+
+ ///
+ /// The green channel of the pixel.
+ ///
public byte G;
+
+ ///
+ /// The blue channel of the pixel.
+ ///
public byte B;
+
+ ///
+ /// The alpha channel of the pixel.
+ ///
public byte A;
+ ///
public override string ToString() => $"{R}, {G}, {B}, {A}";
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Render/InstancedRenderer.cs b/Engine/src/Graphics/Render/InstancedRenderer.cs
index c03e729..a167ef6 100644
--- a/Engine/src/Graphics/Render/InstancedRenderer.cs
+++ b/Engine/src/Graphics/Render/InstancedRenderer.cs
@@ -6,22 +6,70 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render;
+///
+/// Base class for rendering vertices with support for instancing.
+/// This class is generic, allowing customization for the common vertex type
+/// and the instance-specific vertex type .
+///
+/// The type of the common vertex, must implement .
+/// The type of the instance vertex, must implement .
public abstract class InstancedRenderer
where C : struct, IVertex
where I : struct, IVertex
{
+ ///
+ /// The number of instances that can be rendered.
+ ///
protected readonly int _instanceCount;
+
+ ///
+ /// The array of instance vertices, each vertex is of type .
+ ///
protected readonly I[] _instanceVertices;
+ ///
+ /// The count of instances that are queued for rendering.
+ ///
protected int _queuedInstanceCount;
+ ///
+ /// The type of primitive to be rendered (e.g., triangles, lines).
+ ///
private readonly PrimitiveType _primitiveType;
+
+ ///
+ /// The shader program used for rendering.
+ ///
private readonly Program _program;
+
+ ///
+ /// The index buffer used for the rendering of indexed primitives.
+ ///
private readonly IndexBuffer _indexBuffer;
+
+ ///
+ /// The buffer containing the common vertex data, of type .
+ ///
private readonly VertexBuffer _commonVertexBuffer;
+
+ ///
+ /// The buffer containing the instance-specific vertex data, of type .
+ ///
private readonly VertexBuffer _instanceVertexBuffer;
+
+ ///
+ /// The vertex array object that binds all the buffers for rendering.
+ ///
private readonly VertexArray _vertexArray;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type of primitive to be rendered.
+ /// The total number of instances to be rendered.
+ /// An array of indices for indexed rendering.
+ /// An array of instance-specific vertex data.
+ /// The shader program to use for rendering.
protected InstancedRenderer(PrimitiveType parPrimitiveType, int parInstanceCount,
uint[] parIndexBuffer, C[] parInstanceBuffer,
Program parProgram)
@@ -43,6 +91,11 @@ public abstract class InstancedRenderer
_vertexArray.BindVertexBuffer(_instanceVertexBuffer, 1, 1);
}
+ ///
+ /// Renders the instanced objects with the provided projection and view matrices.
+ ///
+ /// The projection matrix to be used in the shader.
+ /// The view matrix to be used in the shader.
public void Render(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix)
{
if (_queuedInstanceCount <= 0)
@@ -67,15 +120,26 @@ public abstract class InstancedRenderer
_queuedInstanceCount);
}
+ ///
+ /// Resets the renderer, clearing the queued instance count.
+ ///
public virtual void Reset()
{
_queuedInstanceCount = 0;
}
+ ///
+ /// Allows derived classes to set additional uniforms for the shader program.
+ ///
+ /// The shader program to set additional uniforms for.
protected virtual void SetAdditionalUniforms(Program parProgram)
{
}
+ ///
+ /// Determines whether the instance data has changed and needs to be uploaded to the GPU.
+ ///
+ /// true if the data has changed; otherwise, false.
protected virtual bool DataChanged()
{
return true;
diff --git a/Engine/src/Graphics/Render/Mesh/AnyMeshRenderer.cs b/Engine/src/Graphics/Render/Mesh/AnyMeshRenderer.cs
index 08075d7..aec0807 100644
--- a/Engine/src/Graphics/Render/Mesh/AnyMeshRenderer.cs
+++ b/Engine/src/Graphics/Render/Mesh/AnyMeshRenderer.cs
@@ -3,13 +3,50 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Mesh;
-public class AnyMeshRenderer(Engine parEngine, int parMaxInstanceCount)
+///
+/// A renderer class that manages multiple meshes and delegates rendering to individual mesh renderers.
+/// Handles batching of mesh instances and ensures that only the necessary mesh renderers are created.
+///
+public class AnyMeshRenderer
{
+ ///
+ /// A dictionary that maps each mesh to its corresponding .
+ ///
private readonly Dictionary _meshRenderers = new();
+
+ ///
+ /// A hash set that tracks the meshes that were rendered in the current frame.
+ ///
private readonly HashSet _frameMeshes = [];
- private readonly Program _program = parEngine.EngineResourceManager.Load("shader/mesh");
+ ///
+ /// The shader program used for rendering meshes.
+ ///
+ private readonly Program _program;
+ ///
+ /// The maximum number of instances that can be rendered in a single frame.
+ ///
+ private readonly int _maxInstanceCount;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The engine used to load resources.
+ /// The maximum number of instances to render per frame.
+ public AnyMeshRenderer(Engine parEngine, int parMaxInstanceCount)
+ {
+ _maxInstanceCount = parMaxInstanceCount;
+ _program = parEngine.EngineResourceManager.Load("shader/mesh");
+ }
+
+ ///
+ /// Commits an instance of a mesh to the renderer, adding it to the render queue with the specified model matrix and optional texture.
+ /// If the mesh is not already being tracked, a new will be created for it.
+ ///
+ /// The mesh to render.
+ /// The model transformation matrix to apply to the mesh.
+ /// An optional texture to apply to the mesh. If null, no texture is applied.
public void Commit(Asset.Mesh.Mesh parMesh, Matrix4 parModelMatrix, Texture.Texture? parAlbedo = null)
{
if (_meshRenderers.TryGetValue(parMesh, out var meshRenderer))
@@ -18,7 +55,7 @@ public class AnyMeshRenderer(Engine parEngine, int parMaxInstanceCount)
}
else
{
- var newMeshRenderer = new MeshRenderer(parMesh, parMaxInstanceCount, _program);
+ var newMeshRenderer = new MeshRenderer(parMesh, _maxInstanceCount, _program);
newMeshRenderer.Commit(parModelMatrix, parAlbedo);
_meshRenderers.Add(parMesh, newMeshRenderer);
@@ -27,6 +64,11 @@ public class AnyMeshRenderer(Engine parEngine, int parMaxInstanceCount)
_frameMeshes.Add(parMesh);
}
+ ///
+ /// Renders all queued mesh instances by calling the method for each mesh renderer.
+ ///
+ /// The projection matrix to use for rendering.
+ /// The view matrix to use for rendering.
public void Render(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix)
{
foreach (var meshRenderer in _meshRenderers.Values)
@@ -35,6 +77,9 @@ public class AnyMeshRenderer(Engine parEngine, int parMaxInstanceCount)
}
}
+ ///
+ /// Resets the state of the mesh renderers and removes any meshes that were not rendered in the current frame.
+ ///
public void Reset()
{
foreach (var meshRenderer in _meshRenderers.Values)
diff --git a/Engine/src/Graphics/Render/Mesh/MeshInstanceVertex.cs b/Engine/src/Graphics/Render/Mesh/MeshInstanceVertex.cs
index 08abd62..c777764 100644
--- a/Engine/src/Graphics/Render/Mesh/MeshInstanceVertex.cs
+++ b/Engine/src/Graphics/Render/Mesh/MeshInstanceVertex.cs
@@ -4,11 +4,23 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Mesh;
+///
+/// Represents an instance vertex structure for a mesh.
+/// This vertex structure includes texture ID and model matrix.
+///
public struct MeshInstanceVertex : IVertex
{
+ ///
+ /// The texture ID of the vertex.
+ ///
[Vertex(VertexAttribType.Int)] public int _textureId;
+
+ ///
+ /// The model matrix of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4, 4)] public Matrix4 _modelMatrix;
+ ///
public override int GetHashCode()
{
return HashCode.Combine(_textureId, _modelMatrix);
diff --git a/Engine/src/Graphics/Render/Mesh/MeshRenderer.cs b/Engine/src/Graphics/Render/Mesh/MeshRenderer.cs
index 298608e..975268a 100644
--- a/Engine/src/Graphics/Render/Mesh/MeshRenderer.cs
+++ b/Engine/src/Graphics/Render/Mesh/MeshRenderer.cs
@@ -5,21 +5,53 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Mesh;
-public class MeshRenderer(Asset.Mesh.Mesh parMesh, int parInstanceCount, Program parProgram)
- : InstancedRenderer(
- PrimitiveType.Triangles,
- parInstanceCount,
- parMesh.Indices.ToArray(),
- parMesh.Vertices.ToArray(),
- parProgram
- )
+///
+/// A renderer class for rendering meshes using instancing.
+/// Handles the instancing process for meshes, including texture binding and model transformations.
+///
+public class MeshRenderer : InstancedRenderer
{
+ ///
+ /// Maps textures to texture units with a limit of 16 texture units.
+ ///
private readonly TextureUnitMap _textureUnitMap = new(16);
+
+ ///
+ /// Stores the texture unit indices used for binding textures.
+ ///
private readonly int[] _textureUnitIndices = new int[16];
+ ///
+ /// Stores the hash of the current frame, used for detecting changes in instance data.
+ ///
private int _frameHash;
+
+ ///
+ /// Stores the hash of the previous frame.
+ ///
private int _previousHash;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The mesh to render.
+ /// The number of instances to render.
+ /// The shader program to use for rendering the mesh.
+ public MeshRenderer(Asset.Mesh.Mesh parMesh, int parInstanceCount, Program parProgram)
+ : base(
+ PrimitiveType.Triangles, parInstanceCount,
+ parMesh.Indices.ToArray(),
+ parMesh.Vertices.ToArray(),
+ parProgram
+ )
+ {
+ }
+
+ ///
+ /// Commits an instance to the renderer, adding it to the queue with the specified model matrix and optional texture.
+ ///
+ /// The model transformation matrix for this instance.
+ /// An optional texture to apply to the mesh. If null, no texture is applied.
public void Commit(Matrix4 parModelMatrix, Texture.Texture? parTexture = null)
{
if (_queuedInstanceCount >= _instanceCount)
@@ -41,6 +73,16 @@ public class MeshRenderer(Asset.Mesh.Mesh parMesh, int parInstanceCount, Program
_queuedInstanceCount++;
}
+ ///
+ public override void Reset()
+ {
+ base.Reset();
+ _textureUnitMap.Reset();
+ _previousHash = _frameHash;
+ _frameHash = 0;
+ }
+
+ ///
protected override void SetAdditionalUniforms(Program parProgram)
{
foreach (var (texture, unit) in _textureUnitMap.Textures)
@@ -52,16 +94,9 @@ public class MeshRenderer(Asset.Mesh.Mesh parMesh, int parInstanceCount, Program
parProgram.SetUniform("uTexture", _textureUnitIndices);
}
+ ///
protected override bool DataChanged()
{
return _frameHash != _previousHash;
}
-
- public override void Reset()
- {
- base.Reset();
- _textureUnitMap.Reset();
- _previousHash = _frameHash;
- _frameHash = 0;
- }
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Render/Quad/QuadCommonVertex.cs b/Engine/src/Graphics/Render/Quad/QuadCommonVertex.cs
index ca304e7..15bb29a 100644
--- a/Engine/src/Graphics/Render/Quad/QuadCommonVertex.cs
+++ b/Engine/src/Graphics/Render/Quad/QuadCommonVertex.cs
@@ -4,8 +4,19 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Quad;
+///
+/// Represents a common vertex structure for a quad.
+/// This vertex structure includes position and UV coordinates.
+///
public struct QuadCommonVertex : IVertex
{
+ ///
+ /// The position of the vertex in 3D space.
+ ///
[Vertex(VertexAttribType.Float, 3)] public Vector3 _position;
+
+ ///
+ /// The UV coordinates of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 2)] public Vector2 _uv;
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Render/Quad/QuadInstanceVertex.cs b/Engine/src/Graphics/Render/Quad/QuadInstanceVertex.cs
index 287e2bc..ef9400c 100644
--- a/Engine/src/Graphics/Render/Quad/QuadInstanceVertex.cs
+++ b/Engine/src/Graphics/Render/Quad/QuadInstanceVertex.cs
@@ -4,12 +4,28 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Quad;
+///
+/// Represents an instance vertex structure for a quad.
+/// This vertex structure includes color, texture ID, and model matrix.
+///
public struct QuadInstanceVertex : IVertex
{
+ ///
+ /// The color of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4)] public Vector4 _color;
+
+ ///
+ /// The texture ID of the vertex.
+ ///
[Vertex(VertexAttribType.Float)] public float _textureId;
+
+ ///
+ /// The model matrix of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4, 4)] public Matrix4 _modelMatrix;
+ ///
public override int GetHashCode()
{
return HashCode.Combine(_color, _textureId, _modelMatrix);
diff --git a/Engine/src/Graphics/Render/Quad/QuadRenderer.cs b/Engine/src/Graphics/Render/Quad/QuadRenderer.cs
index f646bad..79fc185 100644
--- a/Engine/src/Graphics/Render/Quad/QuadRenderer.cs
+++ b/Engine/src/Graphics/Render/Quad/QuadRenderer.cs
@@ -5,14 +5,37 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Quad;
+///
+/// A renderer class for rendering quadrilaterals (quads) using instancing.
+/// Supports dynamic texture binding and manages the state for rendering multiple instances of quads.
+///
public class QuadRenderer : InstancedRenderer
{
+ ///
+ /// Maps textures to texture units with a limit of 16 texture units.
+ ///
private readonly TextureUnitMap _textureUnitMap = new(16);
+
+ ///
+ /// Stores the texture unit indices used for binding textures.
+ ///
private readonly int[] _textureUnitIndices = new int[16];
+ ///
+ /// Stores the hash of the current frame, used for detecting changes in instance data.
+ ///
private int _frameHash;
+
+ ///
+ /// Stores the hash of the previous frame.
+ ///
private int _previousHash;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The engine used to load resources.
+ /// The number of instances to render.
public QuadRenderer(Engine parEngine, int parInstanceCount)
: base(PrimitiveType.Triangles, parInstanceCount, [0, 2, 1, 2, 3, 1], [
new QuadCommonVertex { _position = new Vector3(-0.5f, -0.5f, 0), _uv = new Vector2(0, 0) },
@@ -24,6 +47,12 @@ public class QuadRenderer : InstancedRenderer
+ /// Commits an instance to the renderer, adding it to the queue with the specified model matrix, color, and optional texture.
+ ///
+ /// The model transformation matrix for this instance.
+ /// The color to apply to this instance.
+ /// An optional texture to apply to the quad. If null, no texture is applied.
public void Commit(in Matrix4 parModelMatrix, in Vector4 parColor, Texture.Texture? parTexture = null)
{
if (_queuedInstanceCount >= _instanceCount)
@@ -46,6 +75,16 @@ public class QuadRenderer : InstancedRenderer
+ public override void Reset()
+ {
+ base.Reset();
+ _textureUnitMap.Reset();
+ _previousHash = _frameHash;
+ _frameHash = 0;
+ }
+
+ ///
protected override void SetAdditionalUniforms(Program parProgram)
{
foreach (var (texture, unit) in _textureUnitMap.Textures)
@@ -57,16 +96,9 @@ public class QuadRenderer : InstancedRenderer
protected override bool DataChanged()
{
return _frameHash != _previousHash;
}
-
- public override void Reset()
- {
- base.Reset();
- _textureUnitMap.Reset();
- _previousHash = _frameHash;
- _frameHash = 0;
- }
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Render/Text/GlyphCommonVertex.cs b/Engine/src/Graphics/Render/Text/GlyphCommonVertex.cs
index ac07e18..bee8f56 100644
--- a/Engine/src/Graphics/Render/Text/GlyphCommonVertex.cs
+++ b/Engine/src/Graphics/Render/Text/GlyphCommonVertex.cs
@@ -4,10 +4,29 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Text;
+///
+/// Represents a common vertex structure for a glyph.
+/// This vertex structure includes color, atlas ID, unit range, and model matrix.
+///
public struct GlyphCommonVertex : IVertex
{
+ ///
+ /// The color of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4)] public Vector4 _color;
+
+ ///
+ /// The atlas ID of the vertex.
+ ///
[Vertex(VertexAttribType.Int)] public int _atlasId;
+
+ ///
+ /// The unit range of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 2)] public Vector2 _unitRange;
+
+ ///
+ /// The model matrix of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4, 4)] public Matrix4 _modelMatrix;
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Render/Text/GlyphVertex.cs b/Engine/src/Graphics/Render/Text/GlyphVertex.cs
index 21d19cb..5676ea1 100644
--- a/Engine/src/Graphics/Render/Text/GlyphVertex.cs
+++ b/Engine/src/Graphics/Render/Text/GlyphVertex.cs
@@ -4,12 +4,39 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Text;
+///
+/// Represents a vertex structure for a glyph.
+/// This vertex structure includes position, UV coordinates, color, atlas ID, unit range, and model matrix.
+///
public struct GlyphVertex : IVertex
{
+ ///
+ /// The position of the vertex in 2D space.
+ ///
[Vertex(VertexAttribType.Float, 2)] public Vector2 _position;
+
+ ///
+ /// The UV coordinates of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 2)] public Vector2 _uv;
+
+ ///
+ /// The color of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4)] public Vector4 _color;
+
+ ///
+ /// The atlas ID of the vertex.
+ ///
[Vertex(VertexAttribType.Int)] public int _atlasId;
+
+ ///
+ /// The unit range of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 2)] public Vector2 _unitRange;
+
+ ///
+ /// The model matrix of the vertex.
+ ///
[Vertex(VertexAttribType.Float, 4, 4)] public Matrix4 _modelMatrix;
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Render/Text/TextRenderer.cs b/Engine/src/Graphics/Render/Text/TextRenderer.cs
index c5c538d..41ad085 100644
--- a/Engine/src/Graphics/Render/Text/TextRenderer.cs
+++ b/Engine/src/Graphics/Render/Text/TextRenderer.cs
@@ -7,21 +7,62 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Text;
+///
+/// A renderer class for rendering text using glyphs from a font atlas.
+/// Handles dynamic font rendering with support for textures.
+///
public class TextRenderer
{
+ ///
+ /// The shader program used for rendering the text.
+ ///
private readonly Program _program;
+
+ ///
+ /// The index buffer used for rendering the text glyphs.
+ ///
private readonly IndexBuffer _indexBuffer;
+
+ ///
+ /// The buffer holding vertex data for all glyphs to be rendered.
+ ///
private readonly VertexBuffer _glyphVertexBuffer;
+
+ ///
+ /// The vertex array object that binds the index and vertex buffers.
+ ///
private readonly VertexArray _vertexArray;
+ ///
+ /// The number of characters that can be rendered at once.
+ ///
private readonly int _characterCount;
+
+ ///
+ /// The array of glyph vertices representing the text to be rendered.
+ ///
private readonly GlyphVertex[] _glyphVertices;
+ ///
+ /// Maps textures to texture units for rendering the font atlas.
+ ///
private readonly TextureUnitMap _textureUnitMap = new(16);
+
+ ///
+ /// Stores the texture unit indices for binding textures.
+ ///
private readonly int[] _textureUnitIndices = new int[16];
+ ///
+ /// The number of characters that have been queued for rendering.
+ ///
private int _queuedCharacterCount;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The engine used to load resources.
+ /// The maximum number of characters to render.
public TextRenderer(Engine parEngine, int parCharacterCount)
{
_characterCount = parCharacterCount;
@@ -39,6 +80,13 @@ public class TextRenderer
_vertexArray.BindVertexBuffer(_glyphVertexBuffer);
}
+ ///
+ /// Commits a string of text to the renderer, creating the necessary glyphs and adding them to the render queue.
+ ///
+ /// The font to use for rendering the text.
+ /// The text string to render.
+ /// The color to apply to the text.
+ /// The model transformation matrix to apply to the text.
public void Commit(Font parFont, string parText, Vector4 parColor, in Matrix4 parModelMatrix)
{
if (_queuedCharacterCount >= _characterCount)
@@ -66,6 +114,11 @@ public class TextRenderer
}
}
+ ///
+ /// Renders the queued text characters to the screen with the given projection and view matrices.
+ ///
+ /// The projection matrix to use for the render.
+ /// The view matrix to use for the render.
public void Render(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix)
{
if (_queuedCharacterCount <= 0)
@@ -90,12 +143,20 @@ public class TextRenderer
GL.DrawElements(PrimitiveType.Triangles, _queuedCharacterCount * 6, DrawElementsType.UnsignedInt, 0);
}
+ ///
+ /// Resets the text renderer, clearing all queued characters and texture unit mappings.
+ ///
public void Reset()
{
_textureUnitMap.Reset();
_queuedCharacterCount = 0;
}
+ ///
+ /// Creates the indices for rendering the glyphs.
+ ///
+ /// The number of characters to render.
+ /// An array of indices for rendering the glyphs.
private static uint[] CreateIndices(int parCharacterCount)
{
var indices = new uint[parCharacterCount * 6];
diff --git a/Engine/src/Graphics/Renderer.cs b/Engine/src/Graphics/Renderer.cs
index d7eb4d2..235e533 100644
--- a/Engine/src/Graphics/Renderer.cs
+++ b/Engine/src/Graphics/Renderer.cs
@@ -7,22 +7,63 @@ using OpenTK.Windowing.Desktop;
namespace Engine.Graphics;
+///
+/// Handles the rendering pipeline, manages render layers, and provides tools for rendering graphics in the engine.
+///
public class Renderer
{
+ ///
+ /// The width of the viewport.
+ ///
public int ViewportWidth => RenderFramebuffer.Width;
+
+ ///
+ /// The height of the viewport.
+ ///
public int ViewportHeight => RenderFramebuffer.Height;
+ ///
+ /// The framebuffer used for rendering.
+ ///
internal Framebuffer.Framebuffer RenderFramebuffer { get; }
+
+ ///
+ /// The texture of the render framebuffer.
+ ///
internal Texture.Texture RenderTexture => RenderFramebuffer.TextureInternal!;
+
+ ///
+ /// The native OpenGL window.
+ ///
internal NativeWindow NativeWindow { get; }
+ ///
+ /// Stores renderers for each render layer in a sorted dictionary.
+ ///
private readonly SortedDictionary _renderers = new();
+
+ ///
+ /// The thread dedicated to rendering.
+ ///
private readonly Thread _renderThread;
+ ///
+ /// Renderer for quad-based primitives.
+ ///
private QuadRenderer QuadRenderer { get; }
+ ///
+ /// Queue of actions scheduled to run on the render thread.
+ ///
private readonly Queue _scheduleActions = new();
+ ///
+ /// Initializes the renderer with the specified engine, dimensions, and native window settings.
+ ///
+ /// The engine instance.
+ /// The width of the rendering viewport.
+ /// The height of the rendering viewport.
+ /// Settings for the native window.
public Renderer(Engine parEngine, int parWidth, int parHeight, NativeWindowSettings parSettings)
{
_renderThread = Thread.CurrentThread;
@@ -48,6 +89,12 @@ public class Renderer
}
}
+ ///
+ /// Retrieves the renderer for the specified render layer.
+ ///
+ /// The render layer to retrieve.
+ /// The for the specified render layer.
+ /// Thrown if the render layer does not exist.
public GenericRenderer this[RenderLayer parRenderLayer]
{
get
@@ -61,24 +108,11 @@ public class Renderer
}
}
- private void InitializeOpenGl(int parWidth, int parHeight)
- {
-#if DEBUG
- Debug.Setup();
-#endif
-
- GL.Enable(EnableCap.DepthTest);
- // GL.Enable(EnableCap.CullFace);
-
- // GL.Enable(EnableCap.FramebufferSrgb);
-
- GL.Enable(EnableCap.Blend);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
-
- GL.Viewport(0, 0, parWidth, parHeight);
- }
-
- public void EnsureRenderThread()
+ ///
+ /// Ensures that the current thread is the render thread.
+ ///
+ /// Thrown if not on the render thread in debug mode.
+ internal void EnsureRenderThread()
{
#if DEBUG
if (Thread.CurrentThread != _renderThread)
@@ -88,11 +122,21 @@ public class Renderer
#endif
}
+ ///
+ /// Schedules an action to be executed on the render thread.
+ ///
+ /// The action to execute.
internal void Schedule(Action parAction)
{
_scheduleActions.Enqueue(parAction);
}
+ ///
+ /// Schedules a function to be executed on the render thread and returns a task representing the result.
+ ///
+ /// The return type of the function.
+ /// The function to execute.
+ /// A task representing the function's result.
internal Task Schedule(Func parAction)
{
var completionSource = new TaskCompletionSource();
@@ -112,6 +156,9 @@ public class Renderer
return completionSource.Task;
}
+ ///
+ /// Prepares the rendering pipeline for a new frame.
+ ///
internal void StartFrame()
{
EnsureRenderThread();
@@ -122,6 +169,10 @@ public class Renderer
}
}
+ ///
+ /// Finalizes the rendering pipeline for the current frame.
+ ///
+ /// A dictionary of matrices for render layers.
internal void EndFrame(Dictionary parMatrices)
{
EnsureRenderThread();
@@ -158,6 +209,11 @@ public class Renderer
RenderFramebuffer.Unbind();
}
+ ///
+ /// Resizes the rendering viewport and updates associated resources.
+ ///
+ /// The new width of the viewport.
+ /// The new height of the viewport.
internal void Resize(int parWidth, int parHeight)
{
RenderFramebuffer.Resize(parWidth, parHeight);
@@ -169,6 +225,9 @@ public class Renderer
}
}
+ ///
+ /// Executes all scheduled actions on the render thread.
+ ///
internal void RunScheduledActions()
{
while (_scheduleActions.TryDequeue(out var action))
@@ -176,4 +235,26 @@ public class Renderer
action();
}
}
+
+ ///
+ /// Initializes OpenGL settings for rendering.
+ ///
+ /// The width of the viewport.
+ /// The height of the viewport.
+ private void InitializeOpenGl(int parWidth, int parHeight)
+ {
+#if DEBUG
+ Debug.Setup();
+#endif
+
+ GL.Enable(EnableCap.DepthTest);
+ // GL.Enable(EnableCap.CullFace);
+
+ // GL.Enable(EnableCap.FramebufferSrgb);
+
+ GL.Enable(EnableCap.Blend);
+ GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+
+ GL.Viewport(0, 0, parWidth, parHeight);
+ }
}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Shader/Program.cs b/Engine/src/Graphics/Shader/Program.cs
index 4e0f2b0..445589d 100644
--- a/Engine/src/Graphics/Shader/Program.cs
+++ b/Engine/src/Graphics/Shader/Program.cs
@@ -4,10 +4,22 @@ using Serilog;
namespace Engine.Graphics.Shader;
+///
+/// Represents an OpenGL shader program that can be used for rendering.
+/// The class handles the compilation, linking, and management of shaders, as well as setting uniform values.
+///
public class Program : OpenGlObject
{
+ ///
+ /// A dictionary mapping uniform names to their locations in the shader program.
+ ///
private readonly Dictionary _uniforms = new();
+ ///
+ /// Initializes a new instance of the class with the provided vertex and fragment shader sources.
+ ///
+ /// The source code for the vertex shader.
+ /// The source code for the fragment shader.
public Program(string parVertexSource, string parFragmentSource)
{
var vertexShader = CompileSource(parVertexSource, ShaderType.VertexShader);
@@ -16,6 +28,13 @@ public class Program : OpenGlObject
Handle = LinkProgram(vertexShader, fragmentShader);
}
+ ///
+ /// Sets a uniform variable in the shader program with the given value.
+ ///
+ /// The type of the uniform value.
+ /// The name of the uniform variable in the shader.
+ /// The value to set for the uniform.
+ /// Thrown when an unsupported uniform type is provided.
public void SetUniform(string parName, in T parValue)
{
try
@@ -62,21 +81,31 @@ public class Program : OpenGlObject
}
}
+ ///
internal override void Bind()
{
GL.UseProgram(Handle);
}
+ ///
internal override void Unbind()
{
GL.UseProgram(0);
}
+ ///
protected override void Destroy()
{
GL.DeleteProgram(Handle);
}
+ ///
+ /// Retrieves the location of a uniform variable in the shader program.
+ /// If the location is not cached, it will be retrieved from OpenGL.
+ ///
+ /// The name of the uniform variable.
+ /// The location of the uniform variable.
+ /// Thrown when the uniform is not found in the shader program.
private int GetUniformLocation(string parName)
{
if (_uniforms.TryGetValue(parName, out var location))
@@ -94,6 +123,13 @@ public class Program : OpenGlObject
return location;
}
+ ///
+ /// Compiles a shader from the given source code and shader type.
+ ///
+ /// The source code of the shader.
+ /// The type of shader (vertex or fragment).
+ /// The compiled shader handle.
+ /// Thrown when the shader fails to compile.
private static int CompileSource(string parSource, ShaderType parType)
{
var shaderId = GL.CreateShader(parType);
@@ -112,6 +148,13 @@ public class Program : OpenGlObject
return shaderId;
}
+ ///
+ /// Links a vertex and fragment shader into a single shader program.
+ ///
+ /// The compiled vertex shader handle.
+ /// The compiled fragment shader handle.
+ /// The linked shader program handle.
+ /// Thrown when the shader program fails to link.
private static int LinkProgram(int parVertexShader, int parFragmentShader)
{
var programId = GL.CreateProgram();
@@ -152,13 +195,52 @@ public class Program : OpenGlObject
}
}
-public class ShaderCompilationException(ShaderType parType, string parMessage)
- : Exception($"Failed to compile {parType} shader: {parMessage}")
+///
+/// Exception thrown when a shader fails to compile.
+///
+public class ShaderCompilationException : Exception
{
- public ShaderType ShaderType { get; } = parType;
+ ///
+ /// The type of the shader that failed to compile.
+ ///
+ public ShaderType ShaderType { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The type of shader that failed to compile.
+ /// The error message from the shader compilation failure.
+ public ShaderCompilationException(ShaderType parType, string parMessage) : base(
+ $"Failed to compile {parType} shader: {parMessage}")
+ {
+ ShaderType = parType;
+ }
}
-public class ShaderLinkException(string parMessage) : Exception($"Failed to link shader program: {parMessage}");
+///
+/// Exception thrown when a shader program fails to link.
+///
+public class ShaderLinkException : Exception
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error message from the shader linking failure.
+ public ShaderLinkException(string parMessage) : base($"Failed to link shader program: {parMessage}")
+ {
+ }
+}
-public class ShaderValidationException(string parMessage)
- : Exception($"Failed to validate shader program: {parMessage}");
\ No newline at end of file
+///
+/// Exception thrown when a shader program fails validation.
+///
+public class ShaderValidationException : Exception
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error message from the shader validation failure.
+ public ShaderValidationException(string parMessage) : base($"Failed to validate shader program: {parMessage}")
+ {
+ }
+}
\ No newline at end of file
diff --git a/Engine/src/Graphics/Texture/DynamicTexture.cs b/Engine/src/Graphics/Texture/DynamicTexture.cs
index 725065e..ab1ef9b 100644
--- a/Engine/src/Graphics/Texture/DynamicTexture.cs
+++ b/Engine/src/Graphics/Texture/DynamicTexture.cs
@@ -5,12 +5,35 @@ using Serilog;
namespace Engine.Graphics.Texture;
+///
+/// Represents a dynamic texture that can be resized and attached to a framebuffer.
+///
public class DynamicTexture : Texture, IFramebufferAttachment
{
+ ///
+ /// The pixel format of the texture.
+ ///
private readonly PixelFormat _format;
+
+ ///
+ /// The pixel type of the texture.
+ ///
private readonly PixelType _type;
+
+ ///
+ /// The internal format of the texture.
+ ///
private readonly PixelInternalFormat _internalFormat;
+ ///
+ /// Initializes a new instance of the class.
+ /// The texture is created with the specified format, type, and internal format.
+ ///
+ /// The width of the texture.
+ /// The height of the texture.
+ /// The format of the texture.
+ /// The type of the texture.
+ /// The internal format of the texture.
internal DynamicTexture(int parWidth, int parHeight, PixelFormat parFormat, PixelType parType,
PixelInternalFormat parInternalFormat)
: base(parWidth, parHeight)
@@ -24,6 +47,13 @@ public class DynamicTexture : Texture, IFramebufferAttachment
IntPtr.Zero);
}
+ ///
+ /// Creates a new with the specified width, height, and pixel type.
+ ///
+ /// The type of pixel used for the texture.
+ /// The width of the texture.
+ /// The height of the texture.
+ /// A new instance of .
public static DynamicTexture Create(int parWidth, int parHeight)
where T : struct, IPixel
{
@@ -31,6 +61,11 @@ public class DynamicTexture : Texture, IFramebufferAttachment
return new DynamicTexture(parWidth, parHeight, pixel.Format, pixel.Type, pixel.InternalFormat);
}
+ ///
+ /// Resizes the texture to the specified width and height.
+ ///
+ /// The new width of the texture.
+ /// The new height of the texture.
public void Resize(int parWidth, int parHeight)
{
if (Width == parWidth && Height == parHeight)
@@ -48,6 +83,7 @@ public class DynamicTexture : Texture, IFramebufferAttachment
Log.Debug("Texture {Handle} resized to {Width}x{Height}", Handle, Width, Height);
}
+ ///
public void Attach(Framebuffer.Framebuffer parFramebuffer, FramebufferAttachment parAttachment)
{
GL.NamedFramebufferTexture(parFramebuffer.Handle, parAttachment, Handle, 0);
diff --git a/Engine/src/Graphics/Texture/IConstTexture.cs b/Engine/src/Graphics/Texture/IConstTexture.cs
index cef2575..674320b 100644
--- a/Engine/src/Graphics/Texture/IConstTexture.cs
+++ b/Engine/src/Graphics/Texture/IConstTexture.cs
@@ -3,22 +3,60 @@ using Engine.Graphics.Pixel;
namespace Engine.Graphics.Texture;
+///
+/// Represents a read-only texture with dimensions and pixel access capabilities.
+///
public interface IConstTexture
{
+ ///
+ /// The width of the texture.
+ ///
public int Width { get; }
+
+ ///
+ /// The height of the texture.
+ ///
public int Height { get; }
+ ///
+ /// Reads pixels from the texture into the provided pixel array.
+ ///
+ /// The pixel type, which must implement .
+ /// The x-coordinate of the region to read.
+ /// The y-coordinate of the region to read.
+ /// The width of the region to read.
+ /// The height of the region to read.
+ /// The array to store the read pixels.
public void ReadPixels(int parX, int parY, int parWidth, int parHeight, T[,] parPixels)
where T : struct, IPixel;
}
+///
+/// Provides extension methods for .
+///
public static class ConstTextureExtensions
{
+ ///
+ /// Reads all pixels from the texture.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to read from.
+ /// A 2D array containing the pixels.
public static T[,] ReadPixels(this IConstTexture parTexture) where T : struct, IPixel
{
return parTexture.ReadPixels(0, 0, parTexture.Width, parTexture.Height);
}
+ ///
+ /// Reads a specified region of pixels from the texture.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to read from.
+ /// The x-coordinate of the region to read.
+ /// The y-coordinate of the region to read.
+ /// The width of the region to read.
+ /// The height of the region to read.
+ /// A 2D array containing the pixels.
public static T[,] ReadPixels(this IConstTexture parTexture, int parX, int parY, int parWidth, int parHeight)
where T : struct, IPixel
{
@@ -28,17 +66,37 @@ public static class ConstTextureExtensions
return pixels;
}
+ ///
+ /// Reads all pixels from the texture into the specified image.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to read from.
+ /// The image to store the pixels.
public static void ReadPixels(this IConstTexture parTexture, Image parImage) where T : struct, IPixel
{
parTexture.ReadPixels(0, 0, parImage);
}
+ ///
+ /// Reads a specified region of pixels from the texture into the specified image.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to read from.
+ /// The x-coordinate of the region to read.
+ /// The y-coordinate of the region to read.
+ /// The image to store the pixels.
public static void ReadPixels(this IConstTexture parTexture, int parX, int parY, Image parImage)
where T : struct, IPixel
{
parTexture.ReadPixels(parX, parY, parImage.Width, parImage.Height, parImage.Pixels);
}
+ ///
+ /// Reads all pixels from the texture into the specified 2D array.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to read from.
+ /// The array to store the pixels.
public static void ReadPixels(this IConstTexture parTexture, T[,] parPixels) where T : struct, IPixel
{
parTexture.ReadPixels(0, 0, parTexture.Width, parTexture.Height, parPixels);
diff --git a/Engine/src/Graphics/Texture/ITexture.cs b/Engine/src/Graphics/Texture/ITexture.cs
index 0d3547c..43e3f1e 100644
--- a/Engine/src/Graphics/Texture/ITexture.cs
+++ b/Engine/src/Graphics/Texture/ITexture.cs
@@ -3,25 +3,60 @@ using Engine.Graphics.Pixel;
namespace Engine.Graphics.Texture;
+///
+/// Represents a writable texture with dimensions and pixel access capabilities.
+///
public interface ITexture : IConstTexture
{
+ ///
+ /// Uploads pixels to the texture.
+ ///
+ /// The pixel type, which must implement .
+ /// The x-coordinate of the region to write.
+ /// The y-coordinate of the region to write.
+ /// The width of the region to write.
+ /// The height of the region to write.
+ /// The pixel data to upload.
public void UploadPixels(int parX, int parY, int parWidth, int parHeight, T[,] parPixels)
where T : struct, IPixel;
}
+///
+/// Provides extension methods for .
+///
public static class TextureExtensions
{
+ ///
+ /// Uploads the entire image to the texture.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to upload to.
+ /// The image containing the pixel data.
public static void UploadPixels(this ITexture parTexture, Image parImage) where T : struct, IPixel
{
parTexture.UploadPixels(0, 0, parImage);
}
+ ///
+ /// Uploads a specified region of the image to the texture.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to upload to.
+ /// The x-coordinate of the region in the image.
+ /// The y-coordinate of the region in the image.
+ /// The image containing the pixel data.
public static void UploadPixels(this ITexture parTexture, int parX, int parY, Image parImage)
where T : struct, IPixel
{
parTexture.UploadPixels(parX, parY, parImage.Width, parImage.Height, parImage.Pixels);
}
+ ///
+ /// Uploads the entire 2D pixel array to the texture.
+ ///
+ /// The pixel type, which must implement .
+ /// The texture to upload to.
+ /// The pixel data to upload.
public static void UploadPixels(this ITexture parTexture, T[,] parPixels) where T : struct, IPixel
{
parTexture.UploadPixels(0, 0, parTexture.Width, parTexture.Height, parPixels);
diff --git a/Engine/src/Graphics/Texture/StaticTexture.cs b/Engine/src/Graphics/Texture/StaticTexture.cs
index 60db787..f31182f 100644
--- a/Engine/src/Graphics/Texture/StaticTexture.cs
+++ b/Engine/src/Graphics/Texture/StaticTexture.cs
@@ -3,13 +3,30 @@ using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Texture;
+///
+/// Represents a static texture in OpenGL, created with fixed storage and format.
+///
public class StaticTexture : Texture
{
+ ///
+ /// Initializes a new instance of the class.
+ /// The texture is created with the specified width, height, and internal format.
+ ///
+ /// The width of the texture.
+ /// The height of the texture.
+ /// The internal format of the texture.
private StaticTexture(int parWidth, int parHeight, SizedInternalFormat parFormat) : base(parWidth, parHeight)
{
GL.TextureStorage2D(Handle, 1, parFormat, Width, Height);
}
+ ///
+ /// Creates a new with the specified width and height.
+ ///
+ /// The type of pixel format used for the texture.
+ /// The width of the texture.
+ /// The height of the texture.
+ /// A new instance of .
public static StaticTexture Create(int parWidth, int parHeight)
where T : struct, IPixel
{
diff --git a/Engine/src/Graphics/Texture/Texture.cs b/Engine/src/Graphics/Texture/Texture.cs
index 9599f4e..23fd302 100644
--- a/Engine/src/Graphics/Texture/Texture.cs
+++ b/Engine/src/Graphics/Texture/Texture.cs
@@ -5,8 +5,13 @@ using Serilog;
namespace Engine.Graphics.Texture;
+///
+/// Represents an abstract texture object used in OpenGL for 2D textures.
+/// Handles the creation, binding, and destruction of textures and provides functionality for uploading and reading pixel data.
+///
public abstract class Texture : OpenGlObject, ITexture
{
+ ///
public int Width
{
get => _width;
@@ -21,6 +26,7 @@ public abstract class Texture : OpenGlObject, ITexture
}
}
+ ///
public int Height
{
get => _height;
@@ -35,9 +41,22 @@ public abstract class Texture : OpenGlObject, ITexture
}
}
+ ///
+ /// The width of the texture.
+ ///
private int _width;
+
+ ///
+ /// The height of the texture.
+ ///
private int _height;
+ ///
+ /// Initializes a new instance of the class with the specified width and height.
+ /// Creates an OpenGL texture handle and sets default texture parameters.
+ ///
+ /// The width of the texture.
+ /// The height of the texture.
protected Texture(int parWidth, int parHeight)
{
Width = parWidth;
@@ -54,6 +73,7 @@ public abstract class Texture : OpenGlObject, ITexture
Log.Debug("Texture {Handle} created with {Width}x{Height}", Handle, Width, Height);
}
+ ///
public void UploadPixels(int parX, int parY, int parWidth, int parHeight, T[,] parPixels)
where T : struct, IPixel
{
@@ -83,6 +103,7 @@ public abstract class Texture : OpenGlObject, ITexture
GL.TextureSubImage2D(Handle, 0, parX, parY, parWidth, parHeight, format, type, parPixels);
}
+ ///
public void ReadPixels(int parX, int parY, int parWidth, int parHeight, T[,] parPixels)
where T : struct, IPixel
{
@@ -118,21 +139,28 @@ public abstract class Texture : OpenGlObject, ITexture
parPixels);
}
+ ///
+ /// Binds the texture to a texture unit.
+ ///
+ /// The texture unit to which the texture should be bound.
public void BindUnit(int parUnit = 0)
{
GL.BindTextureUnit(parUnit, Handle);
}
+ ///
internal override void Bind()
{
GL.BindTexture(TextureTarget.Texture2D, Handle);
}
+ ///
internal override void Unbind()
{
GL.BindTexture(TextureTarget.Texture2D, 0);
}
+ ///
protected override void Destroy()
{
GL.DeleteTexture(Handle);
diff --git a/Engine/src/Graphics/Texture/TextureUnitMap.cs b/Engine/src/Graphics/Texture/TextureUnitMap.cs
index 20dd449..0920271 100644
--- a/Engine/src/Graphics/Texture/TextureUnitMap.cs
+++ b/Engine/src/Graphics/Texture/TextureUnitMap.cs
@@ -1,13 +1,48 @@
namespace Engine.Graphics.Texture;
-public class TextureUnitMap(int parCapacity)
+///
+/// Manages the mapping of textures to texture units.
+/// Allows tracking of textures and their associated texture units within a given capacity.
+///
+public class TextureUnitMap
{
+ ///
+ /// The maximum number of textures that can be mapped.
+ ///
+ public int Capacity { get; }
+
+ ///
+ /// The current number of textures in the unit map.
+ ///
public int Size => _textures.Count;
- public int Capacity => parCapacity;
+
+ ///
+ /// A read-only dictionary that holds the textures and their associated unit numbers.
+ ///
public IReadOnlyDictionary Textures => _textures;
+ ///
+ /// A dictionary that stores the textures and their corresponding texture units.
+ ///
private readonly Dictionary _textures = new();
+ ///
+ /// Initializes a new instance of the class with the specified capacity.
+ ///
+ /// The maximum number of textures that can be mapped in this unit map.
+ public TextureUnitMap(int parCapacity)
+ {
+ Capacity = parCapacity;
+ }
+
+ ///
+ /// Retrieves the texture unit assigned to the specified texture.
+ /// If the texture is not already mapped, a new unit is assigned.
+ /// Throws an exception if the map has reached its capacity.
+ ///
+ /// The texture for which to retrieve the assigned unit.
+ /// The texture unit assigned to the texture.
+ /// Thrown when the map has reached its capacity.
public int GetUnit(Texture parTexture)
{
if (_textures.TryGetValue(parTexture, out var unit))
@@ -15,7 +50,7 @@ public class TextureUnitMap(int parCapacity)
return unit;
}
- if (_textures.Count >= parCapacity)
+ if (_textures.Count >= Capacity)
{
throw new InvalidOperationException("Texture unit map is full");
}
@@ -26,6 +61,9 @@ public class TextureUnitMap(int parCapacity)
return unit;
}
+ ///
+ /// Clears all textures from the unit map, effectively resetting it.
+ ///
public void Reset()
{
_textures.Clear();
diff --git a/Engine/src/Input/IInputHandler.cs b/Engine/src/Input/IInputHandler.cs
index 8a2c9dd..a948e07 100644
--- a/Engine/src/Input/IInputHandler.cs
+++ b/Engine/src/Input/IInputHandler.cs
@@ -4,15 +4,46 @@ using OpenTK.Mathematics;
namespace Engine.Input;
+///
+/// Represents an input handler interface that processes keyboard and mouse input.
+///
public interface IInputHandler : IUpdate
{
- CultureInfo CurrentInputLanguage { get; }
+ ///
+ /// The current input language.
+ ///
+ public CultureInfo CurrentInputLanguage { get; }
- Vector2 MousePosition { get; }
+ ///
+ /// The current mouse position in screen coordinates.
+ ///
+ public Vector2 MousePosition { get; }
- bool IsKeyPressed(KeyboardButtonCode parKeyboardButtonCode);
- bool IsKeyJustPressed(KeyboardButtonCode parKeyboardButtonCode);
+ ///
+ /// Checks if a specific keyboard button is currently pressed.
+ ///
+ /// The keyboard button code to check.
+ /// True if the button is pressed; otherwise, false.
+ public bool IsKeyPressed(KeyboardButtonCode parKeyboardButtonCode);
- bool IsMouseButtonPressed(MouseButtonCode parButtonCode);
- bool IsMouseButtonJustPressed(MouseButtonCode parButtonCode);
+ ///
+ /// Checks if a specific keyboard button was just pressed in the current frame.
+ ///
+ /// The keyboard button code to check.
+ /// True if the button was just pressed; otherwise, false.
+ public bool IsKeyJustPressed(KeyboardButtonCode parKeyboardButtonCode);
+
+ ///
+ /// Checks if a specific mouse button is currently pressed.
+ ///
+ /// The mouse button code to check.
+ /// True if the button is pressed; otherwise, false.
+ public bool IsMouseButtonPressed(MouseButtonCode parButtonCode);
+
+ ///
+ /// Checks if a specific mouse button was just pressed in the current frame.
+ ///
+ /// The mouse button code to check.
+ /// True if the button was just pressed; otherwise, false.
+ public bool IsMouseButtonJustPressed(MouseButtonCode parButtonCode);
}
\ No newline at end of file
diff --git a/Engine/src/Input/KeyboardButtonCode.cs b/Engine/src/Input/KeyboardButtonCode.cs
index a15a2e3..cf35960 100644
--- a/Engine/src/Input/KeyboardButtonCode.cs
+++ b/Engine/src/Input/KeyboardButtonCode.cs
@@ -61,22 +61,42 @@ public enum KeyboardButtonCode
PageUp,
PageDown,
+ ///
+ /// Represents the total count of keyboard button codes.
+ ///
TotalCount = PageDown + 1
}
+///
+/// Provides helper methods for working with keyboard button codes.
+///
public static class KeyboardButtonCodeHelper
{
+ ///
+ /// Gets a list of all printable keyboard button codes.
+ ///
+ /// A list of printable keyboard button codes.
public static List GetAllPrintableKeys()
{
return Enum.GetValues().Where(parX => parX.IsPrintableKey()).ToList();
}
+ ///
+ /// Determines whether a keyboard button code is printable.
+ ///
+ /// The keyboard button code to check.
+ /// True if the key is printable; otherwise, false.
public static bool IsPrintableKey(this KeyboardButtonCode parKey)
{
return parKey is >= KeyboardButtonCode.A and <= KeyboardButtonCode.Z
or >= KeyboardButtonCode.D1 and <= KeyboardButtonCode.D0 or KeyboardButtonCode.Space;
}
+ ///
+ /// Gets the character representation of a keyboard button code based on the current input language.
+ ///
+ /// The keyboard button code to convert.
+ /// The character representation of the key.
public static char GetChar(this KeyboardButtonCode parKey)
{
return Engine.Instance.InputHandler!.CurrentInputLanguage.Name switch
@@ -87,6 +107,11 @@ public static class KeyboardButtonCodeHelper
};
}
+ ///
+ /// Gets the character representation of a keyboard button code in English.
+ ///
+ /// The keyboard button code to convert.
+ /// The character representation of the key.
private static char GetEnChar(this KeyboardButtonCode parKey)
{
return parKey switch
@@ -134,6 +159,11 @@ public static class KeyboardButtonCodeHelper
};
}
+ ///
+ /// Gets the character representation of a keyboard button code in Russian.
+ ///
+ /// The keyboard button code to convert.
+ /// The character representation of the key.
private static char GetRuChar(this KeyboardButtonCode parKey)
{
return parKey switch
diff --git a/Engine/src/Input/MouseButtonCode.cs b/Engine/src/Input/MouseButtonCode.cs
index 4fcc558..bc450ff 100644
--- a/Engine/src/Input/MouseButtonCode.cs
+++ b/Engine/src/Input/MouseButtonCode.cs
@@ -1,10 +1,27 @@
namespace Engine.Input;
+///
+/// Represents the different mouse button codes.
+///
public enum MouseButtonCode
{
+ ///
+ /// Represents the left mouse button.
+ ///
Left,
+
+ ///
+ /// Represents the right mouse button.
+ ///
Right,
+
+ ///
+ /// Represents the middle mouse button.
+ ///
Middle,
+ ///
+ /// Represents the total count of mouse button codes.
+ ///
TotalCount = Middle + 1
}
\ No newline at end of file
diff --git a/Engine/src/Input/WindowInputHandler.cs b/Engine/src/Input/WindowInputHandler.cs
index 8a50f08..6794ca3 100644
--- a/Engine/src/Input/WindowInputHandler.cs
+++ b/Engine/src/Input/WindowInputHandler.cs
@@ -4,47 +4,98 @@ using OpenTK.Windowing.GraphicsLibraryFramework;
namespace Engine.Input;
-public class WindowInputHandler(Window parWindow) : IInputHandler
+///
+/// Handles input for a window, processing keyboard and mouse input states.
+///
+public class WindowInputHandler : IInputHandler
{
+ ///
public CultureInfo CurrentInputLanguage => new(1033);
- public Vector2 MousePosition => parWindow.NativeWindow.MouseState.Position;
- private KeyboardState _keyboardState = parWindow.NativeWindow.KeyboardState.GetSnapshot();
- private KeyboardState _previousKeyboardState = parWindow.NativeWindow.KeyboardState.GetSnapshot();
- private MouseState _mouseState = parWindow.NativeWindow.MouseState.GetSnapshot();
- private MouseState _previousMouseState = parWindow.NativeWindow.MouseState.GetSnapshot();
+ ///
+ public Vector2 MousePosition => _window.NativeWindow.MouseState.Position;
+ ///
+ /// The window to capture input from.
+ ///
+ private readonly Window _window;
+
+ ///
+ /// Keyboard state in the current frame.
+ ///
+ private KeyboardState _keyboardState;
+
+ ///
+ /// Keyboard state in the previous frame.
+ ///
+ private KeyboardState _previousKeyboardState;
+
+ ///
+ /// Mouse state in the current frame.
+ ///
+ private MouseState _mouseState;
+
+ ///
+ /// Mouse state in the previous frame.
+ ///
+ private MouseState _previousMouseState;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The window to capture input from.
+ public WindowInputHandler(Window parWindow)
+ {
+ _window = parWindow;
+
+ _keyboardState = parWindow.NativeWindow.KeyboardState.GetSnapshot();
+ _previousKeyboardState = parWindow.NativeWindow.KeyboardState.GetSnapshot();
+ _mouseState = parWindow.NativeWindow.MouseState.GetSnapshot();
+ _previousMouseState = parWindow.NativeWindow.MouseState.GetSnapshot();
+ }
+
+ ///
public void Update(double parDeltaTime)
{
_previousKeyboardState = _keyboardState;
- _keyboardState = parWindow.NativeWindow.KeyboardState.GetSnapshot();
+ _keyboardState = _window.NativeWindow.KeyboardState.GetSnapshot();
_previousMouseState = _mouseState;
- _mouseState = parWindow.NativeWindow.MouseState.GetSnapshot();
+ _mouseState = _window.NativeWindow.MouseState.GetSnapshot();
}
+ ///
public bool IsKeyPressed(KeyboardButtonCode parKeyboardButtonCode)
{
return _keyboardState.IsKeyDown(MapKeyCode(parKeyboardButtonCode));
}
+ ///
public bool IsKeyJustPressed(KeyboardButtonCode parKeyboardButtonCode)
{
return _keyboardState.IsKeyDown(MapKeyCode(parKeyboardButtonCode)) &&
!_previousKeyboardState.IsKeyDown(MapKeyCode(parKeyboardButtonCode));
}
+ ///
public bool IsMouseButtonPressed(MouseButtonCode parButtonCode)
{
return _mouseState.IsButtonDown(MapMouseButtonCode(parButtonCode));
}
+ ///
public bool IsMouseButtonJustPressed(MouseButtonCode parButtonCode)
{
return _mouseState.IsButtonDown(MapMouseButtonCode(parButtonCode)) &&
!_previousMouseState.IsButtonDown(MapMouseButtonCode(parButtonCode));
}
+ ///
+ /// Maps a custom to the GLFW .
+ ///
+ /// The custom mouse button code.
+ /// The corresponding GLFW mouse button.
+ /// Thrown if the mouse button code is not recognized.
private static MouseButton MapMouseButtonCode(MouseButtonCode parButton)
{
return parButton switch
@@ -56,6 +107,12 @@ public class WindowInputHandler(Window parWindow) : IInputHandler
};
}
+ ///
+ /// Maps a custom to the GLFW .
+ ///
+ /// The custom keyboard button code.
+ /// The corresponding GLFW key.
+ /// Thrown if the keyboard button code is not recognized.
private static Keys MapKeyCode(KeyboardButtonCode parKeyboardButtonCode)
{
return parKeyboardButtonCode switch
diff --git a/Engine/src/Resource/FilesystemResourceStreamProvider.cs b/Engine/src/Resource/FilesystemResourceStreamProvider.cs
index 64dd559..bf222fc 100644
--- a/Engine/src/Resource/FilesystemResourceStreamProvider.cs
+++ b/Engine/src/Resource/FilesystemResourceStreamProvider.cs
@@ -1,9 +1,31 @@
namespace Engine.Resource;
-public class FilesystemResourceStreamProvider(string parBasePath) : IResourceStreamProvider
+///
+/// Provides resource streams from the file system, using a specified base path.
+///
+public class FilesystemResourceStreamProvider : IResourceStreamProvider
{
+ ///
+ /// The base path for locating resources.
+ ///
+ private readonly string _basePath;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The base path for locating resources.
+ public FilesystemResourceStreamProvider(string parBasePath)
+ {
+ _basePath = parBasePath;
+ }
+
+ ///
+ /// Retrieves a stream for the resource located at the specified path, relative to the base path.
+ ///
+ /// The relative path to the resource.
+ /// A stream providing access to the resource data.
public Stream GetStream(string parPath)
{
- return File.OpenRead(Path.Combine(parBasePath, parPath));
+ return File.OpenRead(Path.Combine(_basePath, parPath));
}
}
\ No newline at end of file
diff --git a/Engine/src/Resource/IResourceLoader.cs b/Engine/src/Resource/IResourceLoader.cs
index 4d1173d..1a1483e 100644
--- a/Engine/src/Resource/IResourceLoader.cs
+++ b/Engine/src/Resource/IResourceLoader.cs
@@ -1,6 +1,15 @@
namespace Engine.Resource;
+///
+/// Defines the interface for a resource loader that can load objects from a path using a stream provider.
+///
public interface IResourceLoader
{
- object Load(string parPath, IResourceStreamProvider parStreamProvider);
+ ///
+ /// Loads a resource object from the specified path using the provided stream provider.
+ ///
+ /// The path to the resource.
+ /// The stream provider used to access the resource data.
+ /// The loaded resource object.
+ public object Load(string parPath, IResourceStreamProvider parStreamProvider);
}
\ No newline at end of file
diff --git a/Engine/src/Resource/IResourceManager.cs b/Engine/src/Resource/IResourceManager.cs
index b2a8e30..ed4d9f5 100644
--- a/Engine/src/Resource/IResourceManager.cs
+++ b/Engine/src/Resource/IResourceManager.cs
@@ -1,6 +1,15 @@
namespace Engine.Resource;
+///
+/// Defines the interface for a resource manager that handles loading resources of specific types.
+///
public interface IResourceManager
{
- T Load(string parPath) where T : class;
+ ///
+ /// Loads a resource of the specified type from the given path.
+ ///
+ /// The type of the resource to load.
+ /// The path to the resource.
+ /// The loaded resource as an instance of type T.
+ public T Load(string parPath) where T : class;
}
\ No newline at end of file
diff --git a/Engine/src/Resource/IResourceStreamProvider.cs b/Engine/src/Resource/IResourceStreamProvider.cs
index 9a454ad..e4ee7b6 100644
--- a/Engine/src/Resource/IResourceStreamProvider.cs
+++ b/Engine/src/Resource/IResourceStreamProvider.cs
@@ -1,6 +1,14 @@
namespace Engine.Resource;
+///
+/// Defines the interface for a resource stream provider, responsible for retrieving streams to access resource data.
+///
public interface IResourceStreamProvider
{
- Stream GetStream(string parPath);
+ ///
+ /// Retrieves a stream for the resource located at the specified path.
+ ///
+ /// The path to the resource.
+ /// A stream providing access to the resource data.
+ public Stream GetStream(string parPath);
}
\ No newline at end of file
diff --git a/Engine/src/Resource/Loader/FontLoader.cs b/Engine/src/Resource/Loader/FontLoader.cs
index d13307f..e8f4da9 100644
--- a/Engine/src/Resource/Loader/FontLoader.cs
+++ b/Engine/src/Resource/Loader/FontLoader.cs
@@ -4,8 +4,18 @@ using Engine.Asset.Font.Metadata;
namespace Engine.Resource.Loader;
+///
+/// Loads font resources, including metadata and texture atlas.
+///
public class FontLoader : IResourceLoader
{
+ ///
+ /// Loads a font resource by loading its metadata and texture atlas.
+ ///
+ /// The path to the font resource directory.
+ /// The stream provider used to read files.
+ /// A instance containing the loaded metadata and texture atlas.
+ /// Thrown if the metadata cannot be loaded.
public object Load(string parPath, IResourceStreamProvider parStreamProvider)
{
var metadataPath = Path.Combine(parPath, "metadata.json");
diff --git a/Engine/src/Resource/Loader/ImageLoader.cs b/Engine/src/Resource/Loader/ImageLoader.cs
index 6d204f9..17ce0f9 100644
--- a/Engine/src/Resource/Loader/ImageLoader.cs
+++ b/Engine/src/Resource/Loader/ImageLoader.cs
@@ -6,14 +6,29 @@ using SixLabors.ImageSharp.Processing;
namespace Engine.Resource.Loader;
+///
+/// Loads image resources, including processing the image data.
+///
public class ImageLoader : IResourceLoader
{
+ ///
+ /// Loads the image from the specified path using the provided stream provider.
+ ///
+ /// The path to the image resource.
+ /// The provider for accessing resource streams.
+ /// The loaded image resource.
public object Load(string parPath, IResourceStreamProvider parStreamProvider)
{
using var stream = parStreamProvider.GetStream(parPath);
return Load(stream);
}
+ ///
+ /// Loads the image from a stream and processes it.
+ ///
+ /// The stream containing the image data.
+ /// The processed image resource.
+ /// Thrown if the image cannot be loaded from the stream.
internal static Asset.Image Load(Stream parStream)
{
var sharpImage = Image.Load(parStream);
diff --git a/Engine/src/Resource/Loader/MeshLoader.cs b/Engine/src/Resource/Loader/MeshLoader.cs
index a8e6152..467f2dc 100644
--- a/Engine/src/Resource/Loader/MeshLoader.cs
+++ b/Engine/src/Resource/Loader/MeshLoader.cs
@@ -2,8 +2,18 @@
namespace Engine.Resource.Loader;
+///
+/// Loads mesh resources from various formats, such as .obj and .stl.
+///
public class MeshLoader : IResourceLoader
{
+ ///
+ /// Loads a mesh resource based on the file extension and stream provider.
+ ///
+ /// The path to the mesh resource.
+ /// The provider for accessing resource streams.
+ /// The loaded mesh resource.
+ /// Thrown if the mesh format is unsupported.
public object Load(string parPath, IResourceStreamProvider parStreamProvider)
{
var extension = Path.GetExtension(parPath);
diff --git a/Engine/src/Resource/Loader/ProgramLoader.cs b/Engine/src/Resource/Loader/ProgramLoader.cs
index d216546..274f6a7 100644
--- a/Engine/src/Resource/Loader/ProgramLoader.cs
+++ b/Engine/src/Resource/Loader/ProgramLoader.cs
@@ -4,8 +4,17 @@ using Engine.Graphics.Shader;
namespace Engine.Resource.Loader;
+///
+/// Loads shader program resources, including vertex and fragment shaders.
+///
public partial class ProgramLoader : IResourceLoader
{
+ ///
+ /// Loads a shader program from the specified path and stream provider, separating vertex and fragment shaders.
+ ///
+ /// The path to the shader program resource.
+ /// The provider for accessing resource streams.
+ /// The loaded shader program.
public object Load(string parPath, IResourceStreamProvider parStreamProvider)
{
var textReader = new StreamReader(parStreamProvider.GetStream(parPath));
diff --git a/Engine/src/Resource/Loader/TextureLoader.cs b/Engine/src/Resource/Loader/TextureLoader.cs
index 7530a13..56f7e98 100644
--- a/Engine/src/Resource/Loader/TextureLoader.cs
+++ b/Engine/src/Resource/Loader/TextureLoader.cs
@@ -1,7 +1,16 @@
namespace Engine.Resource.Loader;
+///
+/// Loads texture resources, including image processing and conversion to static textures.
+///
public class TextureLoader : IResourceLoader
{
+ ///
+ /// Loads the texture from the specified path and stream provider.
+ ///
+ /// The path to the texture resource.
+ /// The provider for accessing resource streams.
+ /// The loaded texture resource.
public object Load(string parPath, IResourceStreamProvider parStreamProvider)
{
using var stream = parStreamProvider.GetStream(parPath);
diff --git a/Engine/src/Resource/MemoryResourceStreamProvider.cs b/Engine/src/Resource/MemoryResourceStreamProvider.cs
index 6b127ea..1968ecc 100644
--- a/Engine/src/Resource/MemoryResourceStreamProvider.cs
+++ b/Engine/src/Resource/MemoryResourceStreamProvider.cs
@@ -1,14 +1,30 @@
namespace Engine.Resource;
+///
+/// Provides resource streams from in-memory storage.
+///
public class MemoryResourceStreamProvider : IResourceStreamProvider
{
+ ///
+ /// A dictionary mapping resource paths to their byte data.
+ ///
private readonly Dictionary _resources = new();
+ ///
+ /// Retrieves a stream for the resource stored in memory at the specified path.
+ ///
+ /// The path to the in-memory resource.
+ /// A stream providing access to the resource data.
public Stream GetStream(string parPath)
{
return new MemoryStream(_resources[parPath]);
}
+ ///
+ /// Adds a resource to the in-memory storage.
+ ///
+ /// The path to associate with the resource.
+ /// The byte array representing the resource data.
internal void AddResource(string parPath, byte[] parData)
{
_resources.Add(parPath, parData);
diff --git a/Engine/src/Resource/ResourceManager.cs b/Engine/src/Resource/ResourceManager.cs
index e040edb..553bcd4 100644
--- a/Engine/src/Resource/ResourceManager.cs
+++ b/Engine/src/Resource/ResourceManager.cs
@@ -1,17 +1,42 @@
namespace Engine.Resource;
+///
+/// Manages loading and caching of resources.
+///
public class ResourceManager : IResourceManager
{
+ ///
+ /// The provider for resource streams.
+ ///
internal IResourceStreamProvider StreamProvider { get; }
+ ///
+ /// A dictionary mapping resource types to their respective loaders.
+ ///
private readonly Dictionary _loaders = new();
+
+ ///
+ /// A dictionary mapping resource types to their cached resources.
+ ///
private readonly Dictionary _storages = new();
+ ///
+ /// Initializes a new instance of the class with the specified stream provider.
+ ///
+ /// The stream provider used for resource loading.
public ResourceManager(IResourceStreamProvider parStreamProvider)
{
StreamProvider = parStreamProvider;
}
+ ///
+ /// Loads a resource of the specified type from the given path, using the appropriate loader.
+ /// If the resource is already cached, it is returned from the cache.
+ ///
+ /// The type of the resource to load.
+ /// The path to the resource.
+ /// The loaded resource.
+ /// Thrown when no loader is registered for the specified resource type.
public T Load(string parPath) where T : class
{
if (!_storages.TryGetValue(typeof(T), out var storage))
@@ -38,30 +63,60 @@ public class ResourceManager : IResourceManager
return (T)resource;
}
+ ///
+ /// Registers a loader for a specific resource type.
+ ///
+ /// The type of resource the loader is responsible for.
+ /// The loader to register.
internal void RegisterLoader(IResourceLoader parLoader) where T : class
{
_loaders.Add(typeof(T), parLoader);
}
+ ///
+ /// Clears all cached resources.
+ ///
internal void Reset()
{
_storages.Clear();
}
+ ///
+ /// A helper class for storing resources in memory, indexed by their path.
+ ///
private class ResourceStorage
{
+ ///
+ /// A dictionary mapping resource paths to the resources themselves.
+ ///
private readonly Dictionary _resources = new();
+ ///
+ /// Adds a resource to the storage.
+ ///
+ /// The type of resource to store.
+ /// The path of the resource.
+ /// The resource to store.
public void Add(string parPath, T parResource) where T : class
{
_resources.Add(parPath, parResource);
}
+ ///
+ /// Retrieves a resource from storage by its path.
+ ///
+ /// The type of resource to retrieve.
+ /// The path of the resource.
+ /// The resource, or null if not found.
public T? Get(string parPath) where T : class
{
return _resources.TryGetValue(parPath, out var resource) ? (T)resource : null;
}
+ ///
+ /// Removes a resource from storage by its path.
+ ///
+ /// The path of the resource to remove.
public void Remove(string parPath)
{
_resources.Remove(parPath);
diff --git a/Engine/src/Scene/Component/BuiltIn/Camera.cs b/Engine/src/Scene/Component/BuiltIn/Camera.cs
index 39a690d..23162f6 100644
--- a/Engine/src/Scene/Component/BuiltIn/Camera.cs
+++ b/Engine/src/Scene/Component/BuiltIn/Camera.cs
@@ -4,22 +4,18 @@ using OpenTK.Mathematics;
namespace Engine.Scene.Component.BuiltIn;
-public abstract class Camera(
- float parNearPlane,
- float parFarPlane
-) : Component, ICamera
+///
+/// Abstract base class for cameras that provide view and projection matrices.
+///
+public abstract class Camera : Component, ICamera
{
- public float AspectRatio { get; private set; } = 1;
- public float NearPlane { get; set; } = parNearPlane;
- public float FarPlane { get; set; } = parFarPlane;
-
- public RenderLayer RenderLayer { get; set; } = RenderLayer.DEFAULT;
-
- private Vector2i _screenSize = new(1, 1);
-
+ ///
public abstract Matrix4 View { get; }
+
+ ///
public abstract Matrix4 Projection { get; }
+ ///
public Vector2i ScreenSize
{
get => _screenSize;
@@ -30,6 +26,54 @@ public abstract class Camera(
}
}
+ ///
+ /// The aspect ratio of the camera, calculated as width divided by height.
+ ///
+ public float AspectRatio { get; private set; } = 1;
+
+ ///
+ /// The near clipping plane distance.
+ ///
+ public float NearPlane { get; set; }
+
+ ///
+ /// The far clipping plane distance.
+ ///
+ public float FarPlane { get; set; }
+
+ ///
+ /// The render layer for the camera.
+ ///
+ public RenderLayer RenderLayer { get; set; } = RenderLayer.DEFAULT;
+
+
+ ///
+ /// The screen size of the camera.
+ ///
+ private Vector2i _screenSize = new(1, 1);
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The near clipping plane distance.
+ /// The far clipping plane distance.
+ protected Camera(float parNearPlane, float parFarPlane)
+ {
+ NearPlane = parNearPlane;
+ FarPlane = parFarPlane;
+ }
+
+ ///
+ /// Converts a screen position to a world position in 3D space.
+ ///
+ /// The screen position to convert.
+ /// The corresponding world position.
public abstract Vector3 ScreenToWorld(Vector2 parScreenPosition);
+
+ ///
+ /// Converts a world position to a screen position in 2D space.
+ ///
+ /// The world position to convert.
+ /// The corresponding screen position.
public abstract Vector2 WorldToScreen(Vector3 parWorldPosition);
}
\ No newline at end of file
diff --git a/Engine/src/Scene/Component/BuiltIn/OrthographicCamera.cs b/Engine/src/Scene/Component/BuiltIn/OrthographicCamera.cs
index 79af865..e0068ab 100644
--- a/Engine/src/Scene/Component/BuiltIn/OrthographicCamera.cs
+++ b/Engine/src/Scene/Component/BuiltIn/OrthographicCamera.cs
@@ -3,33 +3,56 @@ using OpenTK.Mathematics;
namespace Engine.Scene.Component.BuiltIn;
-public class OrthographicCamera(
- float parNearPlane = -10000f,
- float parFarPlane = 10000f,
- float parSize = 10f,
- OrthographicCamera.Axis parAxis = OrthographicCamera.Axis.Y
-)
- : Camera(parNearPlane, parFarPlane)
+///
+/// Represents a camera using an orthographic projection.
+///
+public class OrthographicCamera : Camera
{
+ ///
+ /// The axis fixed during scaling.
+ ///
public enum Axis
{
X,
Y
}
+ ///
public override Matrix4 Projection => GetProjectionMatrix();
+
+ ///
public override Matrix4 View => GameObject.Transform.TransformMatrix.Inverted();
- public float Size { get; set; } = parSize;
- public bool UseScreenSize { get; set; } = false;
- public Axis FixedAxis { get; set; } = parAxis;
+ ///
+ /// The size of the orthographic view.
+ ///
+ public float Size { get; set; }
- private Matrix4 GetProjectionMatrix()
+ ///
+ /// Indicates whether to scale based on screen dimensions.
+ ///
+ public bool UseScreenSize { get; set; } = false;
+
+ ///
+ /// The axis to keep fixed when scaling the view.
+ ///
+ public Axis FixedAxis { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The near clipping plane distance.
+ /// The far clipping plane distance.
+ /// The size of the orthographic view.
+ /// The fixed axis for scaling.
+ public OrthographicCamera(float parNearPlane = -10000f, float parFarPlane = 10000f, float parSize = 10f,
+ Axis parAxis = Axis.Y) : base(parNearPlane, parFarPlane)
{
- var size = GameObject.Transform.Size.Xy;
- return Matrix4.CreateOrthographic(size.X, size.Y, -NearPlane, -FarPlane);
+ Size = parSize;
+ FixedAxis = parAxis;
}
+ ///
public override Vector3 ScreenToWorld(Vector2 parScreenPosition)
{
var normalized = (parScreenPosition / ScreenSize) - new Vector2(0.5f);
@@ -42,6 +65,7 @@ public class OrthographicCamera(
.Xyz;
}
+ ///
public override Vector2 WorldToScreen(Vector3 parWorldPosition)
{
var normalized = new Vector4(parWorldPosition, 1)
@@ -55,6 +79,7 @@ public class OrthographicCamera(
return (normalized + new Vector2(0.5f)) * ScreenSize;
}
+ ///
public override void Update(double parDeltaTime)
{
if (UseScreenSize)
@@ -75,4 +100,14 @@ public class OrthographicCamera(
}
}
}
+
+ ///
+ /// Generates the orthographic projection matrix for the camera.
+ ///
+ /// The orthographic projection matrix.
+ private Matrix4 GetProjectionMatrix()
+ {
+ var size = GameObject.Transform.Size.Xy;
+ return Matrix4.CreateOrthographic(size.X, size.Y, -NearPlane, -FarPlane);
+ }
}
\ No newline at end of file
diff --git a/Engine/src/Scene/Component/BuiltIn/PerspectiveCamera.cs b/Engine/src/Scene/Component/BuiltIn/PerspectiveCamera.cs
index d20d752..c60c80c 100644
--- a/Engine/src/Scene/Component/BuiltIn/PerspectiveCamera.cs
+++ b/Engine/src/Scene/Component/BuiltIn/PerspectiveCamera.cs
@@ -3,33 +3,42 @@ using OpenTK.Mathematics;
namespace Engine.Scene.Component.BuiltIn;
-public class PerspectiveCamera(
- float parFieldOfView = 60.0f,
- float parNearPlane = 0.01f,
- float parFarPlane = 1000f
-)
- : Camera(parNearPlane, parFarPlane)
+///
+/// Represents a camera using a perspective projection.
+///
+public class PerspectiveCamera : Camera
{
- public override Matrix4 View
- {
- get
- {
- var transformMatrix = GameObject.Transform.TransformMatrix;
- var forward = new Vector4(0, 1, 0, 1).MulProject(in transformMatrix);
- var eye = new Vector4(0, 0, 0, 1).MulProject(in transformMatrix);
- var up = (new Vector4(0, 0, 1, 1).MulProject(in transformMatrix) - eye).Normalized();
-
- return Matrix4.LookAt(eye.Xyz, forward.Xyz, up.Xyz);
- }
- }
+ ///
+ public override Matrix4 View => GetProjectionMatrix();
+ ///
public override Matrix4 Projection =>
Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(FieldOfView), AspectRatio,
NearPlane, FarPlane);
+ ///
+ /// The forward direction of the camera.
+ ///
public Vector3 Forward => new Vector4(0, 1, 0, 1).MulProject(GameObject.Transform.TransformMatrix).Xyz;
- public float FieldOfView { get; set; } = parFieldOfView;
+ ///
+ /// The vertical field of view of the camera, in degrees.
+ ///
+ public float FieldOfView { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The vertical field of view, in degrees.
+ /// The near clipping plane distance.
+ /// The far clipping plane distance.
+ public PerspectiveCamera(float parFieldOfView = 60.0f, float parNearPlane = 0.01f, float parFarPlane = 1000f) : base(
+ parNearPlane, parFarPlane)
+ {
+ FieldOfView = parFieldOfView;
+ }
+
+ ///
public override Vector3 ScreenToWorld(Vector2 parScreenPosition)
{
var normalized = (parScreenPosition / ScreenSize) - new Vector2(0.5f);
@@ -42,6 +51,7 @@ public class PerspectiveCamera(
.Xyz;
}
+ ///
public override Vector2 WorldToScreen(Vector3 parWorldPosition)
{
var normalized = new Vector4(parWorldPosition, 1)
@@ -54,4 +64,18 @@ public class PerspectiveCamera(
return (normalized + new Vector2(0.5f)) * ScreenSize;
}
+
+ ///
+ /// Generates the perspective projection matrix for the camera.
+ ///
+ /// The perspective projection matrix.
+ private Matrix4 GetProjectionMatrix()
+ {
+ var transformMatrix = GameObject.Transform.TransformMatrix;
+ var forward = new Vector4(0, 1, 0, 1).MulProject(in transformMatrix);
+ var eye = new Vector4(0, 0, 0, 1).MulProject(in transformMatrix);
+ var up = (new Vector4(0, 0, 1, 1).MulProject(in transformMatrix) - eye).Normalized();
+
+ return Matrix4.LookAt(eye.Xyz, forward.Xyz, up.Xyz);
+ }
}
\ No newline at end of file
diff --git a/Engine/src/Scene/Component/BuiltIn/Renderer/Box2DRenderer.cs b/Engine/src/Scene/Component/BuiltIn/Renderer/Box2DRenderer.cs
index f553188..6e1636e 100644
--- a/Engine/src/Scene/Component/BuiltIn/Renderer/Box2DRenderer.cs
+++ b/Engine/src/Scene/Component/BuiltIn/Renderer/Box2DRenderer.cs
@@ -4,14 +4,32 @@ using OpenTK.Mathematics;
namespace Engine.Scene.Component.BuiltIn.Renderer;
+///
+/// A component for rendering 2D boxes with an optional texture and color.
+///
public class Box2DRenderer : Component
{
+ ///
+ /// The color of the box.
+ ///
public ref Vector4 Color => ref _color;
+
+ ///
+ /// The texture of the box.
+ ///
public Texture? Texture { get; set; }
+
+ ///
+ /// The render layer for the box.
+ ///
public RenderLayer RenderLayer { get; set; } = RenderLayer.DEFAULT;
+ ///
+ /// The color of the box.
+ ///
private Vector4 _color = Vector4.One;
+ ///
public override void Render()
{
Engine.Instance.Renderer[RenderLayer].QuadRenderer
diff --git a/Engine/src/Scene/Component/BuiltIn/Renderer/MeshRenderer.cs b/Engine/src/Scene/Component/BuiltIn/Renderer/MeshRenderer.cs
index 47ce443..9d73e6e 100644
--- a/Engine/src/Scene/Component/BuiltIn/Renderer/MeshRenderer.cs
+++ b/Engine/src/Scene/Component/BuiltIn/Renderer/MeshRenderer.cs
@@ -4,12 +4,27 @@ using Engine.Graphics.Texture;
namespace Engine.Scene.Component.BuiltIn.Renderer;
+///
+/// A component for rendering 3D meshes with optional albedo textures.
+///
public class MeshRenderer : Component
{
+ ///
+ /// The mesh to be rendered.
+ ///
public Mesh Mesh { get; set; } = null!;
+
+ ///
+ /// The albedo texture for the mesh.
+ ///
public Texture? Albedo { get; set; } = null;
+
+ ///
+ /// The render layer for the mesh.
+ ///
public RenderLayer RenderLayer { get; set; } = RenderLayer.DEFAULT;
+ ///
public override void Render()
{
Engine.Instance.Renderer[RenderLayer].AnyMeshRenderer
diff --git a/Engine/src/Scene/Component/BuiltIn/Renderer/TextRenderer.cs b/Engine/src/Scene/Component/BuiltIn/Renderer/TextRenderer.cs
index e43f3b7..8eecd02 100644
--- a/Engine/src/Scene/Component/BuiltIn/Renderer/TextRenderer.cs
+++ b/Engine/src/Scene/Component/BuiltIn/Renderer/TextRenderer.cs
@@ -4,15 +4,37 @@ using OpenTK.Mathematics;
namespace Engine.Scene.Component.BuiltIn.Renderer;
+///
+/// A component for rendering text with a specified font, color, and render layer.
+///
public class TextRenderer : Component
{
+ ///
+ /// The font used for rendering the text.
+ ///
public Font Font { get; set; } = null!;
+
+ ///
+ /// The color of the text.
+ ///
public ref Vector4 Color => ref _color;
+
+ ///
+ /// The text to be rendered.
+ ///
public string? Text { get; set; }
+
+ ///
+ /// The render layer for the text.
+ ///
public RenderLayer RenderLayer { get; set; } = RenderLayer.DEFAULT;
+ ///
+ /// The color of the text.
+ ///
private Vector4 _color = Vector4.One;
+ ///
public override void Render()
{
if (Text == null)
diff --git a/Engine/src/Scene/Component/BuiltIn/Transform.cs b/Engine/src/Scene/Component/BuiltIn/Transform.cs
index abc82dd..a74b23e 100644
--- a/Engine/src/Scene/Component/BuiltIn/Transform.cs
+++ b/Engine/src/Scene/Component/BuiltIn/Transform.cs
@@ -2,20 +2,51 @@
namespace Engine.Scene.Component.BuiltIn;
+///
+/// Represents the transform component of a game object, encapsulating its position, rotation, scale, and size.
+///
public class Transform : Component
{
+ ///
+ /// The size of the object in local space.
+ ///
public ref Vector3 Size => ref _size;
+
+ ///
+ /// The scaling factor applied to the object in local space.
+ ///
public ref Vector3 Scale => ref _scale;
+
+ ///
+ /// The rotation of the object in local space, represented as a quaternion.
+ ///
public ref Quaternion Rotation => ref _rotation;
+
+ ///
+ /// The translation (position) of the object in local space.
+ ///
public ref Vector3 Translation => ref _translation;
+ ///
+ /// The full transformation matrix that combines size, scaling, rotation, and translation.
+ ///
public Matrix4 FullTransformMatrix => Matrix4.CreateScale(Size) * TransformMatrix;
+
+ ///
+ /// The combined transformation matrix, accounting for local and parent transformations.
+ ///
public Matrix4 TransformMatrix => LocalTransformMatrix * ParentTransformMatrix;
+ ///
+ /// The local transformation matrix, derived from scale, rotation, and translation.
+ ///
public Matrix4 LocalTransformMatrix => Matrix4.CreateScale(Scale) *
Matrix4.CreateFromQuaternion(Rotation) *
Matrix4.CreateTranslation(Translation);
+ ///
+ /// The parent transformation matrix, retrieved from the parent object in the hierarchy.
+ ///
private Matrix4 ParentTransformMatrix
{
get
@@ -25,16 +56,39 @@ public class Transform : Component
}
}
+ ///
+ /// The size of the object in local space.
+ ///
private Vector3 _size = Vector3.One;
+
+ ///
+ /// The scaling factor applied to the object in local space.
+ ///
private Vector3 _scale = Vector3.One;
+
+ ///
+ /// The rotation of the object in local space, represented as a quaternion.
+ ///
private Quaternion _rotation = Quaternion.Identity;
+
+ ///
+ /// The translation (position) of the object in local space.
+ ///
private Vector3 _translation = Vector3.Zero;
+ ///
+ /// Retrieves the full translation of the object in world space.
+ ///
+ /// A representing the object's world position.
public Vector3 GetFullTranslation()
{
return FullTransformMatrix.ExtractTranslation();
}
+ ///
+ /// Creates a clone of the current transform.
+ ///
+ /// A new instance with the same properties as the original.
public Transform Clone()
{
var clone =
diff --git a/Engine/src/Scene/Component/Component.cs b/Engine/src/Scene/Component/Component.cs
index 96be6fa..0caf776 100644
--- a/Engine/src/Scene/Component/Component.cs
+++ b/Engine/src/Scene/Component/Component.cs
@@ -1,46 +1,89 @@
namespace Engine.Scene.Component;
+///
+/// Base class for all components, defining common lifecycle and behavior methods.
+///
public abstract class Component : IUpdate, IRender
{
+ ///
+ /// A unique identifier for the component.
+ ///
public Guid Id { get; } = Guid.NewGuid();
+ ///
+ /// The game object to which this component is attached.
+ ///
public GameObject GameObject { get; internal set; }
+ ///
+ /// Called when the component is initialized.
+ ///
public virtual void Awake()
{
}
+ ///
+ /// Called once at the start of the component's lifecycle.
+ ///
public virtual void Start()
{
}
+ ///
+ /// Called before the main update loop.
+ ///
+ /// Time elapsed since the last frame.
public virtual void PreUpdate(double parDeltaTime)
{
}
+ ///
+ /// Called during the main update loop.
+ ///
+ /// Time elapsed since the last frame.
public virtual void Update(double parDeltaTime)
{
}
+ ///
+ /// Called during the main render loop.
+ ///
public virtual void Render()
{
}
+ ///
+ /// Called when the component is destroyed.
+ ///
public virtual void Destroy()
{
}
+ ///
+ /// Enables the component, allowing it to participate in updates and rendering.
+ ///
public virtual void Enable()
{
}
+ ///
+ /// Disables the component, stopping it from participating in updates and rendering.
+ ///
public virtual void Disable()
{
}
}
-public static class ComponentTypeExtensions
+///
+/// Provides extension methods for component type analysis.
+///
+internal static class ComponentTypeExtensions
{
+ ///
+ /// Retrieves the base type of a component, accounting for inheritance chains.
+ ///
+ /// The type of the component.
+ /// The base of the component.
internal static Type GetComponentBaseType(this Type parType)
{
var baseType = parType.BaseType;
diff --git a/Engine/src/Scene/GameObject.cs b/Engine/src/Scene/GameObject.cs
index bf68c8b..452c845 100644
--- a/Engine/src/Scene/GameObject.cs
+++ b/Engine/src/Scene/GameObject.cs
@@ -4,32 +4,83 @@ using Engine.Scene.Component.BuiltIn;
namespace Engine.Scene;
+///
+/// Represents a game object in the scene, containing components and providing lifecycle management.
+///
public sealed class GameObject : IUpdate, IRender
{
+ ///
+ /// A unique identifier of the game object.
+ ///
public Guid Id { get; } = Guid.NewGuid();
+ ///
+ /// Indicates whether the game object is enabled based on its own state and its parent's state.
+ ///
public bool IsEnabled
{
get => IsSelfEnabled && IsParentEnabled;
set => _nextIsSelfEnabled = value;
}
+ ///
+ /// The transform component associated with this game object.
+ ///
public Transform Transform { get; }
+ ///
+ /// The scene this game object belongs to.
+ ///
internal Scene? Scene { get; set; }
+ ///
+ /// Indicates whether game object's parent is enabled.
+ ///
private bool IsParentEnabled => Scene?.Hierarchy.GetParent(this)?.IsEnabled ?? true;
+
+ ///
+ /// Indicates whether game object is enabled.
+ ///
private bool IsSelfEnabled { get; set; } = true;
- private readonly HashSet _addedComponents = [];
+ ///
+ /// A list of component types added to the game object.
+ ///
private readonly HashSet _addedComponentTypes = [];
- private readonly Queue _componentActions = new();
+
+ ///
+ /// A list of components attached to the game object.
+ ///
private readonly List _components = [];
+
+ ///
+ /// A queue of actions to be performed on the game object.
+ ///
+ private readonly Queue _componentActions = new();
+
+ ///
+ /// A list of components to be added to the game object.
+ ///
+ private readonly HashSet _addedComponents = [];
+
+ ///
+ /// A list of components to be removed from the game object.
+ ///
private readonly HashSet _removedComponents = [];
+ ///
+ /// Indicates whether the game object is going to be enabled next frame.
+ ///
private bool _nextIsSelfEnabled = true;
+
+ ///
+ /// Indicates whether the game object was enabled last frame.
+ ///
private bool _prevIsSelfEnabled = true;
+ ///
+ /// Initializes a new instance of the class with a default transform component.
+ ///
public GameObject()
{
AddComponent();
@@ -38,6 +89,10 @@ public sealed class GameObject : IUpdate, IRender
Transform = GetComponent()!;
}
+ ///
+ /// Initializes a new instance of the class with a specified transform.
+ ///
+ /// The transform to associate with the game object.
public GameObject(Transform parTransform)
{
AddComponent(parTransform.Clone());
@@ -46,6 +101,10 @@ public sealed class GameObject : IUpdate, IRender
Transform = GetComponent()!;
}
+ ///
+ /// Performs pre-update operations for all components.
+ ///
+ /// The time delta since the last update.
public void PreUpdate(double parDeltaTime)
{
ProcessAddedComponents();
@@ -57,6 +116,7 @@ public sealed class GameObject : IUpdate, IRender
}
}
+ ///
public void Update(double parDeltaTime)
{
if (!IsEnabled)
@@ -91,6 +151,7 @@ public sealed class GameObject : IUpdate, IRender
}
}
+ ///
public void Render()
{
if (!IsEnabled)
@@ -104,6 +165,9 @@ public sealed class GameObject : IUpdate, IRender
}
}
+ ///
+ /// Destroys the game object and its components.
+ ///
public void Destroy()
{
foreach (var component in _components)
@@ -112,6 +176,11 @@ public sealed class GameObject : IUpdate, IRender
}
}
+ ///
+ /// Retrieves a component of a specified type if it exists on the game object.
+ ///
+ /// The type of the component to retrieve.
+ /// The component if found, otherwise null.
public T? GetComponent() where T : Component.Component
{
if (!HasComponent())
@@ -130,6 +199,11 @@ public sealed class GameObject : IUpdate, IRender
return null;
}
+ ///
+ /// Retrieves a component of a specified type from the game object or its children.
+ ///
+ /// The type of the component to retrieve.
+ /// The component if found, otherwise null.
public T? GetComponentAny() where T : Component.Component
{
var component = GetComponent();
@@ -142,6 +216,11 @@ public sealed class GameObject : IUpdate, IRender
return component;
}
+ ///
+ /// Retrieves a component of a specified type from the game object's children.
+ ///
+ /// The type of the component to retrieve.
+ /// The component if found, otherwise null.
public T? GetComponentInChildren() where T : Component.Component
{
var children = Scene!.Hierarchy.GetChildren(this);
@@ -164,12 +243,21 @@ public sealed class GameObject : IUpdate, IRender
return null;
}
+ ///
+ /// Adds a new component of a specified type to the game object.
+ ///
+ /// The type of the component to add.
public void AddComponent() where T : Component.Component, new()
{
var component = new T();
AddComponent(component);
}
+ ///
+ /// Adds a new component of a specified type to the game object with optional constructor arguments.
+ ///
+ /// The type of the component to add.
+ /// The arguments to pass to the component's constructor.
public void AddComponent(params object?[] parArgs) where T : Component.Component
{
var component = (T?)Activator.CreateInstance(
@@ -189,6 +277,11 @@ public sealed class GameObject : IUpdate, IRender
AddComponent(component);
}
+ ///
+ /// Adds an existing component to the game object.
+ ///
+ /// The type of the component to add.
+ /// The component to add.
public void AddComponent(T parComponent) where T : Component.Component
{
parComponent.GameObject = this;
@@ -206,6 +299,10 @@ public sealed class GameObject : IUpdate, IRender
});
}
+ ///
+ /// Removes a component of a specified type from the game object.
+ ///
+ /// The type of the component to remove.
public void RemoveComponent() where T : Component.Component
{
if (typeof(T) == typeof(Transform))
@@ -232,12 +329,20 @@ public sealed class GameObject : IUpdate, IRender
});
}
+ ///
+ /// Checks whether the game object contains a component of a specified type.
+ ///
+ /// The type of the component to check for.
+ /// True if the component exists, otherwise false.
public bool HasComponent() where T : Component.Component
{
var baseType = typeof(T).GetComponentBaseType();
return _addedComponentTypes.Contains(baseType);
}
+ ///
+ /// Processes changes to the game object's components.
+ ///
internal void ProcessChanges()
{
IsSelfEnabled = _nextIsSelfEnabled;
@@ -248,6 +353,9 @@ public sealed class GameObject : IUpdate, IRender
}
}
+ ///
+ /// Initializes newly added components.
+ ///
private void ProcessAddedComponents()
{
foreach (var component in _addedComponents)
@@ -259,6 +367,9 @@ public sealed class GameObject : IUpdate, IRender
_addedComponents.Clear();
}
+ ///
+ /// Cleans up and removes components that were marked for removal.
+ ///
private void ProcessRemovedComponents()
{
foreach (var component in _removedComponents)
@@ -270,16 +381,19 @@ public sealed class GameObject : IUpdate, IRender
_removedComponents.Clear();
}
+ ///
public override string ToString()
{
return Id.ToString();
}
+ ///
public override bool Equals(object? parObj)
{
return parObj is GameObject gameObject && Id == gameObject.Id;
}
+ ///
public override int GetHashCode()
{
return HashCode.Combine(Id);
diff --git a/Engine/src/Scene/Hierarchy.cs b/Engine/src/Scene/Hierarchy.cs
index 88c57d8..235a467 100644
--- a/Engine/src/Scene/Hierarchy.cs
+++ b/Engine/src/Scene/Hierarchy.cs
@@ -3,20 +3,47 @@ using Engine.Util;
namespace Engine.Scene;
+///
+/// Manages a hierarchical relationship between objects, supporting parent-child relationships
+/// and enabling traversal, adding/removing of objects within the hierarchy.
+///
+/// The type of the objects in the hierarchy. Must be a reference type.
public class Hierarchy
where T : class
{
+ ///
+ /// A collection of all objects in the hierarchy (all keys in the parent lookup dictionary).
+ ///
internal Dictionary.KeyCollection Objects => _parentLookup.Keys;
+ ///
+ /// A dictionary mapping objects to their children.
+ ///
private readonly Dictionary, IList> _childrenLookup = new();
+
+ ///
+ /// A dictionary mapping objects to their parent.
+ ///
private readonly Dictionary _parentLookup = new();
+
+ ///
+ /// A queue of actions to be processed.
+ ///
private readonly ConcurrentQueue _hierarchyActions = new();
+ ///
+ /// Initializes a new instance of the class.
+ /// Adds a root element with a null value to represent the root node.
+ ///
public Hierarchy()
{
_childrenLookup.Add(new NullableObject(), new List());
}
+ ///
+ /// Processes queued actions related to changes in the hierarchy (e.g., adding/removing objects).
+ /// This method is invoked to ensure the changes are executed in the proper order.
+ ///
internal void ProcessChanges()
{
while (_hierarchyActions.TryDequeue(out var action))
@@ -25,6 +52,11 @@ public class Hierarchy
}
}
+ ///
+ /// Adds an object to the hierarchy. This method will create a new entry in the hierarchy
+ /// with the object having no parent initially, and will add it as a child of the root.
+ ///
+ /// The object to add to the hierarchy.
public void Add(T parObj)
{
_hierarchyActions.Enqueue(() =>
@@ -40,6 +72,11 @@ public class Hierarchy
});
}
+ ///
+ /// Removes an object from the hierarchy and all its descendants.
+ /// The object will be deleted, and its references will be removed from both parent and child lookup dictionaries.
+ ///
+ /// The object to remove from the hierarchy.
public void Remove(T parObj)
{
foreach (var child in GetChildren(parObj))
@@ -62,11 +99,23 @@ public class Hierarchy
});
}
+ ///
+ /// Adds a child object to a specific parent in the hierarchy.
+ /// This sets the given object's parent and adds it to the parent's list of children.
+ ///
+ /// The parent object.
+ /// The child object to add to the parent.
public void AddChild(T parParent, T parChild)
{
SetParent(parChild, parParent);
}
+ ///
+ /// Sets the parent of an object in the hierarchy.
+ /// This method will remove the object from its current parent and add it to the new parent.
+ ///
+ /// The child object whose parent is being changed.
+ /// The new parent of the child object.
private void SetParent(T parChild, T? parParent)
{
if (parChild.Equals(parParent))
@@ -89,11 +138,22 @@ public class Hierarchy
});
}
+ ///
+ /// Determines if an object exists in the hierarchy.
+ ///
+ /// The object to check for presence in the hierarchy.
+ /// True if the object exists in the hierarchy, otherwise false.
public bool Contains(T parObj)
{
return _parentLookup.ContainsKey(parObj) && _childrenLookup.ContainsKey(parObj);
}
+ ///
+ /// Gets the parent of a given child object in the hierarchy.
+ ///
+ /// The child object whose parent is to be retrieved.
+ /// The parent object of the given child.
+ /// Thrown if the child is not found in the hierarchy.
public T? GetParent(T parChild)
{
return _parentLookup.TryGetValue(parChild, out var parent)
@@ -101,11 +161,22 @@ public class Hierarchy
: throw new InvalidOperationException($"Child {parChild} is not in hierarchy");
}
+ ///
+ /// Gets the children of a given parent object in the hierarchy.
+ /// If no parent is provided, it retrieves the children of the root node.
+ ///
+ /// The parent object whose children are to be retrieved. Null refers to the root.
+ /// A collection of child objects of the specified parent.
public IEnumerable GetChildren(T? parParent = null)
{
return _childrenLookup.TryGetValue(parParent, out var children) ? children : Enumerable.Empty();
}
+ ///
+ /// Gets all descendants of a given parent object in the hierarchy, recursively.
+ ///
+ /// The parent object whose descendants are to be retrieved. Null refers to the root.
+ /// A collection of all descendant objects of the specified parent.
public IEnumerable GetAllChildren(T? parParent = null)
{
var children = GetChildren(parParent);
@@ -121,6 +192,12 @@ public class Hierarchy
}
}
+ ///
+ /// Checks if a given child object is in the hierarchy of a given ancestor object.
+ ///
+ /// The ancestor object to check.
+ /// The child object to check for inclusion in the hierarchy.
+ /// True if the child is in the hierarchy of the ancestor, otherwise false.
public bool IsInHierarchy(T? parAncestor, T? parChild)
{
if (parChild == null) // if child is null (root), then it is not in hierarchy, as root can not have a parent
diff --git a/Engine/src/Scene/IRender.cs b/Engine/src/Scene/IRender.cs
index 5add892..f2ec338 100644
--- a/Engine/src/Scene/IRender.cs
+++ b/Engine/src/Scene/IRender.cs
@@ -1,6 +1,12 @@
namespace Engine.Scene;
+///
+/// Defines an interface for rendering objects.
+///
public interface IRender
{
- void Render();
+ ///
+ /// Renders the object.
+ ///
+ public void Render();
}
\ No newline at end of file
diff --git a/Engine/src/Scene/IUpdate.cs b/Engine/src/Scene/IUpdate.cs
index 2cd9d83..c45b091 100644
--- a/Engine/src/Scene/IUpdate.cs
+++ b/Engine/src/Scene/IUpdate.cs
@@ -1,6 +1,13 @@
namespace Engine.Scene;
+///
+/// Defines an interface for updating logic over time.
+///
public interface IUpdate
{
- void Update(double parDeltaTime);
+ ///
+ /// Updates the state of the object.
+ ///
+ /// The time elapsed since the last update, in seconds.
+ public void Update(double parDeltaTime);
}
\ No newline at end of file
diff --git a/Engine/src/Scene/Scene.cs b/Engine/src/Scene/Scene.cs
index 925fc65..3c0bd19 100644
--- a/Engine/src/Scene/Scene.cs
+++ b/Engine/src/Scene/Scene.cs
@@ -4,17 +4,43 @@ using Engine.Scene.Component.BuiltIn;
namespace Engine.Scene;
+///
+/// Represents a scene in the game, managing the scene hierarchy and rendering the scene.
+///
public class Scene : IUpdate, IRender
{
+ ///
+ /// Determines whether the scene is currently playing.
+ ///
public bool IsPlaying { get; private set; }
+
+ ///
+ /// The time scale for updating the scene. A value of 1.0 means normal speed.
+ ///
public float TimeScale { get; set; } = 1.0f;
+ ///
+ /// A hierarchy of game objects in the scene.
+ ///
internal Hierarchy Hierarchy { get; } = new();
+
+ ///
+ /// A read-only dictionary of cameras, categorized by render layer.
+ ///
internal IReadOnlyDictionary Cameras => _cameras;
+ ///
+ /// A dictionary of cameras, categorized by render layer.
+ ///
private readonly Dictionary _cameras = new();
+
+ ///
+ /// A private queue used to enqueue scene-related actions that should be processed later.
+ /// Actions are executed when the scene is processed for changes.
+ ///
private readonly Queue _sceneActions = [];
+ ///
public void Update(double parDeltaTime)
{
if (!IsPlaying)
@@ -37,6 +63,7 @@ public class Scene : IUpdate, IRender
}
}
+ ///
public void Render()
{
if (!IsPlaying)
@@ -50,6 +77,12 @@ public class Scene : IUpdate, IRender
}
}
+ ///
+ /// Finds all components of type in the scene.
+ ///
+ /// The type of component to find.
+ /// If true, only enabled components are returned.
+ /// A list of components of type .
public List FindAllComponents(bool parOnlyEnabled = true) where T : Component.Component
{
return Hierarchy.Objects
@@ -60,24 +93,42 @@ public class Scene : IUpdate, IRender
.ToList()!;
}
+ ///
+ /// Finds the first component of type in the scene.
+ ///
+ /// The type of component to find.
+ /// The first component of type , or null if not found.
public T? FindFirstComponent() where T : Component.Component
{
return Hierarchy.Objects.Select(parGameObject => parGameObject.GetComponent())
.FirstOrDefault(parComponent => parComponent != null);
}
+ ///
+ /// Adds a game object to the scene.
+ ///
+ /// The game object to add.
public void Add(GameObject parGameObject)
{
parGameObject.Scene = this;
Hierarchy.Add(parGameObject);
}
+ ///
+ /// Adds a child game object to the specified parent game object in the scene.
+ ///
+ /// The parent game object.
+ /// The child game object to add.
public void AddChild(GameObject parParent, GameObject parChild)
{
Add(parChild);
Hierarchy.AddChild(parParent, parChild);
}
+ ///
+ /// Removes a game object from the scene.
+ ///
+ /// The game object to remove.
public void Remove(GameObject parGameObject)
{
var children = Hierarchy.GetAllChildren(parGameObject).ToList();
@@ -97,11 +148,20 @@ public class Scene : IUpdate, IRender
});
}
+ ///
+ /// Gets the children of a parent game object.
+ ///
+ /// The parent game object.
+ /// If true, recursively retrieves all children; otherwise, retrieves only direct children.
+ /// An enumeration of the child game objects.
public IEnumerable GetChildren(GameObject parParent, bool parRecursive = false)
{
return parRecursive ? Hierarchy.GetAllChildren(parParent) : Hierarchy.GetChildren(parParent);
}
+ ///
+ /// Enters the scene by adding all cameras and setting the scene state to playing.
+ ///
internal void Enter()
{
if (IsPlaying)
@@ -120,6 +180,9 @@ public class Scene : IUpdate, IRender
IsPlaying = true;
}
+ ///
+ /// Exits the scene and destroys all game objects in the scene
+ ///
internal void Exit()
{
if (!IsPlaying)
@@ -135,6 +198,9 @@ public class Scene : IUpdate, IRender
IsPlaying = false;
}
+ ///
+ /// Processes changes in the hierarchy and scene actions.
+ ///
private void ProcessChanges()
{
Hierarchy.ProcessChanges();
diff --git a/Engine/src/Scene/SceneManager.cs b/Engine/src/Scene/SceneManager.cs
index 84ca403..5910237 100644
--- a/Engine/src/Scene/SceneManager.cs
+++ b/Engine/src/Scene/SceneManager.cs
@@ -1,11 +1,22 @@
namespace Engine.Scene;
+///
+/// Manages the current scene in the game, handles scene transitions, and facilitates updating and rendering the current scene.
+///
public class SceneManager : IUpdate, IRender
{
+ ///
+ /// The current scene being managed by the scene manager.
+ ///
public Scene? CurrentScene { get; private set; }
+ ///
+ /// A function to be called to transition to the next scene.
+ /// This is set by the scene manager when transitioning to a new scene and reset after the transition is complete.
+ ///
private Func? _nextScene;
+ ///
public void Update(double parDeltaTime)
{
if (_nextScene != null)
@@ -22,11 +33,16 @@ public class SceneManager : IUpdate, IRender
}
}
+ ///
public void Render()
{
CurrentScene?.Render();
}
+ ///
+ /// Queues a scene transition by setting the next scene to transition to.
+ ///
+ /// A function that provides the next scene to transition to.
public void TransitionTo(Func? parScene)
{
_nextScene = parScene;
diff --git a/Engine/src/Util/EngineUtil.cs b/Engine/src/Util/EngineUtil.cs
index f463d1c..4f44094 100644
--- a/Engine/src/Util/EngineUtil.cs
+++ b/Engine/src/Util/EngineUtil.cs
@@ -4,19 +4,45 @@ using Engine.Scene;
namespace Engine.Util;
+///
+/// Provides utility functions and properties for interacting with the engine's core services,
+/// including input handling, scene management, and asset management.
+///
public static class EngineUtil
{
+ ///
+ /// The engine's input handler, which processes user input.
+ ///
public static IInputHandler InputHandler => Engine.Instance.InputHandler!;
+
+ ///
+ /// The engine's scene manager, which handles the current scene and scene transitions.
+ ///
public static SceneManager SceneManager => Engine.Instance.SceneManager;
+
+ ///
+ /// The engine's asset resource manager, which handles loading and caching of assets.
+ ///
public static IResourceManager AssetResourceManager => Engine.Instance.AssetResourceManager;
+
+ ///
+ /// The engine's data folder, which contains assets and other data files.
+ ///
public static string DataFolder => Engine.Instance.DataFolder;
+ ///
+ /// Creates a game object and adds it to the current scene.
+ ///
+ /// The game object to be added to the scene.
public static void CreateObject(GameObject parGameObject)
{
var scene = Engine.Instance.SceneManager.CurrentScene!;
scene.Add(parGameObject);
}
+ ///
+ /// Closes the engine, shutting down any running systems and freeing resources.
+ ///
public static void Close()
{
Engine.Instance.Close();
diff --git a/Engine/src/Util/Math.cs b/Engine/src/Util/Math.cs
index 945d266..6c32f38 100644
--- a/Engine/src/Util/Math.cs
+++ b/Engine/src/Util/Math.cs
@@ -2,8 +2,17 @@
namespace Engine.Util;
+///
+/// Contains mathematical utility methods.
+///
public static class Math
{
+ ///
+ /// Multiplies a by a and performs projective division.
+ ///
+ /// The vector to be multiplied.
+ /// The matrix to multiply the vector with.
+ /// A transformed after multiplication and projective division.
public static Vector4 MulProject(this Vector4 parA, in Matrix4 parM)
{
var result = parA * parM;
diff --git a/Engine/src/Util/NullableObject.cs b/Engine/src/Util/NullableObject.cs
index eb52b3b..7ff256f 100644
--- a/Engine/src/Util/NullableObject.cs
+++ b/Engine/src/Util/NullableObject.cs
@@ -1,35 +1,67 @@
namespace Engine.Util;
-public readonly struct NullableObject(T? parValue) : IEquatable>
+///
+/// A struct that wraps nullable reference types, providing a way to check if a value is null or not.
+///
+/// The type of the wrapped object, constrained to be a class type.
+public readonly struct NullableObject : IEquatable>
where T : class
{
+ ///
+ /// Determines if the wrapped object is null.
+ ///
public bool IsNull => Value == null;
- public T? Value { get; } = parValue;
+ ///
+ /// The wrapped object.
+ ///
+ public T? Value { get; }
+
+ ///
+ /// Constructs a with a null value.
+ ///
public NullableObject() : this(null)
{
}
+ ///
+ /// Constructs a with the specified value.
+ ///
+ /// The value to wrap.
+ public NullableObject(T? parValue)
+ {
+ Value = parValue;
+ }
+
+ ///
+ /// Implicitly converts the to a nullable value of type .
+ ///
public static implicit operator T?(NullableObject parNullableObject)
{
return parNullableObject.Value;
}
+ ///
+ /// Implicitly converts a nullable value of type to a .
+ ///
public static implicit operator NullableObject(T? parValue)
{
return new NullableObject(parValue);
}
+ ///
public override string ToString()
{
return Value?.ToString() ?? "null";
}
+ ///
public override bool Equals(object? parObj)
{
return parObj is NullableObject other && Equals(other);
}
+ ///
public override int GetHashCode()
{
if (IsNull)
@@ -47,16 +79,23 @@ public readonly struct NullableObject(T? parValue) : IEquatable
public bool Equals(NullableObject parOther)
{
return EqualityComparer.Default.Equals(Value, parOther.Value);
}
+ ///
+ /// Determines whether two instances are equal.
+ ///
public static bool operator ==(NullableObject parLeft, NullableObject parRight)
{
return parLeft.Equals(parRight);
}
+ ///
+ /// Determines whether two instances are not equal.
+ ///
public static bool operator !=(NullableObject parLeft, NullableObject parRight)
{
return !(parLeft == parRight);
diff --git a/Engine/src/Util/TickableTimer.cs b/Engine/src/Util/TickableTimer.cs
index b0cd1fe..426d213 100644
--- a/Engine/src/Util/TickableTimer.cs
+++ b/Engine/src/Util/TickableTimer.cs
@@ -1,12 +1,27 @@
-namespace Engine.Util;
+using Engine.Scene;
-public class TickableTimer
+namespace Engine.Util;
+
+public class TickableTimer : IUpdate
{
+ ///
+ /// Event that is invoked on every update, passing the current time.
+ ///
public event Action? OnUpdate;
+
+ ///
+ /// Event that is invoked when the timer reaches zero and is finished.
+ ///
public event Action? OnFinished;
+ ///
+ /// Indicates whether the timer has finished.
+ ///
public bool IsFinished => _currentTime <= 0;
+ ///
+ /// The current time remaining on the timer.
+ ///
public double CurrentTime
{
get => _currentTime;
@@ -37,6 +52,9 @@ public class TickableTimer
}
}
+ ///
+ /// The total duration of the timer.
+ ///
public double TotalTime
{
get => _totalTime;
@@ -52,9 +70,20 @@ public class TickableTimer
}
}
+ ///
+ /// The current time remaining on the timer.
+ ///
private double _currentTime;
+
+ ///
+ /// The total duration of the timer.
+ ///
private double _totalTime;
+ ///
+ /// Initializes a new with a specified total time.
+ ///
+ /// The total duration of the timer.
public TickableTimer(double parTotalTime)
{
if (parTotalTime <= 0)
@@ -66,11 +95,15 @@ public class TickableTimer
_currentTime = parTotalTime;
}
+ ///
public void Update(double parDeltaTime)
{
CurrentTime -= parDeltaTime;
}
+ ///
+ /// Resets the timer back to its total duration.
+ ///
public void Reset()
{
CurrentTime = TotalTime;
diff --git a/Engine/src/Window.cs b/Engine/src/Window.cs
index 91760b7..83a85d2 100644
--- a/Engine/src/Window.cs
+++ b/Engine/src/Window.cs
@@ -7,19 +7,44 @@ using OpenTK.Windowing.GraphicsLibraryFramework;
namespace Engine;
+///
+/// Represents a window used for rendering and interaction with the user.
+///
public class Window : IPresenter
{
- public event Action? Resize;
+ ///
+ public event Action? OnResize;
+ ///
public int Width { get; private set; }
+
+ ///
public int Height { get; private set; }
+
+ ///
public bool IsExiting => NativeWindow.IsExiting;
+ ///
+ /// The internal native window instance used for rendering and event handling.
+ ///
internal NativeWindow NativeWindow { get; }
+ ///
+ /// The reference to the engine instance associated with this window.
+ ///
private readonly Engine _engine;
+
+ ///
+ /// Indicates whether the window is running in headless mode.
+ ///
private readonly bool _headless;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The engine instance managing this window.
+ /// The native window instance.
+ /// Indicates whether the window is headless.
public Window(Engine parEngine, NativeWindow parWindow, bool parHeadless)
{
_engine = parEngine;
@@ -33,16 +58,18 @@ public class Window : IPresenter
{
Width = parArgs.Width;
Height = parArgs.Height;
- Resize?.Invoke(parArgs);
+ OnResize?.Invoke(parArgs);
};
NativeWindow.VSync = VSyncMode.On;
}
+ ///
public void Update(double parDeltaTime)
{
}
+ ///
public void Render()
{
if (_headless)
@@ -55,6 +82,7 @@ public class Window : IPresenter
NativeWindow.SwapBuffers();
}
+ ///
public void Present(IConstTexture parTexture)
{
if (_headless)
@@ -70,14 +98,22 @@ public class Window : IPresenter
);
}
+ ///
public void Exit()
{
NativeWindow.Close();
}
}
+///
+/// Provides extension methods for the class.
+///
public static class NativeWindowExtensions
{
+ ///
+ /// Swaps the buffers of the specified native window.
+ ///
+ /// The native window instance.
public static unsafe void SwapBuffers(this NativeWindow parWindow)
{
GLFW.SwapBuffers(parWindow.WindowPtr);
diff --git a/PresenterConsole/src/ConsolePresenter.cs b/PresenterConsole/src/ConsolePresenter.cs
index f188a95..ea0f6aa 100644
--- a/PresenterConsole/src/ConsolePresenter.cs
+++ b/PresenterConsole/src/ConsolePresenter.cs
@@ -14,7 +14,7 @@ namespace PresenterConsole;
public class ConsolePresenter : IPresenter
{
- public event Action? Resize;
+ public event Action? OnResize;
public int Width { get; private set; } = 2;
public int Height { get; private set; } = 1;
@@ -104,7 +104,7 @@ public class ConsolePresenter : IPresenter
Width = consoleWidth;
Height = consoleHeight;
- Resize?.Invoke(new ResizeEventArgs(Width / 2 * 4, Height * 4));
+ OnResize?.Invoke(new ResizeEventArgs(Width / 2 * 4, Height * 4));
_framebuffer.Resize(Width / 2, Height);
_consoleOutput.Resize(Width, Height);
diff --git a/PresenterWpf/src/App.xaml.cs b/PresenterWpf/src/App.xaml.cs
index 90686eb..73ced08 100644
--- a/PresenterWpf/src/App.xaml.cs
+++ b/PresenterWpf/src/App.xaml.cs
@@ -91,7 +91,7 @@ public partial class App : Application
private class PresenterWrapper : IPresenter
{
- public event Action? Resize;
+ public event Action? OnResize;
public IPresenter? Presenter
{
@@ -100,12 +100,12 @@ public partial class App : Application
{
if (_presenter != null)
{
- _presenter.Resize -= PresenterResize;
+ _presenter.OnResize -= PresenterResize;
}
if (value != null)
{
- value.Resize += PresenterResize;
+ value.OnResize += PresenterResize;
}
_presenter = value;
@@ -140,7 +140,7 @@ public partial class App : Application
private void PresenterResize(ResizeEventArgs e)
{
- Resize?.Invoke(e);
+ OnResize?.Invoke(e);
}
}
}
\ No newline at end of file
diff --git a/PresenterWpf/src/MainWindow.xaml.cs b/PresenterWpf/src/MainWindow.xaml.cs
index 74ae01b..a923761 100644
--- a/PresenterWpf/src/MainWindow.xaml.cs
+++ b/PresenterWpf/src/MainWindow.xaml.cs
@@ -12,7 +12,7 @@ namespace PresenterWpf;
public partial class MainWindow : Window, IPresenter
{
- public event Action? Resize;
+ public event Action? OnResize;
public new int Width { get; private set; }
public new int Height { get; private set; }
@@ -46,7 +46,7 @@ public partial class MainWindow : Window, IPresenter
if (_scheduledResize)
{
_scheduledResize = false;
- Resize?.Invoke(new ResizeEventArgs(Width, Height));
+ OnResize?.Invoke(new ResizeEventArgs(Width, Height));
}
}