Copy scene when entering play mode

This commit is contained in:
Simon Lübeß
2023-03-18 23:30:57 +01:00
parent 793aa40975
commit c164aeecaa
14 changed files with 172 additions and 248 deletions
-154
View File
@@ -229,160 +229,6 @@ namespace GlitchyEngine.Content
return .Success;
}
/*public static EcsEntity LoadModel(String filename, Material material, EcsWorld world,
List<AnimationClip> outClips, StringView entityName = StringView())
{
CGLTF.Options options = .();
CGLTF.Data* data;
CGLTF.Result result = CGLTF.ParseFile(options, filename, out data);
Log.EngineLogger.Assert(result == .Success, "Failed to load model.");
result = CGLTF.LoadBuffers(options, data, filename);
Log.EngineLogger.Assert(result == .Success, "Failed to load buffers");
(EcsEntity entity, ?) = CreateEntity(world, entityName, .InvalidEntity);
for(var node in data.Scenes[0].Nodes)
{
NodesToEntities(data, node, entity, world, material, outClips);
}
CGLTF.Free(data);
return entity;
}*/
private static (EcsEntity Entity, TransformComponent* Transform) CreateEntity(EcsWorld world, StringView? name, EcsEntity parent)
{
EcsEntity entity = world.NewEntity();
var nameComponent = world.AssignComponent<DebugNameComponent>(entity);
if (name != null && name.Value.Ptr != null)
{
nameComponent.SetName(name.Value);
}
else
{
nameComponent.SetName("Unnamed Node");
}
/////TODO: !!!!!!!!REPORT!!!!!!!!!!!!!
// This works
TransformComponent cmp = .();
var childTransform = world.AssignComponent<TransformComponent>(entity, cmp);
// This trashes the stack
//var childTransform = world.AssignComponent<TransformComponent>(entity);
childTransform.Parent = parent;
return (entity, childTransform);
}
/*private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, EcsEntity parentEntity, EcsWorld world, Material material, List<AnimationClip> clips)
{
(EcsEntity entity, TransformComponent* childTransform) = CreateEntity(world, node.Name == null ? null : StringView(node.Name), parentEntity);
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);
}
// Invert the Z-Axis of the root Node to convert the coordinate system from right-handed to left-handed
if(parentEntity == .InvalidEntity)
childTransform.Scale *= .(1, 1, -1);
Skeleton skeleton = null;
if(node.Skin != null)
{
skeleton = ExtractSkeleton(node.Skin);
LoadAnimationClips(data, node.Skin, skeleton, 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<MeshComponent>(entity);
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0]))
{
mesh.Mesh = Content.ManageAsset(geo);
}
if(skeleton == null)
{
var meshRenderer = world.AssignComponent<MeshRendererComponent>(entity);
meshRenderer.Material = material.Handle;
}
else
{
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(entity);
meshRenderer.Material = material;
meshRenderer.Skeleton = skeleton;
}
}
// otherwise one child-entity per primitive
else
{
for(var primitive in node.Mesh.Primitives)
{
EcsEntity meshEntity = world.NewEntity();
var meshParent = world.AssignComponent<ParentComponent>(meshEntity);
meshParent.Entity = entity;
var mesh = world.AssignComponent<MeshComponent>(meshEntity);
using (var geo = PrimitiveToGeoBinding(primitive))
{
mesh.Mesh = Content.ManageAsset(geo);
}
if(skeleton == null)
{
var meshRenderer = world.AssignComponent<MeshRendererComponent>(meshEntity);
meshRenderer.Material = material.Handle;
}
else
{
var meshRenderer = world.AssignComponent<SkinnedMeshRendererComponent>(meshEntity);
meshRenderer.Material = material;
meshRenderer.Skeleton = skeleton;
}
}
}
}
skeleton?.ReleaseRef();
for(var child in node.Children)
{
NodesToEntities(data, child, entity, world, material, clips);
}
}*/
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive)
{
GeometryBinding binding = new GeometryBinding();
+1 -1
View File
@@ -873,7 +873,7 @@ namespace GlitchyEngine.Renderer
}
}
public static void DrawSprite(Matrix transform, SpriterRendererComponent* spriteRenderer, uint32 entityId)
public static void DrawSprite(Matrix transform, SpriteRendererComponent* spriteRenderer, uint32 entityId)
{
if (spriteRenderer.IsCircle)
DrawCircle(transform, spriteRenderer.Sprite.Get() ?? s_whiteTexture, spriteRenderer.Color, 1.0f, spriteRenderer.UvTransform, entityId);
+1 -1
View File
@@ -45,7 +45,7 @@ namespace GlitchyEngine.World
}
[Component("Sprite Renderer")]
struct SpriterRendererComponent// : IDisposableComponent
struct SpriteRendererComponent// : IDisposableComponent
{
private AssetHandle<Texture2D> _sprite = .Invalid;
@@ -1,26 +0,0 @@
using System;
namespace GlitchyEngine.World
{
struct DebugNameComponent : IDisposableComponent
{
private String _debugName;
public String DebugName
{
get => _debugName;
set mut => SetName(value);
}
public void SetName(StringView name) mut
{
delete _debugName;
_debugName = new String(name);
}
public void Dispose() mut
{
DeleteAndNullify!(_debugName);
}
}
}
+6
View File
@@ -66,6 +66,12 @@ namespace GlitchyEngine.World
public UUID UUID => GetComponent<IDComponent>().ID;
public StringView Name
{
get => GetComponent<NameComponent>().Name;
set => GetComponent<NameComponent>().Name = value;
}
public TransformComponent* Transform => GetComponent<TransformComponent>();
public T* AddComponent<T>(T value = T()) where T: struct, new
+27
View File
@@ -0,0 +1,27 @@
using System;
namespace GlitchyEngine.World
{
struct NameComponent : IDisposableComponent
{
private String _name;
public StringView Name
{
get => _name;
set mut => SetName(value);
}
public void SetName(StringView name) mut
{
if (_name == null)
_name = new String(name);
else
_name.Set(name);
}
public void Dispose() mut
{
DeleteAndNullify!(_name);
}
}
}
@@ -1,10 +0,0 @@
namespace GlitchyEngine.World
{
/**
* A Component that allows to specify a parent entity.
*/
public struct ParentComponent
{
public EcsEntity Entity;
}
}
+65 -12
View File
@@ -11,7 +11,7 @@ namespace GlitchyEngine.World
using internal ScriptableEntity;
using internal GlitchyEngine.World;
class Scene
class Scene : RefCounter
{
internal EcsWorld _ecsWorld = new .() ~ delete _;
@@ -26,6 +26,8 @@ namespace GlitchyEngine.World
private AssetHandle _gammaCorrectEffect;
private uint32 _viewportWidth, _viewportHeight;
// Maps ids to the entities they represent.
private Dictionary<UUID, EcsEntity> _idToEntity = new .() ~ delete _;
@@ -56,7 +58,7 @@ namespace GlitchyEngine.World
_onComponentAddedHandlers.Add(typeof(CameraComponent), (e, t, c) => {
CameraComponent* cameraComponent = (.)c;
cameraComponent.Camera.SetViewportSize(e.Scene.ViewportWidth, e.Scene.ViewportHeight);
cameraComponent.Camera.SetViewportSize(e.Scene._viewportWidth, e.Scene._viewportHeight);
});
RenderTargetGroupDescription desc = .(100, 100,
@@ -82,6 +84,59 @@ namespace GlitchyEngine.World
public ~this()
{
}
public void CopyTo(Scene target)
{
// Copy entities
for (let sourceHandle in _ecsWorld.Enumerate())
{
Entity sourceEntity = .(sourceHandle, this);
target.CreateEntity(sourceEntity.Name, sourceEntity.UUID);
}
// TODO: perhaps use reflection and comptime
// Copy components
//CopyComponents<TransformComponent>(this, target); /* Parent will be copied below*/
CopyComponents<MeshRendererComponent>(this, target);
CopyComponents<EditorComponent>(this, target);
CopyComponents<SpriteRendererComponent>(this, target);
CopyComponents<CameraComponent>(this, target);
CopyComponents<NativeScriptComponent>(this, target);
CopyComponents<LightComponent>(this, target);
CopyComponents<Rigidbody2DComponent>(this, target);
CopyComponents<BoxCollider2DComponent>(this, target);
CopyComponents<CircleCollider2DComponent>(this, target);
// Copy transforms
for (let (sourceHandle, sourceTransform) in _ecsWorld.Enumerate<TransformComponent>())
{
Entity sourceEntity = Entity(sourceHandle, this);
Entity sourceParent = Entity(sourceTransform.Parent, this);
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
*targetEntity.Transform = *sourceTransform;
if (sourceParent.IsValid)
{
Entity targetParent = target.GetEntityByID(sourceParent.UUID);
targetEntity.Parent = targetParent;
}
}
target.OnViewportResize(_viewportWidth, _viewportHeight);
}
private static void CopyComponents<TComponent>(Scene source, Scene target) where TComponent : struct, new
{
for (let (sourceHandle, sourceComponent) in source._ecsWorld.Enumerate<TComponent>())
{
Entity sourceEntity = .(sourceHandle, source);
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
targetEntity.AddComponent<TComponent>(*sourceComponent);
}
}
b2Vec2 _gravity2D = .(0.0f, -9.8f);
@@ -256,7 +311,7 @@ namespace GlitchyEngine.World
// Sprite renderer
Renderer2D.BeginScene(*primaryCamera, primaryCameraTransform, .BackToFront);
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriterRendererComponent>())
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriteRendererComponent>())
{
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
}
@@ -469,7 +524,7 @@ namespace GlitchyEngine.World
// Sprite renderer
Renderer2D.BeginScene(camera, .BackToFront);
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriterRendererComponent>())
for (var (entity, transform, sprite) in _ecsWorld.Enumerate<TransformComponent, SpriteRendererComponent>())
{
Renderer2D.DrawSprite(transform.WorldTransform, sprite, entity.Index);
}
@@ -502,12 +557,12 @@ namespace GlitchyEngine.World
}
/// Creates a new Entity with the given name.
public Entity CreateEntity(String name = "", UUID id = default)
public Entity CreateEntity(StringView name = "", UUID id = default)
{
Entity entity = Entity(_ecsWorld.NewEntity(), this);
entity.AddComponent<TransformComponent>();
let nameComponent = entity.AddComponent<DebugNameComponent>();
let nameComponent = entity.AddComponent<NameComponent>();
nameComponent.SetName(name.IsEmpty ? "Entity" : name);
// If no id is given generate a random one.
@@ -549,13 +604,11 @@ namespace GlitchyEngine.World
return .Err;
}
private uint32 ViewportWidth, ViewportHeight;
/// Sets the size of the viewport into which the scene will be rendered.
public void OnViewportResize(uint32 width, uint32 height)
{
ViewportWidth = width;
ViewportHeight = height;
_viewportWidth = width;
_viewportHeight = height;
for (var (entity, cameraComponent) in _ecsWorld.Enumerate<CameraComponent>())
{
@@ -565,8 +618,8 @@ namespace GlitchyEngine.World
}
}
_compositeTarget.Resize(ViewportWidth, ViewportHeight);
_cameraTarget.Resize(ViewportWidth, ViewportHeight);
_compositeTarget.Resize(_viewportWidth, _viewportHeight);
_cameraTarget.Resize(_viewportWidth, _viewportHeight);
}
private void OnComponentAdded(Entity entity, Type componentType, void* component)
+5 -5
View File
@@ -79,12 +79,12 @@ class SceneSerializer
SerializeComponent<EditorComponent>(writer, entity, "EditorComponent", scope (component) => {});
SerializeComponent<DebugNameComponent>(writer, entity, "NameComponent", scope (component) =>
SerializeComponent<NameComponent>(writer, entity, "NameComponent", scope (component) =>
{
Serialize.Value(writer, "Name", component.DebugName);
Serialize.Value(writer, "Name", component.Name);
});
SerializeComponent<SpriterRendererComponent>(writer, entity, "SpriterRendererComponent", scope (component) =>
SerializeComponent<SpriteRendererComponent>(writer, entity, "SpriterRendererComponent", scope (component) =>
{
Serialize.Value(writer, "Color", component.Color);
Serialize.Value(writer, "IsCircle", component.IsCircle);
@@ -317,7 +317,7 @@ class SceneSerializer
case "EditorComponent":
Try!(DeserializeComponent<EditorComponent>(reader, entity, scope (component) => { return .Ok; }));
case "NameComponent":
Try!(DeserializeComponent<DebugNameComponent>(reader, entity, scope (component) =>
Try!(DeserializeComponent<NameComponent>(reader, entity, scope (component) =>
{
String name;
@@ -330,7 +330,7 @@ class SceneSerializer
return .Ok;
}));
case "SpriterRendererComponent":
Try!(DeserializeComponent<SpriterRendererComponent>(reader, entity, scope (component) =>
Try!(DeserializeComponent<SpriteRendererComponent>(reader, entity, scope (component) =>
{
Try!(Deserialize.Value(reader, "Color", out component.Color));
reader.EntryEnd();
@@ -20,6 +20,7 @@ namespace GlitchyEngine.World
/// The frame when the transform was recalculated
public uint Frame;
// TODO: probably use UUID
public EcsEntity Parent
{
get => _parent;