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)); } }