Fixed various memory leaks + ModelLoader cleanup

This commit is contained in:
Simon Lübeß
2021-10-14 20:47:25 +02:00
parent cd82a99450
commit 84df8c111b
5 changed files with 57 additions and 229 deletions
+15 -166
View File
@@ -13,11 +13,8 @@ namespace GlitchyEngine.Content
static readonly Matrix RightToLeftHand = .Scaling(1, 1, -1);
public static void LoadModel(String filename, Effect validationEffect, Material material, EcsWorld world,
List<(Matrix Transform, GeometryBinding Model)> output, out Skeleton skeleton, out List<AnimationClip> clips)
List<AnimationClip> outClips)
{
skeleton = null;
removeMe___Clips = null;
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, filename, out data);
@@ -30,44 +27,13 @@ namespace GlitchyEngine.Content
for(var node in data.Scenes[0].Nodes)
{
NodesToEntities(data, node, null, world, validationEffect, material);
NodesToEntities(data, node, null, world, validationEffect, material, outClips);
}
clips = removeMe___Clips;
for(var node in data.Nodes)
{
if(node.Mesh != null)
{
Matrix transform = ?;
CGLTF.NodeTransformLocal(&node, (float*)&transform);
transform = RightToLeftHand * transform;
for(var primitive in node.Mesh.Primitives)
{
GeometryBinding binding = ModelLoader.PrimitiveToGeoBinding(primitive, validationEffect);
output.Add((transform, binding));
}
}
if(node.Skin != null)
{
AnimationClip clip;
(skeleton, clip) = ExtractBonestuff(node.Skin, data);
clips.Add(clip);
}
}
CGLTF.Free(data);
}
static List<AnimationClip> removeMe___Clips;
private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, Entity? parentEntity, EcsWorld world, Effect validationEffect, Material material)
private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, Entity? parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips)
{
Entity entity = world.NewEntity();
@@ -116,8 +82,7 @@ namespace GlitchyEngine.Content
{
skeleton = ExtractSkeleton(node.Skin);
removeMe___Clips = new List<AnimationClip>();
LoadAnimationClips(data, node.Skin, skeleton, removeMe___Clips);
LoadAnimationClips(data, node.Skin, skeleton, clips);
}
if(node.Mesh != null)
@@ -126,7 +91,11 @@ namespace GlitchyEngine.Content
if(node.Mesh.Primitives.Length == 1)
{
var mesh = world.AssignComponent<MeshComponent>(entity);
mesh.Mesh = ModelLoader.PrimitiveToGeoBinding(node.Mesh.Primitives[0], validationEffect);
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0], validationEffect))
{
mesh.Mesh = geo;
}
if(skeleton == null)
{
@@ -168,9 +137,11 @@ namespace GlitchyEngine.Content
}
}
skeleton?.ReleaseRef();
for(var child in node.Children)
{
NodesToEntities(data, child, entity, world, validationEffect, material);
NodesToEntities(data, child, entity, world, validationEffect, material, clips);
}
}
@@ -464,6 +435,9 @@ namespace GlitchyEngine.Content
ref JointAnimation jointAnimation = ref clip.JointAnimations[nodeIndex];
if(jointAnimation == null)
jointAnimation = new JointAnimation();
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Count == channel.Sampler.Output.Count);
int samples = (int)channel.Sampler.Input.Count;
@@ -536,131 +510,6 @@ namespace GlitchyEngine.Content
}
}
static (Skeleton, AnimationClip) ExtractBonestuff(CGLTF.Skin* skin, CGLTF.Data* data)
{
Skeleton skeleton = new Skeleton();
skeleton.Joints = new Joint[skin.Joints.Length];
AnimationClip testClip = new AnimationClip(skeleton);
testClip.IsLooping = true;
for(int i < skin.Joints.Length)
{
ref Joint joint = ref skeleton.Joints[i];
joint.InverseBindPose = GetEntry<Matrix>(skin.InverseBindMatrices, i);
joint.Name = new String(skin.Joints[i].Name);
int parentId = skin.Joints.IndexOf(skin.Joints[i].Parent);
Log.EngineLogger.AssertDebug(parentId < uint8.MaxValue, scope $"A skeleton must not have more than {uint8.MaxValue - 1} bones.");
if(parentId == -1)
joint.ParentID = uint8.MaxValue;
else
joint.ParentID = (uint8)parentId;
}
for(var channel in data.Animations[0].Channels)
{
int nodeIndex = skin.Joints.IndexOf(channel.TargetNode);
Log.EngineLogger.AssertDebug(nodeIndex != -1);
ref JointAnimation jointAnimation = ref testClip.JointAnimations[nodeIndex];
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Count == channel.Sampler.Output.Count);
int samples = (int)channel.Sampler.Input.Count;
Log.EngineLogger.AssertDebug(channel.Sampler.Input.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Input.Type == .Scalar);
InterpolationMode interpolationMode;
switch(channel.Sampler.Interpolation)
{
case .Step:
interpolationMode = .Step;
case .Linear:
interpolationMode = .Linear;
case .CubicSpline:
interpolationMode = .CubicSpline;
}
switch(channel.TargetPath)
{
case .Translation:
jointAnimation.TranslationChannel = new .(samples, interpolationMode);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec3);
for(int i < samples)
{
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
/*
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
float timeStamp2 = ?;
CGLTF.AccessorReadFloat(channel.Sampler.Input, (uint)i, (float*)&timeStamp2, 1);
Log.EngineLogger.Assert(timeStamp == timeStamp2);
Vector3 sample2 = ?;
CGLTF.AccessorReadFloat(channel.Sampler.Output, (uint)i, (float*)&sample2, 3);
Log.EngineLogger.Assert(sample == sample2);
*/
jointAnimation.TranslationChannel.TimeStamps[i] = timeStamp;
jointAnimation.TranslationChannel.Values[i] = sample;
}
case .Rotation:
jointAnimation.RotationChannel = new .(samples, interpolationMode);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec4);
for(int i < samples)
{
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
Quaternion sample = GetEntry<Quaternion>(channel.Sampler.Output, i);
jointAnimation.RotationChannel.TimeStamps[i] = timeStamp;
jointAnimation.RotationChannel.Values[i] = sample;
}
case .Scale:
jointAnimation.ScaleChannel = new .(samples, interpolationMode);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.ComponentType == .R_32f);
Log.EngineLogger.AssertDebug(channel.Sampler.Output.Type == .Vec3);
for(int i < samples)
{
float timeStamp = GetEntry<float>(channel.Sampler.Input, i);
Vector3 sample = GetEntry<Vector3>(channel.Sampler.Output, i);
jointAnimation.ScaleChannel.TimeStamps[i] = timeStamp;
jointAnimation.ScaleChannel.Values[i] = sample;
}
default:
Log.EngineLogger.Error($"Unknown channel target path \"{channel.TargetPath}\"");
}
//channel.
//
//testClip.JointAnimations[i].
testClip.Duration = Math.Max(testClip.Duration, jointAnimation.Duration);
}
return (skeleton, testClip);
}
static T GetEntry<T>(CGLTF.Accessor* accessor, int index)
{
Log.EngineLogger.AssertDebug((uint)index < accessor.Count);
@@ -68,8 +68,7 @@ namespace GlitchyEngine.Renderer.Animation
class AnimationClip : RefCounter
{
private Skeleton _skeleton ~ _.ReleaseRef();
//public float FramesPerSecond;
public JointAnimation[] JointAnimations;
public JointAnimation[] JointAnimations ~ delete _;
public bool IsLooping;
public float Duration;
@@ -78,7 +77,7 @@ namespace GlitchyEngine.Renderer.Animation
[AllowAppend]
public this(Skeleton skeleton)
{
var jointAnimations = append JointAnimation[skeleton.Joints.Count];
var jointAnimations = new JointAnimation[skeleton.Joints.Count];
Log.EngineLogger.AssertDebug(skeleton != null);
@@ -91,7 +90,8 @@ namespace GlitchyEngine.Renderer.Animation
{
for(var jointAnimation in JointAnimations)
{
jointAnimation.Dispose();
//jointAnimation.Dispose();
delete jointAnimation;
}
}
}
@@ -186,11 +186,11 @@ namespace GlitchyEngine.Renderer.Animation
}
}
struct JointAnimation : IDisposable
class JointAnimation// : IDisposable
{
public JointAnimationChannel<Vector3> TranslationChannel;
public JointAnimationChannel<Quaternion> RotationChannel;
public JointAnimationChannel<Vector3> ScaleChannel;
public JointAnimationChannel<Vector3> TranslationChannel ~ delete _;
public JointAnimationChannel<Quaternion> RotationChannel ~ delete _;
public JointAnimationChannel<Vector3> ScaleChannel ~ delete _;
public float Duration
{
@@ -200,14 +200,14 @@ namespace GlitchyEngine.Renderer.Animation
TranslationChannel?.Duration ?? 0, RotationChannel?.Duration ?? 0), ScaleChannel?.Duration ?? 0);
}
}
/*
public void Dispose()
{
delete TranslationChannel;
delete RotationChannel;
delete ScaleChannel;
}
*/
public JointPose GetCurrentPose(float timeStamp)
{
JointPose result;
+24 -2
View File
@@ -1,7 +1,29 @@
using System;
using GlitchyEngine.World;
namespace GlitchyEngine.Renderer
{
public struct MeshComponent
public struct MeshComponent : IDisposableComponent
{
public GeometryBinding Mesh;
private GeometryBinding _mesh;
public GeometryBinding Mesh
{
[Inline]
get => _mesh;
set mut
{
if(_mesh == value)
return;
SetReference!(_mesh, value);
}
}
public static void DisposeComponent(void* component)
{
Self* self = (Self*)component;
ReleaseRefAndNullify!(self._mesh);
}
}
}
@@ -16,9 +16,7 @@ namespace GlitchyEngine.World
if(_animationClip == value)
return;
_animationClip?.ReleaseRef();
_animationClip = value;
_animationClip?.AddRef();
SetReference!(_animationClip, value);
}
}
+7 -48
View File
@@ -215,25 +215,10 @@ namespace Sandbox
TestLoadModel();
}
//GeometryBinding _modelTest ~ _?.ReleaseRef();
List<(Matrix Transform, GeometryBinding Model)> _modelTest = new .() ~ UnloadModelTest!();
Skeleton Skeleton;
List<AnimationClip> Clips ~ delete _;
List<AnimationClip> Clips = new List<AnimationClip>() ~ DeleteContainerAndReleaseItems!(_);
Material animationMat;
mixin UnloadModelTest()
{
for(var entry in _modelTest)
{
entry.Model?.ReleaseRef();
}
delete _modelTest;
}
void TestLoadModel()
{
var testEffect = Application.Get().EffectLibrary.Get("testShader");
@@ -255,13 +240,7 @@ namespace Sandbox
materialTestMaterial.SetVariable("BaseColor", Color.White);
materialTestMaterial.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized());
//ModelLoader.LoadModel("content\\Models\\Test\\axisTest.glb", testEffect, _modelTest, out Skeleton, out Clip);
//ModelLoader.LoadModel("content\\Models\\RiggedSimple\\RiggedSimple.glb", testEffect, _modelTest, out Skeleton, out Clip);
//ModelLoader.LoadModel("content\\Models\\Fox\\Fox.glb", testEffect, _modelTest, out Skeleton, out Clip);
//ModelLoader.LoadModel("content\\Models\\Fox\\Fox_2.glb", testEffect, materialTestMaterial, _world, _modelTest, out Skeleton, out Clips);
//ModelLoader.LoadModel("content\\Models\\DancingCylinder\\DancingCylinder.glb", testEffect, _modelTest, out Skeleton, out Clip);
ModelLoader.LoadModel("content\\Models\\Figure\\Figure.gltf", testEffect, materialTestMaterial, _world, _modelTest, out Skeleton, out Clips);
//ModelLoader.LoadModel("content\\Models\\RiggedFigure\\RiggedFigure.glb", testEffect, materialTestMaterial, _world, _modelTest, out Skeleton, out Clips);
ModelLoader.LoadModel("content\\Models\\Figure\\Figure.gltf", testEffect, materialTestMaterial, _world, Clips);
materialTestMaterial.ReleaseRef();
testEffect.ReleaseRef();
@@ -275,28 +254,6 @@ namespace Sandbox
animation.IsPlaying = true;
animation.[Friend]_pose = new SkeletonPose(meshRenderer.Skeleton);
}
/*
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, "content\\Models\\box.gltf", out data);
CGLTF.LoadBuffers(options, data, "content\\Models\\box.gltf");
Log.EngineLogger.Assert(result == .Success, "Failed to load model");
var mesh = data.Meshes[0];
var primitive = mesh.Primitives[0];
var testEffect = _effectLibrary.Get("testShader");
_modelTest = ModelLoader.PrimitiveToGeoBinding(_context, primitive, testEffect);
testEffect.ReleaseRef();
/* TODO make awesome stuff */
CGLTF.Free(data);
*/
}
Entity evenCrazierParent;
@@ -436,8 +393,10 @@ namespace Sandbox
}
}
var skeleton = currentClip.Skeleton;
// Update joints
for(int i < Skeleton.Joints.Count)
for(int i < skeleton.Joints.Count)
{
ref JointPose localPose = ref pose.LocalPose[i];
@@ -448,7 +407,7 @@ namespace Sandbox
Matrix.RotationQuaternion(localPose.Rotation) *
Matrix.Scaling(localPose.Scale);
uint8 parentIndex = Skeleton.Joints[i].ParentID;
uint8 parentIndex = skeleton.Joints[i].ParentID;
ref Matrix globalPose = ref pose.GlobalPose[i];
@@ -461,7 +420,7 @@ namespace Sandbox
globalPose = pose.GlobalPose[parentIndex] * jointToParent;
}
pose.SkinningMatricies[i] = globalPose * Skeleton.Joints[i].InverseBindPose;
pose.SkinningMatricies[i] = globalPose * skeleton.Joints[i].InverseBindPose;
pose.InvTransSkinningMatricies[i] = ((Matrix3x3)pose.SkinningMatricies[i]).Inverse().Transpose();
}