diff --git a/GlitchyEngine/src/Content/ModelLoader.bf b/GlitchyEngine/src/Content/ModelLoader.bf index 971ba1d..7641c86 100644 --- a/GlitchyEngine/src/Content/ModelLoader.bf +++ b/GlitchyEngine/src/Content/ModelLoader.bf @@ -4,6 +4,7 @@ using cgltf; using GlitchyEngine.Math; using GlitchyEngine.Renderer; using GlitchyEngine.Renderer.Animation; +using GlitchyEngine.World; namespace GlitchyEngine.Content { @@ -11,10 +12,11 @@ namespace GlitchyEngine.Content { static readonly Matrix RightToLeftHand = .Scaling(1, 1, -1); - public static void LoadModel(String filename, GraphicsContext context, Effect validationEffect, List<(Matrix Transform, GeometryBinding Model)> output, out Skeleton skeleton, out AnimationClip clip) + public static void LoadModel(String filename, GraphicsContext context, Effect validationEffect, Material material, EcsWorld world, + List<(Matrix Transform, GeometryBinding Model)> output, out Skeleton skeleton, out List clips) { skeleton = null; - clip = null; + removeMe___Clips = null; CGLTF.Options options = .(); CGLTF.Data* data; @@ -26,6 +28,14 @@ namespace GlitchyEngine.Content Log.EngineLogger.Assert(result == .Success, "Failed to load buffers"); + for(var node in data.Scenes[0].Nodes) + { + NodesToEntities(data, node, null, world, context, validationEffect, material); + } + + clips = removeMe___Clips; + + for(var node in data.Nodes) { if(node.Mesh != null) @@ -45,12 +55,117 @@ namespace GlitchyEngine.Content if(node.Skin != null) { + AnimationClip clip; (skeleton, clip) = ExtractBonestuff(node.Skin, data); + clips.Add(clip); + } + } + + + CGLTF.Free(data); + } + + static List removeMe___Clips; + + private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, Entity? parentEntity, EcsWorld world, GraphicsContext context, Effect validationEffect, Material material) + { + Entity entity = world.NewEntity(); + + if(parentEntity.HasValue) + { + var childParent = world.AssignComponent(entity); + childParent.Entity = parentEntity.Value; + } + + var childTransform = world.AssignComponent(entity); + + if(node.HasMatrix) + { + childTransform.LocalTransform = *(Matrix*)&node.Matrix; + } + else + { + if(node.HasTranslation) + childTransform.Position = *(Vector3*)&node.Translation; + else + childTransform.Position = .Zero; + + if(node.HasRotation) + childTransform.Rotation = *(Quaternion*)&node.Rotation; + else + childTransform.Rotation = .Identity; + + if(node.HasScale) + childTransform.Scale = *(Vector3*)&node.Scale; + else + childTransform.Scale = .(1, 1, 1); + } + + if(parentEntity == null) + childTransform.Scale *= .(1, 1, -1); + + Skeleton skeleton = null; + + if(node.Skin != null) + { + skeleton = ExtractSkeleton(node.Skin); + + removeMe___Clips = new List(); + LoadAnimationClips(data, node.Skin, skeleton, removeMe___Clips); + } + + if(node.Mesh != null) + { + // If we have only one primitive, add it directly to the entity + if(node.Mesh.Primitives.Length == 1) + { + var mesh = world.AssignComponent(entity); + mesh.Mesh = ModelLoader.PrimitiveToGeoBinding(context, node.Mesh.Primitives[0], validationEffect); + + if(skeleton == null) + { + var meshRenderer = world.AssignComponent(entity); + meshRenderer.Material = material; + } + else + { + var meshRenderer = world.AssignComponent(entity); + meshRenderer.Material = material; + meshRenderer.Skeleton = skeleton; + } + } + // otherwise one child-entity per primitive + else + { + for(var primitive in node.Mesh.Primitives) + { + Entity meshEntity = world.NewEntity(); + + var meshParent = world.AssignComponent(meshEntity); + meshParent.Entity = entity; + + var mesh = world.AssignComponent(meshEntity); + mesh.Mesh = ModelLoader.PrimitiveToGeoBinding(context, node.Mesh.Primitives[0], validationEffect); + + if(skeleton == null) + { + var meshRenderer = world.AssignComponent(entity); + meshRenderer.Material = material; + } + else + { + var meshRenderer = world.AssignComponent(entity); + meshRenderer.Material = material; + meshRenderer.Skeleton = skeleton; + } + } } } - /* TODO make awesome stuff */ - CGLTF.Free(data); + for(var child in node.Children) + { + NodesToEntities(data, child, entity, world, context, validationEffect, material); + } } public static GeometryBinding PrimitiveToGeoBinding(GraphicsContext context, CGLTF.Primitive primitive, Effect validationEffect) @@ -95,6 +210,9 @@ namespace GlitchyEngine.Content } } + bool hasNormals = false; + bool hasTangents = false; + // vertices { List elements = scope .(primitive.Attributes.Length); @@ -103,6 +221,19 @@ namespace GlitchyEngine.Content for(var attribute in primitive.Attributes) { + { + StringView attributeName = StringView(attribute.Name); + + if(attributeName.Equals("NORMAL")) + { + hasNormals = true; + } + else if(attributeName.Equals("TANGENT")) + { + hasTangents = true; + } + } + // Get Input Element format Format format = FormatFromVectorComponent(attribute.Data.Type, attribute.Data.ComponentType); Log.EngineLogger.AssertDebug(format != .Unknown, "Vertex element format must not be \"Unknown.\""); @@ -114,7 +245,7 @@ namespace GlitchyEngine.Content // Get vertex buffer { CGLTF.BufferView* bufferView = attribute.Data.BufferView; - + // if buffer doesn't exist -> create if(!buffers.TryGetValue(bufferView, out vertexBuffer)) { @@ -147,6 +278,7 @@ namespace GlitchyEngine.Content StringView strView = .(attribute.Name); + // Remove number from end of name while((*(strView.EndPtr - 1)).IsDigit) { strView.Length--; @@ -156,36 +288,254 @@ namespace GlitchyEngine.Content elements.Add(element); } + // Generate normals if missing + if(!hasNormals) + { + CGLTF.Accessor* positions = null; + + // Find position accessor + for(var attribute in primitive.Attributes) + { + if(StringView(attribute.Name).Equals("POSITION")) + { + positions = attribute.Data; + break; + } + } + + Log.EngineLogger.AssertDebug(positions != null, "The model appears to have no position data?!"); + + Vector3[] normals = new Vector3[positions.Count]; + + if(primitive.Indices != null) + GenerateNormals(primitive.Indices, positions, normals); + else + GenerateNormals(positions, normals); + + VertexBuffer vertexBuffer = new VertexBuffer(context, (uint32)sizeof(Vector3), (uint32)normals.Count, .Immutable); + vertexBuffer.SetData(normals); + + bindings.Add(vertexBuffer.Binding); + + uint32 bindingSlot = (.)bindings.Count - 1; + + binding.SetVertexBufferSlot(vertexBuffer.Binding, (.)bindingSlot); + VertexElement element = .(.R32G32B32_Float, "NORMAL", false, 0, bindingSlot); + elements.Add(element); + } + + // TODO: validate vertex layout somewhere else + VertexElement[] vertexElements = new VertexElement[elements.Count]; for(int i < elements.Count) { vertexElements[i] = elements[i]; } - // TODO: validate vertex layout somewhere else - VertexLayout layout = new VertexLayout(context, vertexElements, true, validationEffect.VertexShader); binding.SetVertexLayout(layout..ReleaseRefNoDelete()); } - // TODO: calculate normals if missing // TODO: calculate tangents if missing (MikkTSpace algorithm) // Note: Bitangent = cross(normal, tangent.xyz) * tangent.w return binding; } + /// Generates the normals for one triangle + static mixin GenerateTriangleNormals(int index0, int index1, int index2, CGLTF.Accessor* positions, Vector3[] normals) + { + Vector3 position0 = GetEntry(positions, (.)index0); + Vector3 position1 = GetEntry(positions, (.)index1); + Vector3 position2 = GetEntry(positions, (.)index2); + + ref Vector3 normal0 = ref normals[(.)index0]; + ref Vector3 normal1 = ref normals[(.)index1]; + ref Vector3 normal2 = ref normals[(.)index2]; + + Vector3 e0 = position1 - position0; + Vector3 e1 = position2 - position0; + + Vector3 normal = Vector3.Cross(e0, e1); + + normal0 += normal; + normal1 += normal; + normal2 += normal; + } + + [Inline] + static void NormalizeNormals(Vector3[] normals) + { + for(int i < normals.Count) + { + normals[i].Normalize(); + } + } + + /// Generates normals for the given model using indexed geometry + static void GenerateNormals(CGLTF.Accessor* indices, CGLTF.Accessor* positions, Vector3[] normals) + { + /// Enumerate triangle-wise + for(uint t = 0; t < indices.Count; t += 3) + { + int index0 = (.)CGLTF.AccessorReadIndex(indices, t); + int index1 = (.)CGLTF.AccessorReadIndex(indices, t + 1); + int index2 = (.)CGLTF.AccessorReadIndex(indices, t + 2); + + GenerateTriangleNormals!(index0, index1, index2, positions, normals); + } + + NormalizeNormals(normals); + } + + /// Generates normals for the given model using nonindexed geometry + static void GenerateNormals(CGLTF.Accessor* positions, Vector3[] normals) + { + /// Enumerate triangle-wise + for(int i = 0; i < (.)positions.Count; i += 3) + { + GenerateTriangleNormals!(i, i + 1, i + 2, positions, normals); + } + + NormalizeNormals(normals); + } + + static Skeleton ExtractSkeleton(CGLTF.Skin* skin) + { + Skeleton skeleton = new Skeleton(); + skeleton.Joints = new Joint[skin.Joints.Length]; + + for(int i < skin.Joints.Length) + { + ref Joint joint = ref skeleton.Joints[i]; + + joint.InverseBindPose = GetEntry(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; + } + + return skeleton; + } + + static bool AnimationBelongsToSkeleton(CGLTF.Animation animation, CGLTF.Skin* skin) + { + for(var channel in animation.Channels) + { + if(skin.Joints.IndexOf(channel.TargetNode) == -1) + { + return false; + } + } + + return true; + } + + static void LoadAnimationClips(CGLTF.Data* data, CGLTF.Skin* skin, Skeleton skeleton, List clips) + { + for(var animation in data.Animations) + { + if(!AnimationBelongsToSkeleton(animation, skin)) + continue; + + AnimationClip clip = new AnimationClip(skeleton); + clips.Add(clip); + clip.IsLooping = true; + + for(var channel in animation.Channels) + { + int nodeIndex = skin.Joints.IndexOf(channel.TargetNode); + + Log.EngineLogger.AssertDebug(nodeIndex != -1); + + ref JointAnimation jointAnimation = ref clip.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(channel.Sampler.Input, i); + Vector3 sample = GetEntry(channel.Sampler.Output, i); + + 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(channel.Sampler.Input, i); + Quaternion sample = GetEntry(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(channel.Sampler.Input, i); + Vector3 sample = GetEntry(channel.Sampler.Output, i); + + jointAnimation.ScaleChannel.TimeStamps[i] = timeStamp; + jointAnimation.ScaleChannel.Values[i] = sample; + } + default: + Log.EngineLogger.Error($"Unknown channel target path \"{channel.TargetPath}\""); + } + + clip.Duration = Math.Max(clip.Duration, jointAnimation.Duration); + } + } + } + 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(); - testClip.Skeleton = skeleton; - testClip.FramesPerSecond = 0; - testClip.JointAnimations = new JointAnimation[skeleton.Joints.Count]; - //testClip.Samples = new AnimationSample[1]; - //testClip.Samples[0].JointPose = new JointPose[skeleton.Joints.Count]; + AnimationClip testClip = new AnimationClip(skeleton); testClip.IsLooping = true; for(int i < skin.Joints.Length) @@ -323,6 +673,16 @@ namespace GlitchyEngine.Content CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 4); case typeof(Matrix): CGLTF.AccessorReadFloat(accessor, (uint)index, (float*)&result, 16); + case default: + uint8* data = (uint8*)accessor.BufferView.Buffer.Data; + + data += accessor.BufferView.Offset; + + data += accessor.Offset; + + data += accessor.Stride * (uint)index; + + result = *(T*)data; } return result; diff --git a/GlitchyEngine/src/Renderer/Animation/AnimationClip.bf b/GlitchyEngine/src/Renderer/Animation/AnimationClip.bf index c918190..1ead3af 100644 --- a/GlitchyEngine/src/Renderer/Animation/AnimationClip.bf +++ b/GlitchyEngine/src/Renderer/Animation/AnimationClip.bf @@ -67,25 +67,24 @@ namespace GlitchyEngine.Renderer.Animation class AnimationClip : RefCounted { private Skeleton _skeleton ~ _.ReleaseRef(); - public float FramesPerSecond; + //public float FramesPerSecond; public JointAnimation[] JointAnimations; public bool IsLooping; public float Duration; - public Skeleton Skeleton - { - get => _skeleton; - set - { - if(_skeleton == value) - return; + public Skeleton Skeleton => _skeleton; - _skeleton?.ReleaseRef(); - _skeleton = value; - _skeleton?.AddRef(); - } + [AllowAppend] + public this(Skeleton skeleton) + { + var jointAnimations = append JointAnimation[skeleton.Joints.Count]; + + Log.EngineLogger.AssertDebug(skeleton != null); + + _skeleton = skeleton..AddRef(); + JointAnimations = jointAnimations; } - + // TODO: check public ~this() { @@ -93,8 +92,6 @@ namespace GlitchyEngine.Renderer.Animation { jointAnimation.Dispose(); } - - delete JointAnimations; } } diff --git a/Sandbox/src/SandboxApp.bf b/Sandbox/src/SandboxApp.bf index 8e204bb..ca54a57 100644 --- a/Sandbox/src/SandboxApp.bf +++ b/Sandbox/src/SandboxApp.bf @@ -84,6 +84,8 @@ namespace Sandbox [AllowAppend] public this() : base("Example") { + Application.Get().Window.IsVSync = false; + _context = Application.Get().Window.Context..AddRef(); var effectLibrary = Application.Get().EffectLibrary; @@ -217,9 +219,11 @@ namespace Sandbox List<(Matrix Transform, GeometryBinding Model)> _modelTest = new .() ~ UnloadModelTest!(); - Skeleton Skeleton ~ delete _; - AnimationClip Clip ~ delete _; + Skeleton Skeleton; + List Clips ~ delete _; + AnimationPlayer AnimationPlayer ~ delete _; + Material animationMat; mixin UnloadModelTest() { @@ -234,18 +238,44 @@ namespace Sandbox void TestLoadModel() { var testEffect = Application.Get().EffectLibrary.Get("testShader"); + var materialTestMaterial = new Material(testEffect); + animationMat = materialTestMaterial; + + Matrix[] matrices = scope Matrix[255]; + Matrix3x3[] matrices2 = scope Matrix3x3[255]; + + for(int i < 255) + { + matrices[i] = .Identity; + matrices2[i] = .Identity; + } + + materialTestMaterial.SetVariable("SkinningMatrices", matrices); + materialTestMaterial.SetVariable("InvTransSkinningMatrices", matrices2); + + materialTestMaterial.SetVariable("BaseColor", Color.White); + materialTestMaterial.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized()); //ModelLoader.LoadModel("content\\Models\\Test\\axisTest.glb", _context, testEffect, _modelTest, out Skeleton, out Clip); //ModelLoader.LoadModel("content\\Models\\RiggedSimple\\RiggedSimple.glb", _context, testEffect, _modelTest, out Skeleton, out Clip); - //ModelLoader.LoadModel("content\\Models\\Fox\\Fox_2.glb", _context, testEffect, _modelTest, out Skeleton, out Clip); + //ModelLoader.LoadModel("content\\Models\\Fox\\Fox.glb", _context, testEffect, _modelTest, out Skeleton, out Clip); + //ModelLoader.LoadModel("content\\Models\\Fox\\Fox_2.glb", _context, testEffect, materialTestMaterial, _world, _modelTest, out Skeleton, out Clips); //ModelLoader.LoadModel("content\\Models\\DancingCylinder\\DancingCylinder.glb", _context, testEffect, _modelTest, out Skeleton, out Clip); - //ModelLoader.LoadModel("content\\Models\\Figure\\Figure.gltf", _context, testEffect, _modelTest, out Skeleton, out Clip); - ModelLoader.LoadModel("content\\Models\\RiggedFigure\\RiggedFigure.glb", _context, testEffect, _modelTest, out Skeleton, out Clip); + ModelLoader.LoadModel("content\\Models\\Figure\\Figure.gltf", _context, testEffect, materialTestMaterial, _world, _modelTest, out Skeleton, out Clips); + //ModelLoader.LoadModel("content\\Models\\RiggedFigure\\RiggedFigure.glb", _context, testEffect, materialTestMaterial, _world, _modelTest, out Skeleton, out Clips); + materialTestMaterial.ReleaseRef(); testEffect.ReleaseRef(); - if(Skeleton != null && Clip != null) - AnimationPlayer = new AnimationPlayer(Skeleton, Clip); + if(Clips != null && Clips.Count > 0) + AnimationPlayer = new AnimationPlayer(Skeleton, Clips.Back); + + for(var (entity, transform, mesh, meshRenderer) in _world.Enumerate()) + { + var animation = _world.AssignComponent(entity); + + animation.AnimationClip = Clips[0]; + } /* CGLTF.Options options = .(); @@ -282,7 +312,9 @@ namespace Sandbox _world.Register(); _world.Register(); _world.Register(); + _world.Register(); _world.Register(); + _world.Register(); var basicEffect = Application.Get().EffectLibrary.Get("basicShader"); @@ -292,7 +324,7 @@ namespace Sandbox testMaterial2.SetVariable("BaseColor", _squareColor1); basicEffect.ReleaseRef(); - + /* Entity[20][20] entities; int i = 0; @@ -343,12 +375,12 @@ namespace Sandbox var parent = _world.AssignComponent(entities[x][y]); parent.Entity = crazyParent; } + */ } float f = 0.0f; bool playAnimation = false; - bool drawModel = false; public override void Update(GameTime gameTime) { @@ -371,14 +403,26 @@ namespace Sandbox _opaqueBlendState.Bind(); var basicEffect = Application.Get().EffectLibrary.Get("basicShader"); + + _context.SetRasterizerState(_rasterizerState); - // Model test + TransformSystem.Update(_world); + + for(var (entity, transform, mesh, meshRenderer) in _world.Enumerate()) { - //AnimationPlayer.CurrentClip.Samples[0].JointPose[1].Rotation = .(1, 0, 0, 1)..Normalize(); + Renderer.Submit(mesh.Mesh, meshRenderer.Material, transform.WorldTransform); + } + + for(var (entity, transform, mesh, meshRenderer, animation) in _world.Enumerate()) + { + var material = meshRenderer.Material; - Matrix scaling = .Scaling(1f, 1.0f, -1.0f); + //var testEffect = Application.Get().EffectLibrary.Get("testShader"); - var testEffect = Application.Get().EffectLibrary.Get("testShader"); + if(AnimationPlayer == null) + { + AnimationPlayer = new AnimationPlayer(meshRenderer.Skeleton, Clips[0]); + } if(AnimationPlayer != null) { @@ -417,68 +461,27 @@ namespace Sandbox Vector3 end = parentMatrix.Translation; - Renderer.DrawLine(start, end, .Black, scaling); + Renderer.DrawLine(start, end, .Black, transform.WorldTransform); } - Renderer.DrawLine(.Zero, Vector3(0.1f, 0, 0), .Red, scaling * mat); - Renderer.DrawLine(.Zero, Vector3(0, 0.1f, 0), .Lime, scaling * mat); - Renderer.DrawLine(.Zero, Vector3(0, 0, 0.1f), .Blue, scaling * mat); + Renderer.DrawLine(.Zero, Vector3(0.1f, 0, 0), .Red, transform.WorldTransform * mat); + Renderer.DrawLine(.Zero, Vector3(0, 0.1f, 0), .Lime, transform.WorldTransform * mat); + Renderer.DrawLine(.Zero, Vector3(0, 0, 0.1f), .Blue, transform.WorldTransform * mat); i++; } - - testEffect.Variables["SkinningMatrices"].SetData(AnimationPlayer.SkinningMatricies); - testEffect.Variables["InvTransSkinningMatrices"].SetData(AnimationPlayer.InvTransSkinningMatricies); - - testEffect.Variables["BaseColor"].SetData(Color.White); - testEffect.Variables["LightDir"].SetData(Vector3(1, 1, -0.5f).Normalized()); - + + material.SetVariable("SkinningMatrices", AnimationPlayer.SkinningMatricies); + material.SetVariable("InvTransSkinningMatrices", AnimationPlayer.InvTransSkinningMatricies); + + // TODO: non engine + material.SetVariable("BaseColor", Color.White); + material.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized()); } - if(drawModel) - { - for(var entry in _modelTest) - { - Renderer.Submit(entry.Model, testEffect, .Identity * scaling);//entry.Transform - } - } - - testEffect.ReleaseRef(); + Renderer.Submit(mesh.Mesh, material, transform.WorldTransform); } - _context.SetRasterizerState(_rasterizerState); - - //var crazyTransform = _world.GetComponent(evenCrazierParent); - //crazyTransform.Rotation += .((float)gameTime.FrameTime.TotalSeconds / 2, 0, 0); - - - var crazyTransform = _world.GetComponent(crazyParent); - if(Input.IsKeyPressed(Key.Six)) - { - crazyTransform.RotationEuler += .((float)gameTime.FrameTime.TotalSeconds, 0, 0); - } - if(Input.IsKeyPressed(Key.Seven)) - { - crazyTransform.RotationEuler += .(0, (float)gameTime.FrameTime.TotalSeconds, 0); - } - if(Input.IsKeyPressed(Key.Eight)) - { - Vector3 vec = crazyTransform.RotationEuler; - vec += .(0, 0, (float)gameTime.FrameTime.TotalSeconds); - crazyTransform.RotationEuler = vec; - } - if(Input.IsKeyPressed(Key.Nine)) - { - crazyTransform.RotationEuler = .(0, 0, 0); - } - - TransformSystem.Update(_world); - - for(var (entity, transform, mesh, meshRenderer) in _world.Enumerate()) - { - Renderer.Submit(mesh.Mesh, meshRenderer.Material, transform.WorldTransform); - } - basicEffect.Variables["BaseColor"].SetData(_squareColor1); _checkerMaterial.SetVariable("BaseColor", Color.White); @@ -517,18 +520,16 @@ namespace Sandbox if(AnimationPlayer != null) { - ImGui.DragFloat("Timestamp", &AnimationPlayer.TimeStamp, 0.01f, -Clip.Duration, Clip.Duration); + ImGui.DragFloat("Timestamp", &AnimationPlayer.TimeStamp, 0.01f, -AnimationPlayer.CurrentClip.Duration, AnimationPlayer.CurrentClip.Duration); while(AnimationPlayer.TimeStamp < 0) { - AnimationPlayer.TimeStamp += Clip.Duration; + AnimationPlayer.TimeStamp += AnimationPlayer.CurrentClip.Duration; } ImGui.Checkbox("Play", &playAnimation); } - ImGui.Checkbox("Draw Model", &drawModel); - ImGui.End(); ImGui.Begin("Test");