diff --git a/Examples/Tutorial 4.1 - Model Loading/Program.cs b/Examples/Tutorial 4.1 - Model Loading/Program.cs
index a3e0cad..8f974e5 100644
--- a/Examples/Tutorial 4.1 - Model Loading/Program.cs
+++ b/Examples/Tutorial 4.1 - Model Loading/Program.cs
@@ -85,10 +85,11 @@ private static void OnLoad()
Shader = new Shader(Gl, PathExtensions.GetAssemblyPath("shader2.vert"), Default.LightShader, "test");
Texture = new Texture(Gl, "silk.png");
- var model = ObjLoaderFactory.Load(Gl, "Untitled2.obj");
-
- _models.Add(model);
- _models.Add(model);
+ if (ObjLoaderFactory.Load(Gl, "D:\\Untitled2.obj", out var model))
+ {
+ _models.Add(model!);
+ _models.Add(model!);
+ }
}
private static void OnUpdate(double deltaTime)
diff --git a/ObjLoader/DataStore.cs b/ObjLoader/DataStore.cs
index ec82bc1..1840908 100644
--- a/ObjLoader/DataStore.cs
+++ b/ObjLoader/DataStore.cs
@@ -9,14 +9,23 @@
namespace SharpEngine.Core.ObjLoader
{
///
- /// Stores parsed OBJ file data such as vertices, normals, texture coordinates, materials and groups.
- /// This type is used by the OBJ loader type parsers to collect geometry and material information.
+ /// Represents the smoothing group information for a face group.
///
+ /// Determines whether smoothing is enabled for the face group.
+ /// The ID of the smoothing group, if applicable.
+ public readonly record struct SmoothingGroup(bool Enabled, int? GroupId);
+
+
///
/// Stores parsed OBJ file data such as vertices, normals, texture coordinates, materials and groups.
/// This type is used by the OBJ loader type parsers to collect geometry and material information.
///
- public class DataStore : IGroupDataStore, IFaceGroup, ITextureDataStore, INormalDataStore, IVertexDataStore, IMaterialDataStore
+ ///
+ /// TODO: This is probably not implemented corretly.
+ /// We are not handling things on a per-object basis and we are not handling smoothing groups correctly.
+ /// We should probably have a more complex data structure that can handle multiple objects, each with their own groups, materials, and smoothing groups.
+ ///
+ public class DataStore : IGroupDataStore, IFaceGroup, ITextureDataStore, INormalDataStore, IVertexDataStore, IMaterialDataStore, ISmoothingGroupDataStore, IObjectNameDataStore
{
private Group _currentGroup = null!;
@@ -35,6 +44,12 @@ public class DataStore : IGroupDataStore, IFaceGroup, ITextureDataStore, INormal
/// Gets the list of groups present in the file.
public List Groups { get; } = [];
+ /// Gets the list of smoothing groups defined in the file.
+ public List SmoothingGroups { get; } = [];
+
+ /// Gets the name of the object defined in the file, if any.
+ public string ObjectName { get; private set; } = string.Empty;
+
///
/// Initializes a new instance of and creates a default group.
///
@@ -83,5 +98,17 @@ public void AddVertex(Vertex vertex)
///
public void AddMaterial(Material currentMaterial)
=> Materials.Add(currentMaterial);
+
+ ///
+ public void SetSmoothingGroup(int groupNumber)
+ => SmoothingGroups.Add(new SmoothingGroup(true, groupNumber));
+
+ ///
+ public void SetSmoothingGroupOff()
+ => SmoothingGroups.Add(new SmoothingGroup(false, null));
+
+ ///
+ public void SetObjectName(string name)
+ => ObjectName = name;
}
}
\ No newline at end of file
diff --git a/ObjLoader/IObjectNameDataStore.cs b/ObjLoader/IObjectNameDataStore.cs
new file mode 100644
index 0000000..44806a0
--- /dev/null
+++ b/ObjLoader/IObjectNameDataStore.cs
@@ -0,0 +1,13 @@
+namespace SharpEngine.Core.ObjLoader;
+
+///
+/// Holds the name of the object being parsed, allowing it to be set during parsing and retrieved later.
+///
+public interface IObjectNameDataStore
+{
+ ///
+ /// Sets the name of the object being parsed.
+ ///
+ /// The name of the object.
+ void SetObjectName(string name);
+}
\ No newline at end of file
diff --git a/ObjLoader/ISmoothingGroupDataStore.cs b/ObjLoader/ISmoothingGroupDataStore.cs
new file mode 100644
index 0000000..8afc13c
--- /dev/null
+++ b/ObjLoader/ISmoothingGroupDataStore.cs
@@ -0,0 +1,18 @@
+namespace SharpEngine.Core.ObjLoader;
+
+///
+/// Represents a data store for smoothing group information in an OBJ file, allowing the storage of smoothing group lines for later processing.
+///
+public interface ISmoothingGroupDataStore
+{
+ ///
+ /// Sets the current smoothing group to the specified group number.
+ ///
+ /// The smoothing group number.
+ void SetSmoothingGroup(int groupNumber);
+
+ ///
+ /// Turns off the current smoothing group.
+ ///
+ void SetSmoothingGroupOff();
+}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/LoaderBase.cs b/ObjLoader/Loaders/LoaderBase.cs
index 5253b8f..206c6d5 100644
--- a/ObjLoader/Loaders/LoaderBase.cs
+++ b/ObjLoader/Loaders/LoaderBase.cs
@@ -1,3 +1,5 @@
+using Microsoft.Extensions.Logging;
+using SharpEngine.Telemetry;
using System.IO;
using System.IO.Abstractions;
@@ -11,6 +13,8 @@ public abstract class LoaderBase
private readonly IFileStreamFactory _fileStreamFactory;
private readonly IFileManager _fileManager;
+ private readonly ILogger _logger = LoggingExtensions.CreateLogger();
+
///
/// Initializes a new instance of the .
///
@@ -27,8 +31,15 @@ protected LoaderBase(IFileStreamFactory fileStreamFactory, IFileManager fileMana
/// I/O exceptions (for example FileNotFoundException, UnauthorizedAccessException, IOException) are propagated to the caller.
///
/// The path of the file to open and parse.
- public void ParseFile(string path)
+ /// if the file was parsed successfully; otherwise, .
+ public bool ParseFile(string path)
{
+ if (!_fileStreamFactory.FileSystem.File.Exists(path))
+ {
+ _logger.LogError("File not found: {Path}", path);
+ return false;
+ }
+
using var fileStream = _fileStreamFactory.FileSystem.FileStream.New(path, FileMode.Open, FileAccess.Read);
using var lineStreamReader = _fileManager.StreamReader(path);
@@ -37,20 +48,28 @@ public void ParseFile(string path)
var currentLine = lineStreamReader.ReadLine();
if (!string.IsNullOrWhiteSpace(currentLine))
- ParseLine(currentLine);
+ {
+ if (!ParseLine(currentLine))
+ {
+ _logger.LogError("Failed to parse line: {Line}", currentLine);
+ // return false;
+ }
+ }
}
+
+ return true;
}
- private void ParseLine(string currentLine)
+ private bool ParseLine(string currentLine)
{
if (currentLine[0] == '#')
- return;
+ return true;
var fields = currentLine.Trim().Split(null, 2);
var keyword = fields[0].Trim();
var data = fields[1].Trim();
- ParseLine(keyword, data);
+ return ParseLine(keyword, data);
}
///
@@ -58,6 +77,7 @@ private void ParseLine(string currentLine)
///
/// Keyword that identifies the line type or command.
/// Data associated with the keyword; may be empty or contain parameters or raw text to interpret.
- protected abstract void ParseLine(string keyword, string data);
+ /// if the line was parsed successfully; otherwise, .
+ protected abstract bool ParseLine(string keyword, string data);
}
}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
index 9861031..b45b5a0 100644
--- a/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
+++ b/ObjLoader/Loaders/MaterialLoader/MaterialLibraryLoader.cs
@@ -74,17 +74,18 @@ private void AddParseAction(string key, Action action)
=> _parseActionDictionary.Add(key.ToLowerInvariant(), action);
///
- protected override void ParseLine(string keyword, string data)
+ protected override bool ParseLine(string keyword, string data)
{
var parseAction = GetKeywordAction(keyword, out bool found);
if (!found)
{
_unrecognizedLines.Add(keyword + " " + data);
- return;
+ return false;
}
parseAction!(data);
+ return true;
}
private Action? GetKeywordAction(string keyword, out bool found)
diff --git a/ObjLoader/Loaders/ObjLoader/FileManager.cs b/ObjLoader/Loaders/ObjLoader/FileManager.cs
new file mode 100644
index 0000000..0e44ce3
--- /dev/null
+++ b/ObjLoader/Loaders/ObjLoader/FileManager.cs
@@ -0,0 +1,15 @@
+using SharpEngine.Core.ObjLoader.Loader.Loaders;
+using System.IO;
+
+namespace SharpEngine.Core.ObjLoader.Loaders.ObjLoader
+{
+ ///
+ /// Represents a testable wrapper for creating stream file related objects.
+ ///
+ public class FileManager : IFileManager
+ {
+ ///
+ public StreamReader StreamReader(string path)
+ => new(path);
+ }
+}
\ No newline at end of file
diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
index a79ac5b..fbb9b0f 100644
--- a/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
+++ b/ObjLoader/Loaders/ObjLoader/ObjLoader.cs
@@ -1,11 +1,13 @@
-using SharpEngine.Core.Entities.Properties.Meshes;
+using Microsoft.Extensions.Logging;
+using SharpEngine.Core.Entities.Properties.Meshes;
using SharpEngine.Core.ObjLoader.Loader.Loaders;
using SharpEngine.Core.ObjLoader.TypeParsers;
-
+using SharpEngine.Telemetry;
using Silk.NET.OpenGL;
using System.Collections.Generic;
using System.IO.Abstractions;
+using System.Linq;
namespace SharpEngine.Core.ObjLoader.Loaders.ObjLoader
{
@@ -19,6 +21,8 @@ public class ObjLoader : LoaderBase
private readonly List _typeParsers = [];
private readonly List _unrecognizedLines = [];
+ private readonly ILogger _logger = LoggingExtensions.CreateLogger();
+
///
/// Initializes a new instance of with the specified file path and data store.
///
@@ -46,16 +50,25 @@ public ObjLoader SetupTypeParsers(params ITypeParser[] parsers)
}
///
- protected override void ParseLine(string keyword, string data)
+ protected override bool ParseLine(string keyword, string data)
{
foreach (var typeParser in _typeParsers)
+ {
if (typeParser.CanParse(keyword))
{
typeParser.Parse(data);
- return;
+ return true;
}
+ else
+ {
+ _logger.LogDebug("Type parser {Parser} cannot parse keyword: {Keyword}", typeParser.GetType().Name, keyword);
+ }
+ }
_unrecognizedLines.Add(keyword + " " + data);
+ _logger.LogError("Unrecognized line in OBJ file: {Line}", keyword + " " + data);
+
+ return false;
}
///
@@ -64,12 +77,18 @@ protected override void ParseLine(string keyword, string data)
/// The OpenGL context used to construct GPU resources.
public List Load(GL gl)
{
- ParseFile(_path);
+ if (!ParseFile(_path))
+ {
+ _logger.LogError("Failed to parse OBJ file: {Path}", _path);
+ return [];
+ }
+ // TODO: Handle multiple meshes and objects in the OBJ file. Currently, this implementation assumes a single mesh.
return
[
new(gl)
{
+ Name = _dataStore.ObjectName,
Vertices2 = _dataStore.Vertices,
TextureCoordinates2 = _dataStore.Textures,
Normals2 = _dataStore.Normals,
diff --git a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
index b99400c..20b7d20 100644
--- a/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
+++ b/ObjLoader/Loaders/ObjLoader/ObjLoaderFactory.cs
@@ -1,9 +1,10 @@
+using Microsoft.Extensions.Logging;
using SharpEngine.Core.Components.Properties.Meshes;
using SharpEngine.Core.Entities.Properties.Meshes;
-using SharpEngine.Core.ObjLoader.Loader.Loaders;
using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
using SharpEngine.Core.ObjLoader.Loaders.MaterialLoader;
-
+using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Telemetry;
using Silk.NET.OpenGL;
using System;
@@ -13,16 +14,6 @@
namespace SharpEngine.Core.ObjLoader.Loaders.ObjLoader
{
- ///
- /// Represents a testable wrapper for creating stream file related objects.
- ///
- public class FileManager : IFileManager
- {
- ///
- public StreamReader StreamReader(string path)
- => new(path);
- }
-
///
/// Handles loading 3D models.
///
@@ -31,6 +22,8 @@ public static class ObjLoaderFactory
private static readonly FileSystem _fileSystem;
private static readonly FileManager _fileManager;
+ private readonly static ILogger _logger = LoggingExtensions.CreateLogger(typeof(ObjLoaderFactory));
+
static ObjLoaderFactory()
{
_fileSystem = new FileSystem();
@@ -45,15 +38,33 @@ static ObjLoaderFactory()
///
/// The OpenGL context where the model should be bound.
/// Specifies the file path of the mesh to be loaded, which determines the loading method based on its extension.
+ /// The model loaded from the file.
/// The model loaded from the file.
/// Thrown when the file extension of the provided path is not recognized as a supported mesh format.
- public static Model Load(GL gl, string path)
- => Path.GetExtension(path) switch
+ /// Thrown when no meshes are loaded.
+ public static bool Load(GL gl, string path, out Model? model)
+ {
+ try
+ {
+ string fileExtension = Path.GetExtension(path);
+ model = fileExtension switch
+ {
+ FbxExtension => LoadFbx("", path),
+ ObjExtension => LoadObj(gl, path),
+ _ => throw new NotSupportedException($"The file extension {fileExtension} is not a supported mesh file.")
+ };
+
+ _logger.LogDebug("Successfully loaded model '{name}' from path: {path}.", model.Name, path);
+ return true;
+ }
+ catch (Exception ex)
{
- FbxExtension => LoadFbx("", path),
- ObjExtension => LoadObj(gl, path),
- _ => throw new NotSupportedException($"The file extension {Path.GetExtension(path)} is not a supported mesh file.")
- };
+ _logger.LogWarning(ex, "Failed to load model from path: {path}.", path);
+
+ model = null;
+ return false;
+ }
+ }
// TODO: #3 Load fbx mesh from file
private static Model LoadFbx(string identifier, string meshFilePath)
@@ -64,6 +75,10 @@ private static Model LoadFbx(string identifier, string meshFilePath)
private static Model LoadObj(GL gl, string path)
{
var meshes = LoadObjMeshes(gl, path);
+
+ if (meshes.Count == 0)
+ throw new InvalidOperationException("The .obj file contains no meshes.");
+
return new Model(gl, path, meshes);
}
@@ -76,6 +91,8 @@ private static List LoadObjMeshes(GL gl, string path)
var normalParser = new NormalParser(dataStore);
var textureParser = new TextureParser(dataStore);
var vertexParser = new VertexParser(dataStore);
+ var smoothingGroupParser = new SmoothingGroupParser(dataStore);
+ var objectNameParser = new ObjectNameParser(dataStore);
var materialLibraryLoader = new MaterialLibraryLoader(dataStore, _fileSystem.FileStream, _fileManager);
@@ -84,7 +101,7 @@ private static List LoadObjMeshes(GL gl, string path)
var useMaterialParser = new UseMaterialParser(dataStore);
var loader = new ObjLoader(path, dataStore, _fileSystem.FileStream, _fileManager)
- .SetupTypeParsers(faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser);
+ .SetupTypeParsers(faceParser, groupParser, normalParser, textureParser, vertexParser, materialLibraryParser, useMaterialParser, smoothingGroupParser, objectNameParser);
return loader.Load(gl);
}
diff --git a/ObjLoader/TypeParsers/FaceParser.cs b/ObjLoader/TypeParsers/FaceParser.cs
index 0df5e68..83581d5 100644
--- a/ObjLoader/TypeParsers/FaceParser.cs
+++ b/ObjLoader/TypeParsers/FaceParser.cs
@@ -27,7 +27,7 @@ public FaceParser(IFaceGroup faceGroup)
protected override string Keyword => "f";
///
- public override void Parse(string line)
+ public override bool Parse(string line)
{
string[] vertices = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
@@ -35,19 +35,22 @@ public override void Parse(string line)
foreach (string vertexString in vertices)
{
- var faceVertex = ParseFaceVertex(vertexString);
- face.AddVertex(faceVertex);
+ if (TryParseFaceVertex(vertexString, out FaceVertex faceVertex))
+ {
+ face.AddVertex(faceVertex);
+ }
}
_faceGroup.AddFace(face);
+ return true;
}
- private static FaceVertex ParseFaceVertex(string vertexString)
+ private static bool TryParseFaceVertex(string vertexString, out FaceVertex faceVertex)
{
string[] fields = vertexString.Split('/', StringSplitOptions.None);
int vertexIndex = fields[0].ParseInvariantInt();
- var faceVertex = new FaceVertex(vertexIndex, 0, 0);
+ faceVertex = new FaceVertex(vertexIndex, 0, 0);
if (fields.Length > 1)
{
@@ -61,7 +64,7 @@ private static FaceVertex ParseFaceVertex(string vertexString)
faceVertex.NormalIndex = normalIndex;
}
- return faceVertex;
+ return true;
}
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/GroupParser.cs b/ObjLoader/TypeParsers/GroupParser.cs
index e5dae69..0934906 100644
--- a/ObjLoader/TypeParsers/GroupParser.cs
+++ b/ObjLoader/TypeParsers/GroupParser.cs
@@ -23,7 +23,10 @@ public GroupParser(IGroupDataStore dataStore)
protected override string Keyword => "g";
///
- public override void Parse(string line)
- => _dataStore.PushGroup(line);
+ public override bool Parse(string line)
+ {
+ _dataStore.PushGroup(line);
+ return true;
+ }
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/ITypeParser.cs b/ObjLoader/TypeParsers/ITypeParser.cs
index 1b041ba..3fd685b 100644
--- a/ObjLoader/TypeParsers/ITypeParser.cs
+++ b/ObjLoader/TypeParsers/ITypeParser.cs
@@ -9,13 +9,14 @@ public interface ITypeParser
/// Determines whether the specified keyword can be parsed.
///
/// The keyword to check.
- /// True if the keyword can be parsed; otherwise, false.
+ /// if the keyword can be parsed; otherwise, .
bool CanParse(string keyword);
///
/// Parses a single input line and updates the object's state accordingly.
///
/// The input line to parse.
- void Parse(string line);
+ /// if the line was successfully parsed; otherwise, .
+ bool Parse(string line);
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/MaterialLibraryParser.cs b/ObjLoader/TypeParsers/MaterialLibraryParser.cs
index f622cc8..7be0889 100644
--- a/ObjLoader/TypeParsers/MaterialLibraryParser.cs
+++ b/ObjLoader/TypeParsers/MaterialLibraryParser.cs
@@ -23,6 +23,10 @@ public MaterialLibraryParser(IMaterialLibraryLoaderFacade facade)
protected override string Keyword => "mtllib";
///
- public override void Parse(string line) => _libraryLoaderFacade.Load(line);
+ public override bool Parse(string line)
+ {
+ _libraryLoaderFacade.Load(line);
+ return true;
+ }
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/NormalParser.cs b/ObjLoader/TypeParsers/NormalParser.cs
index af7974b..111800b 100644
--- a/ObjLoader/TypeParsers/NormalParser.cs
+++ b/ObjLoader/TypeParsers/NormalParser.cs
@@ -25,7 +25,7 @@ public NormalParser(INormalDataStore dataStore)
protected override string Keyword => "vn";
///
- public override void Parse(string line)
+ public override bool Parse(string line)
{
string[] parts = line.Split(' ');
@@ -35,6 +35,8 @@ public override void Parse(string line)
var normal = new Normal(x, y, z);
_dataStore.AddNormal(normal);
+
+ return true;
}
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/ObjectNameParser.cs b/ObjLoader/TypeParsers/ObjectNameParser.cs
new file mode 100644
index 0000000..13d0d9f
--- /dev/null
+++ b/ObjLoader/TypeParsers/ObjectNameParser.cs
@@ -0,0 +1,33 @@
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+using System;
+
+namespace SharpEngine.Core.ObjLoader.TypeParsers;
+
+///
+/// Parses object name lines `o object_name` and handles the object name accordingly.
+///
+public class ObjectNameParser : TypeParserBase, ITypeParser
+{
+ private IObjectNameDataStore _dataStore;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The data store to store the parsed object name.
+ public ObjectNameParser(IObjectNameDataStore dataStore)
+ {
+ _dataStore = dataStore;
+ }
+
+ ///
+ protected override string Keyword => "o";
+
+ ///
+ /// Thrown when the line format is invalid.
+ public override bool Parse(string data)
+ {
+ _dataStore.SetObjectName(data);
+
+ return true;
+ }
+}
diff --git a/ObjLoader/TypeParsers/SmoothingGroupParser.cs b/ObjLoader/TypeParsers/SmoothingGroupParser.cs
new file mode 100644
index 0000000..693bcea
--- /dev/null
+++ b/ObjLoader/TypeParsers/SmoothingGroupParser.cs
@@ -0,0 +1,45 @@
+using SharpEngine.Core.ObjLoader.Loader.TypeParsers;
+using System;
+
+namespace SharpEngine.Core.ObjLoader.TypeParsers;
+
+///
+/// Parses smoothing group definitions ("s") and populates the current group's smoothing group information.
+///
+public class SmoothingGroupParser : TypeParserBase, ITypeParser
+{
+ private ISmoothingGroupDataStore _dataStore;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The data store to store the parsed smoothing group information.
+ public SmoothingGroupParser(ISmoothingGroupDataStore dataStore)
+ {
+ _dataStore = dataStore;
+ }
+
+ ///
+ protected override string Keyword => "s";
+
+ ///
+ ///
+ /// The line is expected to be in the format "group_number" or "off" so the s at the beginning is not included in the data string passed to this method.
+ ///
+ /// Thrown when the line format is invalid or the smoothing group number is not a valid integer.
+ public override bool Parse(string data)
+ {
+ if (data.Equals("off", StringComparison.OrdinalIgnoreCase))
+ {
+ _dataStore.SetSmoothingGroupOff();
+ return true;
+ }
+
+ // Parse the smoothing group number
+ if (!int.TryParse(data, out int groupNumber))
+ throw new FormatException($"Invalid smoothing group identifier: {data}");
+
+ _dataStore.SetSmoothingGroup(groupNumber);
+ return true;
+ }
+}
diff --git a/ObjLoader/TypeParsers/TextureParser.cs b/ObjLoader/TypeParsers/TextureParser.cs
index 43a2e8e..df5a0e3 100644
--- a/ObjLoader/TypeParsers/TextureParser.cs
+++ b/ObjLoader/TypeParsers/TextureParser.cs
@@ -25,7 +25,7 @@ public TextureParser(ITextureDataStore dataStore)
protected override string Keyword => "vt";
///
- public override void Parse(string line)
+ public override bool Parse(string line)
{
string[] parts = line.Split(' ');
@@ -34,6 +34,8 @@ public override void Parse(string line)
var texture = new TextureCoordinate(x, y);
_dataStore.AddTexture(texture);
+
+ return true;
}
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/TypeParserBase.cs b/ObjLoader/TypeParsers/TypeParserBase.cs
index 7410790..30ac334 100644
--- a/ObjLoader/TypeParsers/TypeParserBase.cs
+++ b/ObjLoader/TypeParsers/TypeParserBase.cs
@@ -17,6 +17,6 @@ public abstract class TypeParserBase : ITypeParser
public bool CanParse(string keyword) => keyword.EqualsOrdinalIgnoreCase(Keyword);
///
- public abstract void Parse(string line);
+ public abstract bool Parse(string line);
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/UseMaterialParser.cs b/ObjLoader/TypeParsers/UseMaterialParser.cs
index aa4d6eb..76d6f5d 100644
--- a/ObjLoader/TypeParsers/UseMaterialParser.cs
+++ b/ObjLoader/TypeParsers/UseMaterialParser.cs
@@ -1,5 +1,4 @@
-using SharpEngine.Core.Components.ObjLoader.DataStore;
-using SharpEngine.Core.ObjLoader.TypeParsers;
+using SharpEngine.Core.ObjLoader.TypeParsers;
namespace SharpEngine.Core.ObjLoader.Loader.TypeParsers
{
@@ -23,6 +22,10 @@ public UseMaterialParser(IMaterialDataStore dataStore)
protected override string Keyword => "usemtl";
///
- public override void Parse(string line) => _dataStore.SetMaterial(line);
+ public override bool Parse(string line)
+ {
+ _dataStore.SetMaterial(line);
+ return true;
+ }
}
}
\ No newline at end of file
diff --git a/ObjLoader/TypeParsers/VertexParser.cs b/ObjLoader/TypeParsers/VertexParser.cs
index 94159b3..fadb733 100644
--- a/ObjLoader/TypeParsers/VertexParser.cs
+++ b/ObjLoader/TypeParsers/VertexParser.cs
@@ -27,7 +27,7 @@ public VertexParser(IVertexDataStore dataStore)
protected override string Keyword => "v";
///
- public override void Parse(string line)
+ public override bool Parse(string line)
{
string[] parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
@@ -41,6 +41,8 @@ public override void Parse(string line)
};
_dataStore.AddVertex(vertex);
+
+ return true;
}
}
}
\ No newline at end of file
diff --git a/SharpEngine.Core.Components/Properties/Meshes/Model.cs b/SharpEngine.Core.Components/Properties/Meshes/Model.cs
index 360b321..2947ec0 100644
--- a/SharpEngine.Core.Components/Properties/Meshes/Model.cs
+++ b/SharpEngine.Core.Components/Properties/Meshes/Model.cs
@@ -23,12 +23,14 @@ public class Model : IDisposable
/// Gets the list of meshes contained within the model.
public List Meshes { get; set; } = [];
+ public string Name { get; }
+
///
/// Initializes a new instance of the Model class with the specified OpenGL context and model file path.
///
/// The GL context used for rendering and resource management.
/// The file path of the model asset.
- public Model(GL gl, string path)
+ public Model(GL gl, string path) : this(gl, path, Enumerable.Empty())
{
_gl = gl;
Path = path;
@@ -47,7 +49,11 @@ public Model(GL gl, string path, IEnumerable meshes)
{
_gl = gl;
Path = path;
- Meshes = [.. meshes.Select(ProcessMesh)];
+
+ if (meshes.Any())
+ Meshes = meshes.Select(ProcessMesh).ToList();
+
+ Name = meshes.FirstOrDefault()?.Name ?? System.IO.Path.GetFileNameWithoutExtension(path) ?? "UnnamedModel";
}
///
diff --git a/SharpEngine.Core/Abstractions/ISettings.cs b/SharpEngine.Core/Abstractions/ISettings.cs
index 6800463..d0984b2 100644
--- a/SharpEngine.Core/Abstractions/ISettings.cs
+++ b/SharpEngine.Core/Abstractions/ISettings.cs
@@ -1,4 +1,5 @@
-using SharpEngine.Core.Renderers;
+using Microsoft.Extensions.Logging;
+using SharpEngine.Core.Renderers;
using Silk.NET.Input;
namespace SharpEngine.Core.Interfaces;
@@ -26,6 +27,11 @@ public interface ISettings
/// Gets or sets the secondary mouse button.
public MouseButton SecondaryButton { get; set; }
+
+ ///
+ /// Gets or sets the log level for the game engine.
+ ///
+ public LogLevel LogLevel { get; set; }
}
///
@@ -45,4 +51,7 @@ public class DefaultSettings : ISettings
///
public MouseButton SecondaryButton { get; set; } = MouseButton.Right;
+
+ ///
+ public LogLevel LogLevel { get; set; } = LogLevel.Information;
}
diff --git a/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs b/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs
index 03d03f7..dbeef01 100644
--- a/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs
+++ b/SharpEngine.Core/Entities/Views/Settings/DefaultViewSettings.cs
@@ -1,4 +1,5 @@
-using SharpEngine.Core.Renderers;
+using Microsoft.Extensions.Logging;
+using SharpEngine.Core.Renderers;
using Silk.NET.Input;
using Silk.NET.Maths;
@@ -48,4 +49,7 @@ public DefaultViewSettings()
///
public MouseButton SecondaryButton { get; set; } = MouseButton.Right;
+
+ ///
+ public LogLevel LogLevel { get; set; } = LogLevel.Information;
}
diff --git a/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs b/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs
index 09c65cb..013f31b 100644
--- a/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs
+++ b/SharpEngine.Core/Entities/Views/Settings/ViewSettings.cs
@@ -1,4 +1,5 @@
-using SharpEngine.Core.Renderers;
+using Microsoft.Extensions.Logging;
+using SharpEngine.Core.Renderers;
using Silk.NET.Input;
using Silk.NET.Windowing;
@@ -52,4 +53,7 @@ public ViewSettings()
///
public MouseButton SecondaryButton { get; set; } = MouseButton.Right;
+
+ ///
+ public LogLevel LogLevel { get; set; } = LogLevel.Information;
}