Basic mutability framework
This commit is contained in:
@@ -12,8 +12,36 @@ Actor::~Actor()
|
||||
{
|
||||
|
||||
}
|
||||
void Actor::tick(float)
|
||||
|
||||
void Actor::launchStart()
|
||||
{
|
||||
rootComponent->launchStart();
|
||||
for(auto child : children)
|
||||
{
|
||||
child->launchStart();
|
||||
}
|
||||
start();
|
||||
}
|
||||
Array<Job> Actor::launchTick(float deltaTime) const
|
||||
{
|
||||
Array<Job> result = rootComponent->launchTick(deltaTime);
|
||||
for(auto child : children)
|
||||
{
|
||||
result.addAll(child->launchTick(deltaTime));
|
||||
}
|
||||
result.add(tick(deltaTime));
|
||||
return result;
|
||||
}
|
||||
|
||||
Array<Job> Actor::launchUpdate()
|
||||
{
|
||||
Array<Job> result = rootComponent->launchUpdate();
|
||||
for(auto child : children)
|
||||
{
|
||||
result.addAll(child->launchUpdate());
|
||||
}
|
||||
result.add(update());
|
||||
return result;
|
||||
}
|
||||
void Actor::notifySceneAttach(PScene scene)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Math/Transform.h"
|
||||
#include "ThreadPool.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -12,8 +13,12 @@ class Actor
|
||||
public:
|
||||
Actor();
|
||||
virtual ~Actor();
|
||||
|
||||
void tick(float deltaTime);
|
||||
virtual void launchStart();
|
||||
virtual void start() {}
|
||||
Array<Job> launchTick(float deltaTime) const;
|
||||
virtual Job tick(float deltaTime) const { co_return; }
|
||||
Array<Job> launchUpdate();
|
||||
virtual Job update() { co_return; }
|
||||
void notifySceneAttach(PScene scene);
|
||||
PScene getScene();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
target_sources(SeeleEngine
|
||||
PRIVATE
|
||||
Util.h
|
||||
Scene.cpp
|
||||
Scene.h)
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ target_sources(SeeleEngine
|
||||
CameraComponent.cpp
|
||||
Component.h
|
||||
Component.cpp
|
||||
MyComponent.h
|
||||
MyComponent.cpp
|
||||
MyOtherComponent.h
|
||||
MyOtherComponent.cpp
|
||||
PrimitiveComponent.cpp
|
||||
PrimitiveComponent.h
|
||||
PrimitiveUniformBufferLayout.h)
|
||||
@@ -5,11 +5,16 @@
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
CameraComponent::CameraComponent()
|
||||
: bNeedsViewBuild(true)
|
||||
CameraComponent::CameraComponent()
|
||||
: aspectRatio(0)
|
||||
, fieldOfView(0)
|
||||
, bNeedsViewBuild(true)
|
||||
, bNeedsProjectionBuild(true)
|
||||
, originPoint(0, 0, 0)
|
||||
, cameraPosition(0, 0, 50)
|
||||
, eye(Vector())
|
||||
, projectionMatrix(Matrix4())
|
||||
, viewMatrix(Matrix4())
|
||||
{
|
||||
distance = 50;
|
||||
rotationX = 0;
|
||||
|
||||
@@ -13,9 +13,38 @@ Component::Component()
|
||||
Component::~Component()
|
||||
{
|
||||
}
|
||||
void Component::tick(float)
|
||||
|
||||
void Component::launchStart()
|
||||
{
|
||||
for(auto child : children)
|
||||
{
|
||||
child->launchStart();
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
Array<Job> Component::launchTick(float deltaTime) const
|
||||
{
|
||||
Array<Job> result;
|
||||
for(auto child : children)
|
||||
{
|
||||
result.addAll(child->launchTick(deltaTime));
|
||||
}
|
||||
result.add(tick(deltaTime));
|
||||
return result;
|
||||
}
|
||||
|
||||
Array<Job> Component::launchUpdate()
|
||||
{
|
||||
Array<Job> result;
|
||||
for(auto child : children)
|
||||
{
|
||||
result.addAll(child->launchUpdate());
|
||||
}
|
||||
result.add(update());
|
||||
return result;
|
||||
}
|
||||
|
||||
PComponent Component::getParent()
|
||||
{
|
||||
return parent;
|
||||
@@ -32,6 +61,25 @@ PActor Component::getOwner()
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
const Array<PComponent>& Component::getChildComponents()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
void Component::setParent(PComponent newParent)
|
||||
{
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
void Component::setOwner(PActor newOwner)
|
||||
{
|
||||
owner = newOwner;
|
||||
}
|
||||
|
||||
void Component::addChildComponent(PComponent component)
|
||||
{
|
||||
children.add(component);
|
||||
}
|
||||
|
||||
void Component::notifySceneAttach(PScene scene)
|
||||
{
|
||||
@@ -118,16 +166,6 @@ Transform Component::getTransform() const
|
||||
return transform;
|
||||
}
|
||||
|
||||
void Component::setParent(PComponent newParent)
|
||||
{
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
void Component::setOwner(PActor newOwner)
|
||||
{
|
||||
owner = newOwner;
|
||||
}
|
||||
|
||||
void Component::internalSetTransform(Vector newLocation, Quaternion newRotation)
|
||||
{
|
||||
if (parent != nullptr)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
#include "Math/Transform.h"
|
||||
#include "Scene/Util.h"
|
||||
#include "ThreadPool.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -12,11 +14,18 @@ class Component
|
||||
public:
|
||||
Component();
|
||||
virtual ~Component();
|
||||
void tick(float deltaTime);
|
||||
void launchStart();
|
||||
virtual void start() {};
|
||||
Array<Job> launchTick(float deltaTime) const;
|
||||
virtual Job tick(float deltaTime) const { co_return; }
|
||||
Array<Job> launchUpdate();
|
||||
virtual Job update() { co_return; }
|
||||
PComponent getParent();
|
||||
PActor getOwner();
|
||||
const Array<PComponent>& getChildComponents();
|
||||
void setParent(PComponent parent);
|
||||
void setOwner(PActor owner);
|
||||
void addChildComponent(PComponent component);
|
||||
virtual void notifySceneAttach(PScene scene);
|
||||
|
||||
void setWorldLocation(Vector location);
|
||||
@@ -35,7 +44,30 @@ public:
|
||||
|
||||
Transform getTransform() const;
|
||||
|
||||
template<typename ComponentType>
|
||||
RefPtr<ComponentType> getComponent()
|
||||
{
|
||||
return tryFindComponent<ComponentType>();
|
||||
}
|
||||
private:
|
||||
template<typename ComponentType>
|
||||
RefPtr<ComponentType> tryFindComponent()
|
||||
{
|
||||
for(auto child : children)
|
||||
{
|
||||
RefPtr<ComponentType> result = child.cast<ComponentType>();
|
||||
if(result != nullptr)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = parent->tryFindComponent<ComponentType>();
|
||||
if(result != nullptr)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void internalSetTransform(Vector newLocation, Quaternion newRotation);
|
||||
void propagateTransformUpdate();
|
||||
void updateComponentTransform(Quaternion relativeRotationQuat);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "MyComponent.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
MyComponent::MyComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void MyComponent::start()
|
||||
{
|
||||
otherComp = getComponent<MyOtherComponent>();
|
||||
otherComp.update();
|
||||
}
|
||||
|
||||
Job MyComponent::tick(float deltatime) const
|
||||
{
|
||||
writable++;
|
||||
otherComp->data = *writable;
|
||||
co_return;
|
||||
}
|
||||
|
||||
Job MyComponent::update()
|
||||
{
|
||||
writable.update();
|
||||
co_return;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "Component.h"
|
||||
#include "MyOtherComponent.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
class MyComponent : public Component
|
||||
{
|
||||
public:
|
||||
MyComponent();
|
||||
virtual void start();
|
||||
virtual Job tick(float deltatime) const;
|
||||
virtual Job update();
|
||||
private:
|
||||
Writable<PMyOtherComponent> otherComp;
|
||||
Writable<uint32> writable = Writable<uint32>(0);
|
||||
uint32 notWritable = 10;
|
||||
};
|
||||
DECLARE_REF(MyComponent);
|
||||
} // namespace Seele
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "MyOtherComponent.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
Job MyOtherComponent::tick(float deltaTime) const
|
||||
{
|
||||
std::cout << *data << std::endl;
|
||||
co_return;
|
||||
}
|
||||
|
||||
Job MyOtherComponent::update()
|
||||
{
|
||||
data.update();
|
||||
co_return;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "Component.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
class MyOtherComponent : public Component
|
||||
{
|
||||
public:
|
||||
virtual Job tick(float deltaTime) const;
|
||||
virtual Job update();
|
||||
Writable<uint32> data = Writable<uint32>(0);
|
||||
private:
|
||||
};
|
||||
DEFINE_REF(MyOtherComponent);
|
||||
} // namespace Seele
|
||||
@@ -26,7 +26,7 @@ PrimitiveComponent::PrimitiveComponent(PMeshAsset asset)
|
||||
batch.useReverseCulling = false;
|
||||
batch.useWireframe = false;
|
||||
batch.vertexInput = assetMeshes[i]->vertexInput;
|
||||
auto& batchElement = batch.elements.add();
|
||||
MeshBatchElement batchElement;
|
||||
batchElement.baseVertexIndex = 0;
|
||||
batchElement.firstIndex = 0;
|
||||
batchElement.indexBuffer = assetMeshes[i]->indexBuffer;
|
||||
@@ -35,6 +35,7 @@ PrimitiveComponent::PrimitiveComponent(PMeshAsset asset)
|
||||
batchElement.isInstanced = false;
|
||||
batchElement.numInstances = 1;
|
||||
batchElement.numPrimitives = assetMeshes[i]->indexBuffer->getNumIndices() / 3; //TODO: hardcoded
|
||||
batch.elements.push_back(batchElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ public:
|
||||
~PrimitiveComponent();
|
||||
virtual void notifySceneAttach(PScene scene) override;
|
||||
Matrix4 getRenderMatrix();
|
||||
const Array<StaticMeshBatch>& getStaticMeshes()
|
||||
std::vector<StaticMeshBatch>& getStaticMeshes()
|
||||
{
|
||||
return staticMeshes;
|
||||
}
|
||||
private:
|
||||
Array<PMaterialAsset> materials;
|
||||
std::vector<PMaterialAsset> materials;
|
||||
Gfx::PUniformBuffer uniformBuffer;
|
||||
Array<StaticMeshBatch> staticMeshes;
|
||||
std::vector<StaticMeshBatch> staticMeshes;
|
||||
friend class Scene;
|
||||
};
|
||||
DEFINE_REF(PrimitiveComponent)
|
||||
|
||||
@@ -33,19 +33,39 @@ Scene::~Scene()
|
||||
{
|
||||
}
|
||||
|
||||
void Scene::tick(double)
|
||||
void Scene::start()
|
||||
{
|
||||
for(auto actor : rootActors)
|
||||
{
|
||||
actor->launchStart();
|
||||
}
|
||||
}
|
||||
|
||||
Job Scene::beginUpdate(double deltaTime)
|
||||
{
|
||||
for(auto actor : rootActors)
|
||||
{
|
||||
co_await Job::all(actor->launchTick(static_cast<float>(deltaTime)));
|
||||
}
|
||||
}
|
||||
|
||||
Job Scene::commitUpdate()
|
||||
{
|
||||
for(auto actor : rootActors)
|
||||
{
|
||||
co_await Job::all(actor->launchUpdate());
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::addActor(PActor actor)
|
||||
{
|
||||
rootActors.add(actor);
|
||||
rootActors.push_back(actor);
|
||||
actor->notifySceneAttach(this);
|
||||
}
|
||||
|
||||
void Scene::addPrimitiveComponent(PPrimitiveComponent comp)
|
||||
{
|
||||
primitives.add(comp);
|
||||
primitives.push_back(comp);
|
||||
for(auto& batch : comp->getStaticMeshes())
|
||||
{
|
||||
PrimitiveUniformBuffer data;
|
||||
@@ -62,6 +82,6 @@ void Scene::addPrimitiveComponent(PPrimitiveComponent comp)
|
||||
{
|
||||
element.uniformBuffer = uniformBuffer;
|
||||
}
|
||||
staticMeshes.add(batch);
|
||||
staticMeshes.push_back(batch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,17 +38,19 @@ class Scene
|
||||
public:
|
||||
Scene(Gfx::PGraphics graphics);
|
||||
~Scene();
|
||||
void tick(double deltaTime);
|
||||
void start();
|
||||
Job beginUpdate(double deltaTime);
|
||||
Job commitUpdate();
|
||||
void addActor(PActor actor);
|
||||
void addPrimitiveComponent(PPrimitiveComponent comp);
|
||||
|
||||
const Array<PPrimitiveComponent>& getPrimitives() const { return primitives; }
|
||||
const Array<StaticMeshBatch>& getStaticMeshes() const { return staticMeshes; }
|
||||
const std::vector<PPrimitiveComponent>& getPrimitives() const { return primitives; }
|
||||
const std::vector<StaticMeshBatch>& getStaticMeshes() const { return staticMeshes; }
|
||||
const LightEnv& getLightBuffer() const { return lightEnv; }
|
||||
private:
|
||||
Array<StaticMeshBatch> staticMeshes;
|
||||
Array<PActor> rootActors;
|
||||
Array<PPrimitiveComponent> primitives;
|
||||
std::vector<StaticMeshBatch> staticMeshes;
|
||||
std::vector<PActor> rootActors;
|
||||
std::vector<PPrimitiveComponent> primitives;
|
||||
LightEnv lightEnv;
|
||||
Gfx::PGraphics graphics;
|
||||
};
|
||||
|
||||
@@ -26,25 +26,25 @@ SceneUpdater::~SceneUpdater()
|
||||
|
||||
void SceneUpdater::registerComponentUpdate(PComponent component)
|
||||
{
|
||||
std::unique_lock lck(pendingUpdatesLock);
|
||||
std::scoped_lock lck(pendingUpdatesLock);
|
||||
updatesRan.add([component](float delta) mutable { component->tick(delta); });
|
||||
}
|
||||
|
||||
void SceneUpdater::registerActorUpdate(PActor actor)
|
||||
{
|
||||
std::unique_lock lck(pendingUpdatesLock);
|
||||
std::scoped_lock lck(pendingUpdatesLock);
|
||||
updatesRan.add([actor](float delta) mutable { actor->tick(delta); });
|
||||
}
|
||||
|
||||
void SceneUpdater::runUpdates(float delta)
|
||||
{
|
||||
|
||||
std::unique_lock pendingLock(pendingUpdatesLock);
|
||||
std::scoped_lock pendingLock(pendingUpdatesLock);
|
||||
frameDelta = delta;
|
||||
pendingUpdates = std::move(updatesRan);
|
||||
updatesRan = List<std::function<void(float)>>();
|
||||
|
||||
std::unique_lock lck(frameFinishedLock);
|
||||
std::scoped_lock lck(frameFinishedLock);
|
||||
pendingLock.unlock();
|
||||
pendingUpdatesSem.release(pendingUpdates.size());
|
||||
frameFinishedCV.wait(lck);
|
||||
@@ -57,18 +57,18 @@ void SceneUpdater::work()
|
||||
pendingUpdatesSem.acquire();
|
||||
std::function<void(float)> function;
|
||||
{
|
||||
std::unique_lock lck(pendingUpdatesLock);
|
||||
std::scoped_lock lck(pendingUpdatesLock);
|
||||
function = std::move(pendingUpdates.front());
|
||||
pendingUpdates.popFront();
|
||||
if(pendingUpdates.empty())
|
||||
{
|
||||
std::unique_lock lck(frameFinishedLock);
|
||||
std::scoped_lock lck(frameFinishedLock);
|
||||
frameFinishedCV.notify_all();
|
||||
}
|
||||
}
|
||||
function(frameDelta);
|
||||
{
|
||||
std::unique_lock lck(pendingUpdatesLock);
|
||||
std::scoped_lock lck(pendingUpdatesLock);
|
||||
updatesRan.add(std::move(function));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
#include "MinimalEngine.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
template<typename T>
|
||||
class Writable
|
||||
{
|
||||
public:
|
||||
Writable()
|
||||
{}
|
||||
explicit Writable(T initialData)
|
||||
: data(initialData)
|
||||
, toBeWritten(initialData)
|
||||
{}
|
||||
Writable(const Writable& other) = delete;
|
||||
Writable(Writable&& other) = default;
|
||||
~Writable() = default;
|
||||
Writable& operator=(const Writable& other) = delete;
|
||||
Writable& operator=(Writable&& other) = default;
|
||||
const Writable& operator=(const T& other) const
|
||||
{
|
||||
deferWrite(other);
|
||||
return *this;
|
||||
}
|
||||
const Writable& operator=(T&& other) const
|
||||
{
|
||||
deferWrite(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator+(Other&& other) const
|
||||
{
|
||||
deferWrite(data + std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator-(Other&& other) const
|
||||
{
|
||||
deferWrite(data - std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator*(Other&& other) const
|
||||
{
|
||||
deferWrite(data * std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator/(Other&& other) const
|
||||
{
|
||||
deferWrite(data / std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator%(Other&& other) const
|
||||
{
|
||||
deferWrite(data % std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator^(Other&& other) const
|
||||
{
|
||||
deferWrite(data ^ std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator&(Other&& other) const
|
||||
{
|
||||
deferWrite(data & std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Other>
|
||||
const Writable& operator|(Other&& other) const
|
||||
{
|
||||
deferWrite(data | std::forward<Other>(other));
|
||||
return *this;
|
||||
}
|
||||
template<typename Type>
|
||||
bool operator==(Type other) const
|
||||
{
|
||||
return data == other.data;
|
||||
}
|
||||
template<typename Type>
|
||||
bool operator<=>(Type other) const
|
||||
{
|
||||
return data <=> other.data;
|
||||
}
|
||||
const Writable& operator++() const
|
||||
{
|
||||
deferWrite(data+1);
|
||||
return *this;
|
||||
}
|
||||
const Writable& operator--() const
|
||||
{
|
||||
deferWrite(data-1);
|
||||
return *this;
|
||||
}
|
||||
Writable&& operator++(int) const
|
||||
{
|
||||
Writable tmp(data);
|
||||
++*this;
|
||||
return std::move(tmp);
|
||||
}
|
||||
Writable&& operator--(int) const
|
||||
{
|
||||
Writable tmp(data);
|
||||
--*this;
|
||||
return std::move(tmp);
|
||||
}
|
||||
const T& operator*() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
const T& get() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
const T& operator->() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
void update()
|
||||
{
|
||||
// lock should not be necessary, but lets keep it for now
|
||||
std::scoped_lock lock(dataLock);
|
||||
data = toBeWritten;
|
||||
dirty = false;
|
||||
}
|
||||
private:
|
||||
template<typename Type>
|
||||
void deferWrite(Type&& newValue) const
|
||||
{
|
||||
std::scoped_lock lock(dataLock);
|
||||
assert(!dirty);
|
||||
toBeWritten = std::forward<Type>(newValue);
|
||||
dirty = true;
|
||||
}
|
||||
mutable bool dirty = false;
|
||||
mutable std::mutex dataLock;
|
||||
mutable T toBeWritten;
|
||||
T data;
|
||||
};
|
||||
template<typename A>
|
||||
concept writable = requires(A&& a)
|
||||
{
|
||||
a.update();
|
||||
};
|
||||
} // namespace Seele
|
||||
Reference in New Issue
Block a user