Started upgrading things to new state

This commit is contained in:
2023-02-27 23:36:03 -08:00
parent fc34ae94ff
commit 8e04742d5a
19 changed files with 456 additions and 495 deletions

View File

@ -138,7 +138,7 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) {
switch(canvas->drawType) { switch(canvas->drawType) {
case UI_DRAW_TYPE_WORLD_ABSOLUTE: case UI_DRAW_TYPE_WORLD_ABSOLUTE:
projection = camera->projection; projection = camera->getProjection();
view = camera->transform->getWorldTransform(); view = camera->transform->getWorldTransform();
model = canvas->transform->getWorldTransform(); model = canvas->transform->getWorldTransform();
break; break;

View File

@ -9,57 +9,54 @@
using namespace Dawn; using namespace Dawn;
Camera::Camera(SceneItem *item) : Camera::Camera(SceneItem *item) :
SceneItemComponent(item) SceneItemComponent(item),
renderTarget(nullptr),
fov(0.785398f),// 45 degrees,
type(CAMERA_TYPE_PERSPECTIVE),
orthoLeft(0.0f),
orthoRight(1.0f),
orthoBottom(0.0f),
orthoTop(1.0f),
clipNear(0.001f),
clipFar(50.0f)
{ {
this->getRenderTarget()->eventRenderTargetResized.addListener(
this, &Camera::onRenderTargetResize
);
} }
void Camera::updateProjection() { glm::mat4 Camera::getProjection() {
switch(this->type) { if(this->projectionNeedsUpdating) {
case CAMERA_TYPE_ORTHONOGRAPHIC: switch(this->type) {
this->projection = glm::ortho( case CAMERA_TYPE_ORTHONOGRAPHIC:
this->orthoLeft, this->projection = glm::ortho(
this->orthoRight, (float_t)this->orthoLeft,
this->orthoBottom, (float_t)this->orthoRight,
this->orthoTop, (float_t)this->orthoBottom,
this->clipNear, (float_t)this->orthoTop,
this->clipFar (float_t)this->clipNear,
); (float_t)this->clipFar
break; );
break;
case CAMERA_TYPE_PERSPECTIVE: case CAMERA_TYPE_PERSPECTIVE:
this->projection = glm::perspective( this->projection = glm::perspective(
this->fov, (float_t)this->fov,
this->getAspect(), this->getAspect(),
this->clipNear, (float_t)this->clipNear,
this->clipFar (float_t)this->clipFar
); );
break; break;
}
this->projectionNeedsUpdating = false;
} }
return this->projection;
} }
RenderTarget * Camera::getRenderTarget() { RenderTarget * Camera::getRenderTarget() {
if(this->target == nullptr) { auto v = this->renderTarget;
if(this->renderTarget == nullptr) {
return this->getGame()->renderManager.getBackBuffer(); return this->getGame()->renderManager.getBackBuffer();
} }
return this->target; return (RenderTarget*)this->renderTarget;
}
void Camera::setRenderTarget(RenderTarget *renderTarget) {
if(renderTarget == this->target) return;
this->getRenderTarget()->eventRenderTargetResized.removeListener(
this, &Camera::onRenderTargetResize
);
this->target = renderTarget;
this->getRenderTarget()->eventRenderTargetResized.addListener(
this, &Camera::onRenderTargetResize
);
this->updateProjection();
this->eventRenderTargetResized.invoke(
renderTarget->getWidth(), renderTarget->getHeight()
);
} }
float_t Camera::getAspect() { float_t Camera::getAspect() {
@ -80,12 +77,46 @@ glm::vec3 Camera::getRayDirectionFromScreenSpace(glm::vec2 screenSpace) {
} }
void Camera::onStart() { void Camera::onStart() {
this->updateProjection(); // Render Target
useEffect(renderTarget, [&]{
if(renderTarget.previous != nullptr) {
renderTarget.previous->eventRenderTargetResized.removeListener(
this, &Camera::onRenderTargetResize
);
}
this->projectionNeedsUpdating = true;
auto rt = this->getRenderTarget();
rt->eventRenderTargetResized.addListener(
this, &Camera::onRenderTargetResize
);
this->eventRenderTargetResized.invoke(
rt->getWidth(), rt->getHeight()
);
this->event2RenderTargetResized.invoke(rt->getWidth(), rt->getHeight());
});
// All regular properties.
auto cbUpdateProj = [&]{
this->projectionNeedsUpdating = true;
};
useEffect(fov, cbUpdateProj);
useEffect(type, cbUpdateProj);
useEffect(orthoLeft, cbUpdateProj);
useEffect(orthoRight, cbUpdateProj);
useEffect(orthoBottom, cbUpdateProj);
useEffect(orthoTop, cbUpdateProj);
useEffect(clipNear, cbUpdateProj);
useEffect(clipFar, cbUpdateProj);
getRenderTarget()->eventRenderTargetResized.addListener(this, &Camera::onRenderTargetResize);
} }
void Camera::onRenderTargetResize(RenderTarget *target, float_t w, float_t h) { void Camera::onRenderTargetResize(RenderTarget *target, float_t w, float_t h) {
this->updateProjection(); this->projectionNeedsUpdating = true;
this->eventRenderTargetResized.invoke(w, h); this->eventRenderTargetResized.invoke(w, h);
this->event2RenderTargetResized.invoke(w, h);
} }
void Camera::onDispose() { void Camera::onDispose() {

View File

@ -17,34 +17,32 @@ namespace Dawn {
class Camera : public SceneItemComponent { class Camera : public SceneItemComponent {
protected: protected:
RenderTarget *target = nullptr; bool_t projectionNeedsUpdating = true;
glm::mat4 projection;
void onRenderTargetResize(RenderTarget *target, float_t w, float_t h); void onRenderTargetResize(RenderTarget *target, float_t w, float_t h);
public: public:
Event<float_t, float_t> eventRenderTargetResized;
static Camera * create(Scene *scene) { static Camera * create(Scene *scene) {
auto item = scene->createSceneItem(); auto item = scene->createSceneItem();
auto cam = item->addComponent<Camera>(); auto cam = item->addComponent<Camera>();
return cam; return cam;
} }
glm::mat4 projection; StateProperty<RenderTarget*> renderTarget;
StateProperty<float_t> fov;
StateProperty<enum CameraType> type;
// Perspective StateProperty<float_t> orthoLeft;
enum CameraType type = CAMERA_TYPE_PERSPECTIVE; StateProperty<float_t> orthoRight;
float_t fov = 0.785398f;// 45 degrees StateProperty<float_t> orthoBottom;
StateProperty<float_t> orthoTop;
// Ortho StateProperty<float_t> clipNear;
float_t orthoLeft = 0.0f; StateProperty<float_t> clipFar;
float_t orthoRight = 1.0f;
float_t orthoBottom = 0.0f;
float_t orthoTop = 1.0f;
// Shared Event<float_t, float_t> eventRenderTargetResized;
float_t clipNear = 0.001f; StateEvent<float_t, float_t> event2RenderTargetResized;
float_t clipFar = 50.0f;
/** /**
* Create a new Camera Component. * Create a new Camera Component.
@ -54,9 +52,11 @@ namespace Dawn {
Camera(SceneItem *item); Camera(SceneItem *item);
/** /**
* Updates the projection matrix. * Returns the current projection matrix.
*
* @return Projection matrix for this camera.
*/ */
void updateProjection(); glm::mat4 getProjection();
/** /**
* Returns the intended render target for this camera to render to, will * Returns the intended render target for this camera to render to, will
@ -66,13 +66,6 @@ namespace Dawn {
*/ */
RenderTarget * getRenderTarget(); RenderTarget * getRenderTarget();
/**
* Updates the render target for the camera to use.
*
* @param renderTarget Render target for this camera to draw to.
*/
void setRenderTarget(RenderTarget *renderTarget);
/** /**
* Returs the aspect ratio of the camera. * Returs the aspect ratio of the camera.
* *

View File

@ -1,68 +1,65 @@
// Copyright (c) 2023 Dominic Masters // Copyright (c) 2023 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#include "PixelPerfectCamera.hpp" #include "PixelPerfectCamera.hpp"
#include "game/DawnGame.hpp" #include "game/DawnGame.hpp"
using namespace Dawn; using namespace Dawn;
PixelPerfectCamera::PixelPerfectCamera(SceneItem *i) : SceneItemComponent(i) { PixelPerfectCamera::PixelPerfectCamera(SceneItem *i) :
SceneItemComponent(i),
} scale(1.0f)
{
std::vector<SceneItemComponent*> PixelPerfectCamera::getDependencies() {
return std::vector<SceneItemComponent*>{ }
(this->camera = this->item->getComponent<Camera>())
}; std::vector<SceneItemComponent*> PixelPerfectCamera::getDependencies() {
} return std::vector<SceneItemComponent*>{
(this->camera = this->item->getComponent<Camera>())
void PixelPerfectCamera::onRenderTargetResized(float_t w, float_t h) { };
this->updateDimensions(); }
}
void PixelPerfectCamera::updateDimensions() {
void PixelPerfectCamera::updateDimensions() { float_t w, h;
float_t w, h; assertNotNull(this->camera);
assertNotNull(this->camera);
auto target = this->camera->getRenderTarget();
auto target = this->camera->getRenderTarget(); switch(this->camera->type) {
switch(this->camera->type) { case CAMERA_TYPE_ORTHONOGRAPHIC:
case CAMERA_TYPE_ORTHONOGRAPHIC: w = target->getWidth() / 2.0f / (float_t)this->scale;
w = target->getWidth() / 2.0f / this->scale; h = target->getHeight() / 2.0f / (float_t)this->scale;
h = target->getHeight() / 2.0f / this->scale; camera->orthoLeft = -w;
camera->orthoLeft = -w; camera->orthoRight = w;
camera->orthoRight = w; camera->orthoTop = h;
camera->orthoTop = h; camera->orthoBottom = -h;
camera->orthoBottom = -h; break;
camera->updateProjection();
break; case CAMERA_TYPE_PERSPECTIVE:
this->transform->lookAtPixelPerfect(
case CAMERA_TYPE_PERSPECTIVE: glm::vec3(0, 0, 0),
this->transform->lookAtPixelPerfect( glm::vec3(0, 0, 0),
glm::vec3(0, 0, 0), target->getHeight() / this->scale,
glm::vec3(0, 0, 0), this->camera->fov
target->getHeight() / this->scale, );
this->camera->fov // this->transform->lookAt(glm::vec3(360, 360, 360), glm::vec3(0, 0, 0));
); break;
// this->transform->lookAt(glm::vec3(360, 360, 360), glm::vec3(0, 0, 0));
break; default:
assertUnreachable();
default: }
assertUnreachable(); }
}
} void PixelPerfectCamera::onStart() {
assertNotNull(this->camera);
void PixelPerfectCamera::onStart() { this->updateDimensions();
assertNotNull(this->camera);
this->updateDimensions(); useEvent(this->camera->event2RenderTargetResized, [&](float_t w, float_t h){
camera->eventRenderTargetResized.addListener( this->updateDimensions();
this, &PixelPerfectCamera::onRenderTargetResized });
);
} useEffect(scale, [&]{
this->updateDimensions();
void PixelPerfectCamera::onDispose() { });
camera->eventRenderTargetResized.removeListener(
this, &PixelPerfectCamera::onRenderTargetResized
);
} }

View File

@ -1,35 +1,32 @@
// Copyright (c) 2023 Dominic Masters // Copyright (c) 2023 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "Camera.hpp" #include "Camera.hpp"
namespace Dawn { namespace Dawn {
class PixelPerfectCamera : public SceneItemComponent { class PixelPerfectCamera : public SceneItemComponent {
protected: protected:
Camera *camera = nullptr; Camera *camera = nullptr;
/** Event for when the render target is resized. */
void onRenderTargetResized(float_t w, float_t h); /**
* Updates the underlying camera's projection information.
/** */
* Updates the underlying camera's projection information. void updateDimensions();
*/
void updateDimensions(); public:
StateProperty<float_t> scale;
public:
float_t scale = 1.0f; /**
* Create a new PixelPerfectCamera Component.
/** *
* Create a new PixelPerfectCamera Component. * @param item Item that this component belongs to.
* */
* @param item Item that this component belongs to. PixelPerfectCamera(SceneItem *item);
*/
PixelPerfectCamera(SceneItem *item); std::vector<SceneItemComponent*> getDependencies() override;
void onStart() override;
std::vector<SceneItemComponent*> getDependencies() override; };
void onStart() override;
void onDispose() override;
};
} }

View File

@ -8,7 +8,8 @@
using namespace Dawn; using namespace Dawn;
SimpleRenderTargetQuad::SimpleRenderTargetQuad(SceneItem *i) : SimpleRenderTargetQuad::SimpleRenderTargetQuad(SceneItem *i) :
SceneItemComponent(i) SceneItemComponent(i),
renderTarget(nullptr)
{ {
} }
@ -16,36 +17,19 @@ void SimpleRenderTargetQuad::onRenderTargetResized(
RenderTarget *target, float_t w, float_t h RenderTarget *target, float_t w, float_t h
) { ) {
assertTrue(target == this->renderTarget); assertTrue(target == this->renderTarget);
// Update mesh
QuadMesh::bufferQuadMesh( QuadMesh::bufferQuadMesh(
&this->meshHost->mesh, &this->meshHost->mesh,
glm::vec2(0, 0), glm::vec2(0, 0), glm::vec2(0, 0), glm::vec2(0, 0),
glm::vec2(w, h), glm::vec2(1, 1), glm::vec2(
((RenderTarget*)this->renderTarget)->getWidth(),
((RenderTarget*)this->renderTarget)->getHeight()
),
glm::vec2(1, 1),
0, 0 0, 0
); );
} }
void SimpleRenderTargetQuad::setRenderTarget(RenderTarget *rt) {
assertTrue(rt != this->renderTarget);
// Remove old event listener
if(this->renderTarget != nullptr) {
this->renderTarget->eventRenderTargetResized.removeListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized
);
}
this->renderTarget = rt;
// Add new event listener.
if(rt != nullptr) {
rt->eventRenderTargetResized.addListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized
);
}
}
std::vector<SceneItemComponent*> SimpleRenderTargetQuad::getDependencies() { std::vector<SceneItemComponent*> SimpleRenderTargetQuad::getDependencies() {
return std::vector<SceneItemComponent*>{ return std::vector<SceneItemComponent*>{
(this->meshHost = this->item->getComponent<MeshHost>()) (this->meshHost = this->item->getComponent<MeshHost>())
@ -57,15 +41,43 @@ void SimpleRenderTargetQuad::onStart() {
// Create quad mesh // Create quad mesh
this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT); this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
useEffect(this->renderTarget, [&]{
if(this->renderTarget.previous != nullptr) {
this->renderTarget.previous->eventRenderTargetResized.addListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized
);
}
if(this->renderTarget == nullptr) return;
// Update mesh
QuadMesh::bufferQuadMesh(
&this->meshHost->mesh,
glm::vec2(0, 0), glm::vec2(0, 0),
glm::vec2(
((RenderTarget*)this->renderTarget)->getWidth(),
((RenderTarget*)this->renderTarget)->getHeight()
),
glm::vec2(1, 1),
0, 0
);
((RenderTarget*)this->renderTarget)->eventRenderTargetResized.addListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized
);
});
// Perform first resize. // Perform first resize.
if(this->renderTarget != nullptr) { if(this->renderTarget != nullptr) {
QuadMesh::bufferQuadMesh( QuadMesh::bufferQuadMesh(
&this->meshHost->mesh, &this->meshHost->mesh,
glm::vec2(0, 0), glm::vec2(0, 0), glm::vec2(0, 0),
glm::vec2(0, 0), glm::vec2(
glm::vec2(this->renderTarget->getWidth(), this->renderTarget->getHeight()), ((RenderTarget*)this->renderTarget)->getWidth(),
glm::vec2(1,1), ((RenderTarget*)this->renderTarget)->getHeight()
),
glm::vec2(1, 1),
0, 0 0, 0
); );
} }
@ -73,7 +85,7 @@ void SimpleRenderTargetQuad::onStart() {
void SimpleRenderTargetQuad::onDispose() { void SimpleRenderTargetQuad::onDispose() {
if(this->renderTarget != nullptr) { if(this->renderTarget != nullptr) {
this->renderTarget->eventRenderTargetResized.removeListener( ((RenderTarget*)this->renderTarget)->eventRenderTargetResized.removeListener(
this, &SimpleRenderTargetQuad::onRenderTargetResized this, &SimpleRenderTargetQuad::onRenderTargetResized
); );
} }

View File

@ -1,41 +1,34 @@
// Copyright (c) 2023 Dominic Masters // Copyright (c) 2023 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "scene/components/display/MeshHost.hpp" #include "scene/components/display/MeshHost.hpp"
#include "display/RenderTarget.hpp" #include "display/RenderTarget.hpp"
#include "display/mesh/QuadMesh.hpp" #include "display/mesh/QuadMesh.hpp"
namespace Dawn { namespace Dawn {
class SimpleRenderTargetQuad : public SceneItemComponent { class SimpleRenderTargetQuad : public SceneItemComponent {
protected: protected:
MeshHost *meshHost = nullptr; MeshHost *meshHost = nullptr;
RenderTarget *renderTarget = nullptr;
void onRenderTargetResized(RenderTarget *target, float_t w, float_t h);
void onRenderTargetResized(RenderTarget *target, float_t w, float_t h);
public:
public: StateProperty<RenderTarget*> renderTarget;
/**
* Creates a SimpleRenderTargetQuad scene item component. This component /**
* will update the attached MeshHost any time the render target provided * Creates a SimpleRenderTargetQuad scene item component. This component
* is updated / resized. * will update the attached MeshHost any time the render target provided
* * is updated / resized.
* @param item Item that this component is attached to. *
*/ * @param item Item that this component is attached to.
SimpleRenderTargetQuad(SceneItem *item); */
SimpleRenderTargetQuad(SceneItem *item);
/**
* Sets the render target to use for this quad. Can be set to nullptr when std::vector<SceneItemComponent*> getDependencies() override;
* you no longer wish to listen for resize events. void onStart() override;
* void onDispose() override;
* @param rt Render target to attach to. };
*/
void setRenderTarget(RenderTarget *rt);
std::vector<SceneItemComponent*> getDependencies() override;
void onStart() override;
void onDispose() override;
};
} }

View File

@ -1,88 +1,88 @@
// Copyright (c) 2022 Dominic Masters // Copyright (c) 2022 Dominic Masters
// //
// This software is released under the MIT License. // This software is released under the MIT License.
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "scene/SceneItemComponent.hpp" #include "scene/SceneItemComponent.hpp"
#include "scene/components/display/MeshRenderer.hpp" #include "scene/components/display/MeshRenderer.hpp"
#include "scene/components/display/MeshHost.hpp" #include "scene/components/display/MeshHost.hpp"
#include "display/mesh/QuadMesh.hpp" #include "display/mesh/QuadMesh.hpp"
#include "display/Tileset.hpp" #include "display/Tileset.hpp"
#define TILED_SPRITE_FLIP_Y FLAG_DEFINE(0) #define TILED_SPRITE_FLIP_Y FLAG_DEFINE(0)
#define TILED_SPRITE_FLIP_X FLAG_DEFINE(1) #define TILED_SPRITE_FLIP_X FLAG_DEFINE(1)
namespace Dawn { namespace Dawn {
class TiledSprite : public SceneItemComponent { class TiledSprite : public SceneItemComponent {
protected: protected:
MeshHost *host = nullptr; MeshHost *host = nullptr;
Tileset *tileset = nullptr; Tileset *tileset = nullptr;
flag_t flipState = TILED_SPRITE_FLIP_Y; flag_t flipState = TILED_SPRITE_FLIP_Y;
int32_t tileIndex = -1; int32_t tileIndex = -1;
glm::vec2 xy0 = glm::vec2(0, 0); glm::vec2 xy0 = glm::vec2(0, 0);
glm::vec2 xy1 = glm::vec2(1, 1); glm::vec2 xy1 = glm::vec2(1, 1);
glm::vec2 getUV0(); glm::vec2 getUV0();
glm::vec2 getUV1(); glm::vec2 getUV1();
public: public:
TiledSprite(SceneItem *item); TiledSprite(SceneItem *item);
std::vector<SceneItemComponent*> getDependencies() override; std::vector<SceneItemComponent*> getDependencies() override;
void onStart() override; void onStart() override;
/** /**
* Sets which tileset to use for this sprite. * Sets which tileset to use for this sprite.
* *
* @param tileset Tileset to use. * @param tileset Tileset to use.
*/ */
void setTileset(Tileset *tileset); void setTileset(Tileset *tileset);
/** /**
* Sets the tileset for the sprite, and autosizes the sprite based on * Sets the tileset for the sprite, and autosizes the sprite based on
* this tileset. * this tileset.
* *
* @param gridTileset Tileset to use. * @param gridTileset Tileset to use.
* @param center The center offset of the sprite. * @param center The center offset of the sprite.
*/ */
void setTilesetAndSize(TilesetGrid *gridTileset, glm::vec2 center); void setTilesetAndSize(TilesetGrid *gridTileset, glm::vec2 center);
/** /**
* Sets the tileset for the sprite, and autosizes the sprite based on * Sets the tileset for the sprite, and autosizes the sprite based on
* this tileset. This will put the sprite centered on its origin. * this tileset. This will put the sprite centered on its origin.
* *
* @param gridTileset Tileset to use. * @param gridTileset Tileset to use.
*/ */
void setTilesetAndSize(TilesetGrid *gridTileset); void setTilesetAndSize(TilesetGrid *gridTileset);
/** /**
* Updates the selected tile. * Updates the selected tile.
* *
* @param tile Tile to use. * @param tile Tile to use.
*/ */
void setTile(int32_t tile); void setTile(int32_t tile);
/** /**
* Adjust how the sprite is flippxed. * Adjust how the sprite is flippxed.
* *
* @param flippedState Flipped axis flags. * @param flippedState Flipped axis flags.
*/ */
void setFlippedState(flag_t flippedState); void setFlippedState(flag_t flippedState);
/** /**
* Sets the dimensions of this tiled sprite. * Sets the dimensions of this tiled sprite.
* *
* @param size Size of the sprite. * @param size Size of the sprite.
* @param center Negative center offset. * @param center Negative center offset.
*/ */
void setSize(glm::vec2 size, glm::vec2 center); void setSize(glm::vec2 size, glm::vec2 center);
/** /**
* Sets the size of this sprite. This will center the sprite on its origin * Sets the size of this sprite. This will center the sprite on its origin
* *
* @param size Size of the sprite. * @param size Size of the sprite.
*/ */
void setSize(glm::vec2 size); void setSize(glm::vec2 size);
}; };
} }

View File

@ -25,7 +25,7 @@ struct ShaderPassItem SceneDebugLine::createShaderItem(
item.colorValues[shader->program.paramColor] = this->color; item.colorValues[shader->program.paramColor] = this->color;
item.matrixValues[shader->program.paramModel] = this->transform; item.matrixValues[shader->program.paramModel] = this->transform;
item.matrixValues[shader->program.paramView] = camera->transform->getWorldTransform(); item.matrixValues[shader->program.paramView] = camera->transform->getWorldTransform();
item.matrixValues[shader->program.paramProjection] = camera->projection; item.matrixValues[shader->program.paramProjection] = camera->getProjection();
item.boolValues[shader->program.paramHasTexture] = false; item.boolValues[shader->program.paramHasTexture] = false;
auto i = *lineIndex; auto i = *lineIndex;

View File

@ -4,8 +4,3 @@
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Sources # Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
StateOwner.cpp
StateProperty.cpp
)

View File

@ -4,7 +4,53 @@
// https://opensource.org/licenses/MIT // https://opensource.org/licenses/MIT
#pragma once #pragma once
#include "StateEvent.hpp" #include "StateEvent.hpp"
#include "StateOwner.hpp" #include "StateProperty.hpp"
#include "StateProperty.hpp"
namespace Dawn {
class StateOwner {
private:
std::vector<IStateEvent*> eventsSubscribed;
public:
/**
* Listen for changees to a state property and involke the provided func
* when the value is changed.
*
* @tparam V The type of the state property.
* @param property Property to listen for affect changees to.
* @param fn The callback to be invoked when the state value changes.
*/
template<class V>
void useEffect(
StateProperty<V> &property,
const std::function<void()> &fn
) {
property._effectListners.push_back(fn);
}
/**
* Listen for when an event is invoked by a state event. This is intended
* to allow for cross-state-owner communication in a simple and effective
* way.
*
* @tparam F The type of the callback function.
* @tparam A The arguments from the state event that are calledback.
* @param event The event that is being subscribed to.
* @param fn The function to be inokved on event trigger.
*/
template<typename F, typename... A>
void useEvent(StateEvent<A...> &event, F fn) {
event._eventListeners[this].push_back(fn);
this->eventsSubscribed.push_back(&event);
}
~StateOwner() {
auto it = this->eventsSubscribed.begin();
while(it != this->eventsSubscribed.end()) {
(*it)->_stateOwnerDestroyed(this);
++it;
}
}
};
}

View File

@ -9,25 +9,38 @@
namespace Dawn { namespace Dawn {
class StateOwner; class StateOwner;
class IStateEvent {
protected:
virtual void _stateOwnerDestroyed(StateOwner *owner) = 0;
friend class StateOwner;
};
template<typename...A> template<typename...A>
class StateEvent { class StateEvent : public IStateEvent {
private: protected:
std::vector<std::function<void(A...)>> listeners; void _stateOwnerDestroyed(StateOwner *owner) override {
this->_eventListeners.erase(owner);
}
public: public:
std::map<StateOwner*, std::vector<std::function<void(A...)>>> _eventListeners;
/** /**
* Invokes the event and emits to all of the listeners. * Invokes the event and emits to all of the listeners.
* *
* @param args Arguments for this event to pass to the listeners. * @param args Arguments for this event to pass to the listeners.
*/ */
void invoke(A... args) { void invoke(A... args) {
auto itListeners = this->listeners.begin(); auto itListeners = this->_eventListeners.begin();
while(itListeners != this->listeners.end()) { while(itListeners != this->_eventListeners.end()) {
(*itListeners)(args...); auto itLists = itListeners->second.begin();
while(itLists != itListeners->second.end()) {
(*itLists)(args...);
++itLists;
}
++itListeners; ++itListeners;
} }
} }
friend class StateOwner;
}; };
} }

View File

@ -1,8 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "State.hpp"
using namespace Dawn;

View File

@ -1,114 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "StateEvent.hpp"
namespace Dawn {
template<class V>
class StateProperty;
class StateOwner {
private:
std::map<void*, std::vector<std::function<void()>>> effectListeners;
std::vector<std::function<void()>> stateUpdateListeners;
public:
/**
* Creates a new state property and listens for its change.
*
* @tparam V The type of the state that is held.
* @param initial The initial value of this state.
* @return The state that can then be listened for.
*/
template<class V>
StateProperty<V> useState(V initial) {
auto property = StateProperty<V>();
property.value = initial;
property.owner = this;
return property;
}
/**
* Listen for changees to a state property and involke the provided func
* when the value is changed.
*
* @tparam V The type of the state property.
* @param property Property to listen for affect changees to.
* @param fn The callback to be invoked when the state value changes.
*/
template<class V>
void useEffect(StateProperty<V> &property, const std::function<void()> &fn) {
assertFalse(property.owner == this);
this->effectListeners[(void*)&property].push_back(fn);
}
/**
* Listen for changes to any single state property managed by this state
* owner.
*
* @param fn Function to be invoked when any state property is updated.
*/
void useStateUpdated(const std::function<void()> &fn) {
this->stateUpdateListeners.push_back(fn);
}
/**
* Listen for when an event is invoked by a state event. This is intended
* to allow for cross-state-owner communication in a simple and effective
* way.
*
* @tparam A The arguments from the state event that are calledback.
* @param event The event that is being subscribed to.
* @param fn The function to be inokved on event trigger.
*/
template<typename...A>
void useEvent(StateEvent<A...> &event, const std::function<void(A...)> &fn) {
event.listeners.push_back(fn);
}
/**
* Internal method (that has to be exposed) to listen for changes for when
* a state property that belongs to this state owner is updated.
*
* @tparam V The value type of the state property.
* @param prop The property that has its value changed in question.
* @param n The new, current value of the property.
* @param o The old, previous value of the property.
*/
template<class V>
void _statePropertyUpdated(StateProperty<V> *prop, V n, V o) {
auto eff = &this->effectListeners[prop];
auto itEff = eff->begin();
while(itEff != eff->end()) {
(*itEff)();
++itEff;
}
auto itUpdate = this->stateUpdateListeners.begin();
while(itUpdate != this->stateUpdateListeners.end()) {
(*itUpdate)();
++itUpdate;
}
}
/**
* Internal method to listen for when a state property is disposed or
* destroyed so that it can be completely removed from this state owner.
*
* @tparam V Value type.
* @param prop Property that was destroyed.
*/
template<class V>
void _statePropertyDestroyed(StateProperty<V> *prop) {
this->effectListeners.erase((void*)prop);
}
virtual ~StateOwner() {
}
};
}

View File

@ -1,8 +0,0 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "State.hpp"
using namespace Dawn;

View File

@ -7,14 +7,9 @@
#include "assert/assert.hpp" #include "assert/assert.hpp"
namespace Dawn { namespace Dawn {
class StateOwner;
template<class V> template<class V>
class StateProperty { class StateProperty {
private: private:
StateOwner *owner;
V value;
/** /**
* Method that is invoked every time that the value of this state property * Method that is invoked every time that the value of this state property
* is updated. * is updated.
@ -22,25 +17,45 @@ namespace Dawn {
* @param val Value that is to be used for this property. * @param val Value that is to be used for this property.
*/ */
void setInternal(V val) { void setInternal(V val) {
if(val == this->value) return;// TODO: can I omit this? kinda bad tbh. if(val == this->_realValue) return;// TODO: can I omit this? kinda bad tbh.
assertNotNull(this->owner); this->previous = this->_realValue;
auto old = this->value; this->_realValue = val;
this->value = val;
this->owner->_statePropertyUpdated(this, val, old); // Notify the effect listeners
auto itEffect = this->_effectListners.begin();
while(itEffect != this->_effectListners.end()) {
(*itEffect)();
++itEffect;
}
} }
public: public:
V _realValue;
std::vector<std::function<void()>> _effectListners;
V previous;
/**
* Creates a new state property and listens for its change.
*/
StateProperty() {}
/**
* Creates a new state property and listens for its change.
* @param initial The initial value of this state.
*/
StateProperty(V initial) : _realValue(initial) {}
const StateProperty& operator += (const V &value) { const StateProperty& operator += (const V &value) {
this->setInternal(this->value + value); this->setInternal(this->_realValue + value);
return *this; return *this;
} }
const bool_t operator != (const V &value) { const bool_t operator != (const V &value) {
return value != this->value; return value != this->_realValue;
} }
const bool_t operator == (const V &value) { const bool_t operator == (const V &value) {
return value == this->value; return value == this->_realValue;
} }
const StateProperty& operator = (const V &val) { const StateProperty& operator = (const V &val) {
@ -49,15 +64,13 @@ namespace Dawn {
} }
operator V() const { operator V() const {
return this->value; return this->_realValue;
} }
/** /**
* Destructor for StateProperty. * Destructor for StateProperty.
*/ */
~StateProperty() { ~StateProperty() {}
this->owner->_statePropertyDestroyed(this);
}
friend class StateOwner; friend class StateOwner;
}; };

View File

@ -27,7 +27,7 @@ std::vector<struct ShaderPassItem> SimpleTexturedShader::getPassItems(
onlyPass.colorValues[program.paramColor] = simpleMaterial->color; onlyPass.colorValues[program.paramColor] = simpleMaterial->color;
onlyPass.matrixValues[program.paramModel] = material->transform->getWorldTransform(); onlyPass.matrixValues[program.paramModel] = material->transform->getWorldTransform();
onlyPass.matrixValues[program.paramView] = camera->transform->getWorldTransform(); onlyPass.matrixValues[program.paramView] = camera->transform->getWorldTransform();
onlyPass.matrixValues[program.paramProjection] = camera->projection; onlyPass.matrixValues[program.paramProjection] = camera->getProjection();
onlyPass.renderFlags = ( onlyPass.renderFlags = (
RENDER_MANAGER_RENDER_FLAG_BLEND | RENDER_MANAGER_RENDER_FLAG_BLEND |
RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST

View File

@ -8,13 +8,14 @@
using namespace Dawn; using namespace Dawn;
TicTacToeTile::TicTacToeTile(SceneItem *item) : SceneItemComponent(item) { TicTacToeTile::TicTacToeTile(SceneItem *item) :
SceneItemComponent(item),
tileState(TIC_TAC_TOE_EMPTY),
hovered(false)
{
} }
void TicTacToeTile::onStart() { void TicTacToeTile::onStart() {
tileState = useState(TIC_TAC_TOE_EMPTY);
hovered = useState(false);
auto cb = [&]{ auto cb = [&]{
auto sprite = this->item->getComponent<TiledSprite>(); auto sprite = this->item->getComponent<TiledSprite>();
if(this->hovered) { if(this->hovered) {

View File

@ -14,7 +14,7 @@
namespace Dawn { namespace Dawn {
class TicTacToeScene : public Scene, public StateOwner { class TicTacToeScene : public Scene {
protected: protected:
Camera *camera; Camera *camera;