mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Model and Material loading via content manager
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using GlitchyEngine.Core;
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.Content;
|
||||
|
||||
class Asset : RefCounter
|
||||
{
|
||||
private append String _identifier;
|
||||
|
||||
internal IContentManager _contentManager;
|
||||
|
||||
/// Gets the identifier of this asset.
|
||||
/// @remarks The identifier is the name with which the asset was registered in the content manager.
|
||||
/// This identifier can be used to request the Asset from the content manager.
|
||||
public StringView Identifier
|
||||
{
|
||||
get => _identifier;
|
||||
set
|
||||
{
|
||||
_contentManager?.UpdateAssetIdentifier(this, _identifier, value);
|
||||
|
||||
_identifier.Set(value);
|
||||
// TODO: do we need to tell the content manager, that the name changed?
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: do we need unmanaged assets? Probably not...
|
||||
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
|
||||
public IContentManager ContentManager => _contentManager;
|
||||
|
||||
protected ~this()
|
||||
{
|
||||
// TODO: crash when _contentManager is deleted first...
|
||||
// TODO: unregister from content manager
|
||||
_contentManager?.UnmanageAsset(this);
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,9 @@ namespace GlitchyEngine.Content
|
||||
/// Loads the asset from the given data stream with the specified config.
|
||||
/// @param file The stream containing the asset.
|
||||
/// @param config The configuration which specifies the settings used to load the asset.
|
||||
/// @param contentManager The content manager used to load the asset.
|
||||
/// @returns The loaded asset.
|
||||
IRefCounted LoadAsset(Stream file, AssetLoaderConfig config);
|
||||
Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView? subAsset, IContentManager contentManager);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -79,7 +80,17 @@ namespace GlitchyEngine.Content
|
||||
interface IContentManager
|
||||
{
|
||||
/// Loads the given asset.
|
||||
IRefCounted LoadAsset(StringView assetIdentifier);
|
||||
Asset LoadAsset(StringView assetIdentifier);
|
||||
|
||||
/// The content manager will manage the asset (e.g. provide it when LoadAsset is called with the assets identifier)
|
||||
void ManageAsset(Asset asset);
|
||||
|
||||
/// The content manager will no longer manage the asset.
|
||||
void UnmanageAsset(Asset asset);
|
||||
|
||||
// TODO: Maybe calling UnmanageAsset -> ManageAsset is enough....
|
||||
/// Provides a method for the asset to tell its content manager that the identifer changed.
|
||||
void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier);
|
||||
|
||||
/// Returns a data stream for the given asset.
|
||||
Stream GetStream(StringView assetIdentifier);
|
||||
@@ -93,7 +104,22 @@ namespace GlitchyEngine.Content
|
||||
|
||||
class RuntimeContentManager : IContentManager
|
||||
{
|
||||
public IRefCounted LoadAsset(StringView identifier)
|
||||
public Asset LoadAsset(StringView assetIdentifier)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public void ManageAsset(Asset asset)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public void UnmanageAsset(Asset asset)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using GlitchyEngine.Math;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Renderer.Animation;
|
||||
using GlitchyEngine.World;
|
||||
using System.IO;
|
||||
|
||||
namespace GlitchyEngine.Content
|
||||
{
|
||||
@@ -66,6 +67,168 @@ namespace GlitchyEngine.Content
|
||||
return geoBinding;
|
||||
}
|
||||
|
||||
public static GeometryBinding LoadMesh(Stream data, StringView meshName, int primitiveIndex)
|
||||
{
|
||||
// TODO: add a context to remember which buffers were loaded before so that we don't load the same data multiple times.
|
||||
|
||||
uint8[] rawData = new:ScopedAlloc! uint8[data.Length];
|
||||
|
||||
var dataReadResult = data.TryRead(rawData);
|
||||
|
||||
if (dataReadResult case .Err(let err))
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to read data from stream. Error: {err}");
|
||||
}
|
||||
|
||||
CGLTF.Options options = .();
|
||||
CGLTF.Data* modelData;
|
||||
CGLTF.Result result = CGLTF.Parse(options, (Span<uint8>)rawData, out modelData);
|
||||
|
||||
if (!(result case .Success))
|
||||
return null;
|
||||
|
||||
// TODO: one buffer can be used by multiple primitives, the content manager could manage the buffers
|
||||
|
||||
// TODO: load with content manager
|
||||
|
||||
result = CGLTF.LoadBuffers(options, modelData, (char8*)null);
|
||||
//result = LoadBuffersWithContentManager(options, modelData, meshName, Application.Get().ContentManager);
|
||||
|
||||
GeometryBinding geoBinding = null;
|
||||
|
||||
for (var mesh in modelData.Meshes)
|
||||
{
|
||||
var name = StringView(mesh.Name);
|
||||
|
||||
//if (name == meshName)
|
||||
{
|
||||
Log.EngineLogger.AssertDebug(primitiveIndex >= 0 && primitiveIndex < mesh.Primitives.Length);
|
||||
|
||||
geoBinding = PrimitiveToGeoBinding(mesh.Primitives[primitiveIndex]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CGLTF.Free(modelData);
|
||||
|
||||
return geoBinding;
|
||||
}
|
||||
|
||||
private static CGLTF.Result LoadBuffersWithContentManager(CGLTF.Options options, CGLTF.Data* data, StringView fileName, IContentManager contentManager)
|
||||
{
|
||||
if (data.Buffers.Length > 0 && data.Buffers[0].Data == null && data.Buffers[0].Uri == null && !data.Bin.IsEmpty)
|
||||
{
|
||||
if ((uint)data.Bin.Length < data.Buffers[0].Size)
|
||||
return .DataTooShort;
|
||||
|
||||
data.Buffers[0].Data = data.Bin.Ptr;
|
||||
data.Buffers[0].DataFreeMethod = .None;
|
||||
}
|
||||
|
||||
for (ref CGLTF.Buffer buffer in ref data.Buffers)
|
||||
{
|
||||
if (buffer.Data != null)
|
||||
continue;
|
||||
|
||||
if (buffer.Uri == null)
|
||||
continue;
|
||||
|
||||
StringView uri = StringView(buffer.Uri);
|
||||
|
||||
if (uri.StartsWith("data:"))
|
||||
{
|
||||
int commaIndex = uri.IndexOf(',');
|
||||
|
||||
//char* comma = strchr(uri, ',');
|
||||
|
||||
if (commaIndex == -1 || commaIndex >= 7 || uri.StartsWith(";base64"))
|
||||
return .UnknownFormat;
|
||||
|
||||
StringView dataView = uri.Substring(commaIndex + 1);
|
||||
|
||||
#unwarn
|
||||
CGLTF.Result loadBufferResult = CGLTF.LoadBuffersBase64(&options, buffer.Size, dataView.Ptr, &buffer.Data);
|
||||
buffer.DataFreeMethod = .MemoryFree;
|
||||
|
||||
return loadBufferResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
Runtime.NotImplemented();
|
||||
|
||||
// TODO: Request Buffer from Content Manager
|
||||
|
||||
//int index = uri.IndexOf("://");
|
||||
|
||||
//if (index == -1)
|
||||
// return .UnknownFormat;
|
||||
|
||||
// TODO: load buffer file...
|
||||
//CGLTF.Result res = //cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
|
||||
//buffer.DataFreeMethod = cgltf_data_free_method_file_release;
|
||||
|
||||
/*if (res != cgltf_result_success)
|
||||
{
|
||||
return res;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
for (cgltf_size i = 0; i < data->buffers_count; ++i)
|
||||
{
|
||||
if (data->buffers[i].data)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* uri = data->buffers[i].uri;
|
||||
|
||||
if (uri == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(uri, "data:", 5) == 0)
|
||||
{
|
||||
const char* comma = strchr(uri, ',');
|
||||
|
||||
if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0)
|
||||
{
|
||||
cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data);
|
||||
data->buffers[i].data_free_method = cgltf_data_free_method_memory_free;
|
||||
|
||||
if (res != cgltf_result_success)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return cgltf_result_unknown_format;
|
||||
}
|
||||
}
|
||||
else if (strstr(uri, "://") == NULL && gltf_path)
|
||||
{
|
||||
cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
|
||||
data->buffers[i].data_free_method = cgltf_data_free_method_file_release;
|
||||
|
||||
if (res != cgltf_result_success)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return cgltf_result_unknown_format;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return .Success;
|
||||
}
|
||||
|
||||
public static EcsEntity LoadModel(String filename, Material material, EcsWorld world,
|
||||
List<AnimationClip> outClips, StringView entityName = StringView())
|
||||
{
|
||||
|
||||
@@ -7,11 +7,10 @@ namespace GlitchyEngine.Core
|
||||
* Implements the IDisposable interface so that it can be used with a using-Block so that the counter
|
||||
* will be decremented automatically after leaving the block.
|
||||
*/
|
||||
public class RefCounter : System.RefCounted, IDisposable
|
||||
public class RefCounter : RefCounted, IDisposable
|
||||
{
|
||||
protected ~this()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -1,41 +1,28 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.IO;
|
||||
|
||||
extension Path
|
||||
{
|
||||
/// Opens the file browser and selects the specified file.
|
||||
/// @param path The path of the file to select.
|
||||
public static void OpenFolderAndSelectItem(String path)
|
||||
public static mixin GetScopedFullPath(String path)
|
||||
{
|
||||
String fullPath = scope String(256);
|
||||
String fullPath = scope String(Path.MaxPath);
|
||||
Path.GetFullPath(path, fullPath);
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
ProcessStartInfo processInfo = scope .();
|
||||
processInfo.SetFileNameAndArguments(scope $"explorer /select,\"{fullPath}\"");
|
||||
|
||||
scope SpawnedProcess().Start(processInfo);
|
||||
#else
|
||||
Runtime.NotImplemented();
|
||||
#endif
|
||||
fullPath
|
||||
}
|
||||
|
||||
/// Opens the file browser and selects the specified file.
|
||||
/// @param path The path of the file to select.
|
||||
public static extern Result<void> OpenFolderAndSelectItem(String path);
|
||||
|
||||
/// Opens the file browser in the given directory.
|
||||
/// @param directory The directory to show in the file browser.
|
||||
public static void OpenFolder(String directory)
|
||||
{
|
||||
String fullPath = scope String(256);
|
||||
Path.GetFullPath(directory, fullPath);
|
||||
public static extern Result<void> OpenFolder(String directory);
|
||||
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
ProcessStartInfo processInfo = scope .();
|
||||
processInfo.SetFileNameAndArguments(scope $"explorer \"{fullPath}\"");
|
||||
|
||||
scope SpawnedProcess().Start(processInfo);
|
||||
#else
|
||||
Runtime.NotImplemented();
|
||||
#endif
|
||||
}
|
||||
/// Shows a dialog in which the user can select which program to open the given file with.
|
||||
/// @param The Path of the file to open.
|
||||
public static extern Result<void> OpenWithDialog(String filePath);
|
||||
|
||||
public static void Fixup(String path)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
|
||||
using DirectX.Common;
|
||||
using DirectX.Windows;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using DirectX.Windows.Winuser;
|
||||
|
||||
namespace DirectX.Windows.Winuser
|
||||
{
|
||||
enum OpenAsInfoFlags : uint32
|
||||
{
|
||||
/// Enable the "always use this program" checkbox. If not passed, it will be disabled.
|
||||
AllowRegistration = 0x1,
|
||||
/// Do the registration after the user hits the OK button.
|
||||
RegisterExtension = 0x2,
|
||||
/// Execute file after registering.
|
||||
Exec = 0x4,
|
||||
///Force the Always use this program checkbox to be checked.
|
||||
/// Typically, you won't use the OAIF_ALLOW_REGISTRATION flag when you pass this value.
|
||||
ForceRegistration = 0x8,
|
||||
/// Introduced in Windows Vista. Hide the Always use this program checkbox. If this flag is specified, the OAIF_ALLOW_REGISTRATION and OAIF_FORCE_REGISTRATION flags will be ignored.
|
||||
HideRegistration = 0x20,
|
||||
/// Introduced in Windows Vista. The value for the extension that is passed is actually a protocol, so the Open With dialog box should show applications that are registered as capable of handling that protocol.
|
||||
UrlProtocol = 0x40,
|
||||
/// Introduced in Windows 8. The location pointed to by the pcszFile parameter is given as a URI.
|
||||
FileIsUri = 0x80
|
||||
}
|
||||
|
||||
struct OpenAsInfo
|
||||
{
|
||||
public LPCWSTR File;
|
||||
public LPCWSTR Class;
|
||||
public OpenAsInfoFlags Flags;
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
[Import("user32.lib"), CallingConvention(.Stdcall), CLink]
|
||||
public extern static HResult SHOpenWithDialog(HWND hwndParent, OpenAsInfo* poainfo);
|
||||
}
|
||||
}
|
||||
|
||||
namespace System.IO;
|
||||
|
||||
extension Path
|
||||
{
|
||||
/// Opens the file browser and selects the specified file.
|
||||
/// @param path The path of the file to select.
|
||||
public static override Result<void> OpenFolderAndSelectItem(String path)
|
||||
{
|
||||
String fullPath = GetScopedFullPath!(path);
|
||||
|
||||
ProcessStartInfo processInfo = scope .();
|
||||
processInfo.SetFileNameAndArguments(scope $"explorer /select,\"{fullPath}\"");
|
||||
|
||||
return scope SpawnedProcess().Start(processInfo);
|
||||
}
|
||||
|
||||
/// Opens the file browser in the given directory.
|
||||
/// @param directory The directory to show in the file browser.
|
||||
public static override Result<void> OpenFolder(String directory)
|
||||
{
|
||||
String fullPath = GetScopedFullPath!(directory);
|
||||
|
||||
ProcessStartInfo processInfo = scope .();
|
||||
processInfo.SetFileNameAndArguments(scope $"explorer \"{fullPath}\"");
|
||||
|
||||
return scope SpawnedProcess().Start(processInfo);
|
||||
}
|
||||
|
||||
public static override Result<void> OpenWithDialog(String filePath)
|
||||
{
|
||||
String fullPath = GetScopedFullPath!(filePath);
|
||||
|
||||
OpenAsInfo info = .();
|
||||
info.File = fullPath.ToScopedNativeWChar!();
|
||||
info.Class = null;
|
||||
info.Flags = .Exec;
|
||||
|
||||
HResult result = SHOpenWithDialog(0, &info);
|
||||
|
||||
if (result.Succeeded)
|
||||
return .Ok;
|
||||
else
|
||||
return .Err;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using GlitchyEngine.Content;
|
||||
using GlitchyEngine.Core;
|
||||
|
||||
namespace GlitchyEngine.Renderer
|
||||
{
|
||||
public class GeometryBinding : RefCounter
|
||||
// Todo: Rename to Mesh?
|
||||
public class GeometryBinding : Asset
|
||||
{
|
||||
internal List<VertexBufferBinding> _vertexBuffers = new .() ~ delete _;
|
||||
internal IndexBuffer _indexBuffer ~ _?.ReleaseRef();
|
||||
|
||||
@@ -1,237 +1,239 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using GlitchyEngine.Content;
|
||||
using GlitchyEngine.Core;
|
||||
using GlitchyEngine.Math;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using internal GlitchyEngine.Renderer;
|
||||
|
||||
namespace GlitchyEngine.Renderer
|
||||
namespace GlitchyEngine.Renderer;
|
||||
|
||||
public class Material : Asset
|
||||
{
|
||||
public class Material : RefCounter
|
||||
private Effect _effect ~ _?.ReleaseRef();
|
||||
|
||||
private uint8[] _rawVariables ~ delete _;
|
||||
|
||||
private Dictionary<String, TextureViewBinding> _textures = new .();
|
||||
|
||||
private Dictionary<String, (uint32 Offset, BufferVariable Variable)> _variables = new .() ~ delete _;
|
||||
|
||||
public Effect Effect => _effect;
|
||||
|
||||
public this(Effect effect)
|
||||
{
|
||||
private Effect _effect ~ _?.ReleaseRef();
|
||||
_effect = effect..AddRef();
|
||||
|
||||
private uint8[] _rawVariables ~ delete _;
|
||||
// TODO: get variables from effect
|
||||
|
||||
private Dictionary<String, TextureViewBinding> _textures = new .();
|
||||
|
||||
private Dictionary<String, (uint32 Offset, BufferVariable Variable)> _variables = new .() ~ delete _;
|
||||
|
||||
public Effect Effect => _effect;
|
||||
|
||||
public this(Effect effect)
|
||||
for(let (name, entry) in _effect.Textures)
|
||||
{
|
||||
_effect = effect..AddRef();
|
||||
var texture = entry.BoundTexture;
|
||||
texture.AddRef();
|
||||
|
||||
// TODO: get variables from effect
|
||||
|
||||
for(let (name, entry) in _effect.Textures)
|
||||
{
|
||||
var texture = entry.BoundTexture;
|
||||
texture.AddRef();
|
||||
|
||||
_textures.Add(name, texture);
|
||||
}
|
||||
|
||||
InitRawData();
|
||||
_textures.Add(name, texture);
|
||||
}
|
||||
|
||||
public ~this()
|
||||
{
|
||||
for(let (name, texture) in _textures)
|
||||
{
|
||||
texture.Release();
|
||||
}
|
||||
InitRawData();
|
||||
}
|
||||
|
||||
delete _textures;
|
||||
public ~this()
|
||||
{
|
||||
for(let (name, texture) in _textures)
|
||||
{
|
||||
texture.Release();
|
||||
}
|
||||
|
||||
/** @brief Initializes the raw data array for the variables.
|
||||
*/
|
||||
private void InitRawData()
|
||||
delete _textures;
|
||||
}
|
||||
|
||||
/** @brief Initializes the raw data array for the variables.
|
||||
*/
|
||||
private void InitRawData()
|
||||
{
|
||||
uint32 bufferSize = 0;
|
||||
|
||||
for(let variable in _effect.Variables)
|
||||
{
|
||||
uint32 bufferSize = 0;
|
||||
_variables.Add(variable.Name, (bufferSize, variable));
|
||||
|
||||
for(let variable in _effect.Variables)
|
||||
{
|
||||
_variables.Add(variable.Name, (bufferSize, variable));
|
||||
|
||||
bufferSize += variable._sizeInBytes;
|
||||
}
|
||||
|
||||
_rawVariables = new uint8[bufferSize];
|
||||
bufferSize += variable._sizeInBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the materials Shaders and Parameters to the given context.
|
||||
*/
|
||||
public void Bind()
|
||||
_rawVariables = new uint8[bufferSize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the materials Shaders and Parameters to the given context.
|
||||
*/
|
||||
public void Bind()
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
for(let (name, texture) in _textures)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
for(let (name, texture) in _textures)
|
||||
{
|
||||
_effect.SetTexture(name, texture);
|
||||
}
|
||||
|
||||
for(let (name, variable) in _variables)
|
||||
{
|
||||
variable.Variable.SetRawData(RawPointer!<uint8>(variable.Offset));
|
||||
}
|
||||
|
||||
_effect.ApplyChanges();
|
||||
_effect.Bind();
|
||||
_effect.SetTexture(name, texture);
|
||||
}
|
||||
|
||||
/** @brief Sets a texture of the material.
|
||||
* @param name The name of the texture to set.
|
||||
* @param texture The texture to bind to the effect.
|
||||
*/
|
||||
public void SetTexture(String name, Texture texture)
|
||||
for(let (name, variable) in _variables)
|
||||
{
|
||||
if(_textures.TryGetValue(name, var entry))
|
||||
{
|
||||
entry.Release();
|
||||
_textures[name] = texture.GetViewBinding();
|
||||
//texture?.AddRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false);
|
||||
}
|
||||
variable.Variable.SetRawData(RawPointer!<uint8>(variable.Offset));
|
||||
}
|
||||
|
||||
private mixin RawPointer<T>(uint32 offset)
|
||||
_effect.ApplyChanges();
|
||||
_effect.Bind();
|
||||
}
|
||||
|
||||
/** @brief Sets a texture of the material.
|
||||
* @param name The name of the texture to set.
|
||||
* @param texture The texture to bind to the effect.
|
||||
*/
|
||||
public void SetTexture(String name, Texture texture)
|
||||
{
|
||||
if(_textures.TryGetValue(name, var entry))
|
||||
{
|
||||
(T*)(&_rawVariables[offset])
|
||||
entry.Release();
|
||||
_textures[name] = texture.GetViewBinding();
|
||||
//texture?.AddRef();
|
||||
}
|
||||
|
||||
[Inline]
|
||||
private void SetVariable<T>(String name, T value) where T : struct
|
||||
else
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<T>();
|
||||
|
||||
*RawPointer!<T>(entry.Offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
Log.EngineLogger.Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(String name, float value) => SetVariable<float>(name, value);
|
||||
public void SetVariable(String name, Vector2 value) => SetVariable<Vector2>(name, value);
|
||||
public void SetVariable(String name, Vector3 value) => SetVariable<Vector3>(name, value);
|
||||
public void SetVariable(String name, Vector4 value) => SetVariable<Vector4>(name, value);
|
||||
|
||||
public void SetVariable(String name, int32 value) => SetVariable<int32>(name, value);
|
||||
public void SetVariable(String name, Int2 value) => SetVariable<Int2>(name, value);
|
||||
public void SetVariable(String name, Int3 value) => SetVariable<Int3>(name, value);
|
||||
public void SetVariable(String name, Int4 value) => SetVariable<Int4>(name, value);
|
||||
private mixin RawPointer<T>(uint32 offset)
|
||||
{
|
||||
(T*)(&_rawVariables[offset])
|
||||
}
|
||||
|
||||
public void SetVariable(String name, uint32 value) => SetVariable<uint32>(name, value);
|
||||
[Inline]
|
||||
private void SetVariable<T>(String name, T value) where T : struct
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
public void SetVariable(String name, Color value) => SetVariable<ColorRGBA>(name, (ColorRGBA)value);
|
||||
public void SetVariable(String name, ColorRGB value) => SetVariable<ColorRGB>(name, value);
|
||||
public void SetVariable(String name, ColorRGBA value) => SetVariable<ColorRGBA>(name, value);
|
||||
|
||||
public void SetVariable(String name, Matrix3x3 value)
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
// TODO: I'm not sure how to handle Matrix3x3
|
||||
// It seems to be 44 Bytes (11 Floats) large.
|
||||
Log.EngineLogger.AssertDebug(entry.Variable._sizeInBytes == 44, "Made wrong assumption about the size of float3x3 in a hlsl constant-buffer.");
|
||||
entry.Variable.EnsureTypeMatch<T>();
|
||||
|
||||
*RawPointer!<T>(entry.Offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(String name, float value) => SetVariable<float>(name, value);
|
||||
public void SetVariable(String name, Vector2 value) => SetVariable<Vector2>(name, value);
|
||||
public void SetVariable(String name, Vector3 value) => SetVariable<Vector3>(name, value);
|
||||
public void SetVariable(String name, Vector4 value) => SetVariable<Vector4>(name, value);
|
||||
|
||||
public void SetVariable(String name, int32 value) => SetVariable<int32>(name, value);
|
||||
public void SetVariable(String name, Int2 value) => SetVariable<Int2>(name, value);
|
||||
public void SetVariable(String name, Int3 value) => SetVariable<Int3>(name, value);
|
||||
public void SetVariable(String name, Int4 value) => SetVariable<Int4>(name, value);
|
||||
|
||||
public void SetVariable(String name, uint32 value) => SetVariable<uint32>(name, value);
|
||||
|
||||
public void SetVariable(String name, Color value) => SetVariable<ColorRGBA>(name, (ColorRGBA)value);
|
||||
public void SetVariable(String name, ColorRGB value) => SetVariable<ColorRGB>(name, value);
|
||||
public void SetVariable(String name, ColorRGBA value) => SetVariable<ColorRGBA>(name, value);
|
||||
|
||||
public void SetVariable(String name, Matrix3x3 value)
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
// TODO: I'm not sure how to handle Matrix3x3
|
||||
// It seems to be 44 Bytes (11 Floats) large.
|
||||
Log.EngineLogger.AssertDebug(entry.Variable._sizeInBytes == 44, "Made wrong assumption about the size of float3x3 in a hlsl constant-buffer.");
|
||||
|
||||
#unwarn
|
||||
*RawPointer!<float[11]>(entry.Offset) = *(float[11]*)&Matrix4x3(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
*RawPointer!<float[11]>(entry.Offset) = *(float[11]*)&Matrix4x3(value);
|
||||
}
|
||||
|
||||
public void SetVariable(String name, Matrix3x3[] values)
|
||||
else
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
int count = Math.Min(values.Count, entry.Variable._elements);
|
||||
|
||||
for(int i < count)
|
||||
{
|
||||
(RawPointer!<Matrix4x3>(entry.Offset))[i] = Matrix4x3(values[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
|
||||
public void SetVariable(String name, Matrix4x3 value) => SetVariable<Matrix4x3>(name, value);
|
||||
public void SetVariable(String name, Matrix value) => SetVariable<Matrix>(name, value);
|
||||
|
||||
public void SetVariable(String name, Matrix[] values)
|
||||
}
|
||||
|
||||
public void SetVariable(String name, Matrix3x3[] values)
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix>();
|
||||
entry.Variable.EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
Internal.MemCpy(RawPointer!<Matrix>(entry.Offset), values.Ptr, sizeof(Matrix) * Math.Min(values.Count, entry.Variable._elements));
|
||||
}
|
||||
else
|
||||
int count = Math.Min(values.Count, entry.Variable._elements);
|
||||
|
||||
for(int i < count)
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
(RawPointer!<Matrix4x3>(entry.Offset))[i] = Matrix4x3(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the raw data of the variable.
|
||||
* @param rawData The pointer to the raw data. If rawData is null the raw data will be set to zero.
|
||||
*/
|
||||
internal void SetRawData(uint32 offset, void* rawData, uint32 byteCount)
|
||||
else
|
||||
{
|
||||
if(rawData != null)
|
||||
Internal.MemCpy(&_rawVariables + offset, rawData, byteCount);
|
||||
else
|
||||
Internal.MemSet(&_rawVariables + offset, 0, byteCount);
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
// public void Set(String name, VALUE)...
|
||||
|
||||
public void GetVariable<T>(String name, out T value) where T : struct
|
||||
public void SetVariable(String name, Matrix4x3 value) => SetVariable<Matrix4x3>(name, value);
|
||||
public void SetVariable(String name, Matrix value) => SetVariable<Matrix>(name, value);
|
||||
|
||||
public void SetVariable(String name, Matrix[] values)
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
entry.Variable.EnsureTypeMatch<Matrix>();
|
||||
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<T>();
|
||||
|
||||
value = *RawPointer!<T>(entry.Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ?;
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
Internal.MemCpy(RawPointer!<Matrix>(entry.Offset), values.Ptr, sizeof(Matrix) * Math.Min(values.Count, entry.Variable._elements));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
// Float, Float2, Float3, Float4
|
||||
// Color, ColorRGB, ColorRGBA
|
||||
// Matrix3x3, Matrix4x3, Matrix
|
||||
// Int, Int2, Int3, Int4
|
||||
// UInt, UInt2, UInt3, UInt4
|
||||
// Bool, Bool2, Bool3, Bool4
|
||||
// Half, Half2, Half3, Half4
|
||||
// Byte, Byte2, Byte3, Byte4
|
||||
// Supporeted types
|
||||
// Float, Float2, Float3, Float4
|
||||
// Color, ColorRGB, ColorRGBA
|
||||
// Int, Int2, Int3, Int4
|
||||
// UInt
|
||||
// Matrix3x3, Matrix4x3, Matrix
|
||||
|
||||
// TODO: Add missing variable types
|
||||
// UInt2, UInt3, UInt4
|
||||
// Bool, Bool2, Bool3, Bool4
|
||||
// Half, Half2, Half3, Half4
|
||||
// Byte, Byte2, Byte3, Byte4
|
||||
|
||||
/**
|
||||
* Sets the raw data of the variable.
|
||||
* @param rawData The pointer to the raw data. If rawData is null the raw data will be set to zero.
|
||||
*/
|
||||
internal void SetRawData(uint32 offset, void* rawData, uint32 byteCount)
|
||||
{
|
||||
if(rawData != null)
|
||||
Internal.MemCpy(&_rawVariables + offset, rawData, byteCount);
|
||||
else
|
||||
Internal.MemSet(&_rawVariables + offset, 0, byteCount);
|
||||
}
|
||||
|
||||
public void GetVariable<T>(String name, out T value) where T : struct
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<T>();
|
||||
|
||||
value = *RawPointer!<T>(entry.Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ?;
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using GlitchyEngine.Content;
|
||||
using GlitchyEngine.Core;
|
||||
using GlitchyEngine.Math;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace GlitchyEngine.Renderer
|
||||
{
|
||||
public abstract class Texture : RefCounter
|
||||
public abstract class Texture : Asset
|
||||
{
|
||||
protected SamplerState _samplerState ~ _?.ReleaseRef();
|
||||
|
||||
|
||||
@@ -442,6 +442,9 @@ namespace GlitchyEngine.World
|
||||
|
||||
for (var (entity, transform, mesh, meshRenderer) in _ecsWorld.Enumerate<TransformComponent, MeshComponent, MeshRendererComponent>())
|
||||
{
|
||||
if (mesh.Mesh == null || meshRenderer.Material == null)
|
||||
continue;
|
||||
|
||||
Renderer.Submit(mesh.Mesh, meshRenderer.Material, entity, transform.WorldTransform);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user