Totally refactored UILabel
This commit is contained in:
2
lib/SDL
2
lib/SDL
Submodule lib/SDL updated: c9aec268fa...87a83787a3
Submodule lib/openal-soft updated: fde74453a6...d66107e9f0
@ -132,7 +132,6 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) {
|
||||
auto itCanvas = canvases.begin();
|
||||
while(itCanvas != canvases.end()) {
|
||||
auto canvas = *itCanvas;
|
||||
glm::mat4 model;
|
||||
glm::mat4 projection;
|
||||
glm::mat4 view;
|
||||
|
||||
@ -140,32 +139,23 @@ void RenderPipeline::renderSceneCamera(Scene *scene, Camera *camera) {
|
||||
case UI_DRAW_TYPE_WORLD_ABSOLUTE:
|
||||
projection = camera->getProjection();
|
||||
view = camera->transform->getWorldTransform();
|
||||
model = canvas->transform->getWorldTransform();
|
||||
break;
|
||||
|
||||
case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE:
|
||||
projection = glm::ortho(0.0f, renderTarget->getWidth(), renderTarget->getHeight(), 0.0f);
|
||||
view = glm::mat4(1.0f);
|
||||
model = canvas->transform->getWorldTransform();
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable();
|
||||
}
|
||||
|
||||
auto renderables = canvas->item->findChildrenDeep<UIComponentRendaerable>();
|
||||
auto renderables = canvas->item->findChildrenDeep<UIComponentRenderable>();
|
||||
auto itChild = renderables.begin();
|
||||
while(itChild != renderables.end()) {
|
||||
vectorAppend(&shaderPassItems,(*itChild)->getPassItems(projection, view));
|
||||
++itChild;
|
||||
}
|
||||
|
||||
// auto itChild = canvas->children.begin();
|
||||
// while(itChild != canvas->children.end()) {
|
||||
// vectorAppend(&shaderPassItems, (*itChild)->getPassItems(
|
||||
// projection, view, model
|
||||
// ));
|
||||
// ++itChild;
|
||||
// }
|
||||
++itCanvas;
|
||||
}
|
||||
|
||||
|
@ -115,17 +115,24 @@ namespace Dawn {
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all children, and children of children, recursively that match
|
||||
* the queried component.
|
||||
*
|
||||
* @tparam T Component Type to find.
|
||||
* @return Array of pointers to matching children components.
|
||||
*/
|
||||
template<class T>
|
||||
std::vector<T*> findChildrenDeep() {
|
||||
std::vector<Transform*> itemsToCheck = this->transform.children;
|
||||
std::vector<Transform*> transformsToCheck = this->transform.children;
|
||||
std::vector<T*> itemsFound;
|
||||
|
||||
while(itemsToCheck.size() > 0) {
|
||||
auto item = itemsToCheck.begin();
|
||||
vectorAppend(&itemsToCheck, (*item)->children);
|
||||
auto component = (*item)->item->getComponent<T>();
|
||||
while(transformsToCheck.size() > 0) {
|
||||
auto tras = transformsToCheck.begin();
|
||||
vectorAppend(&transformsToCheck, (*tras)->children);
|
||||
auto component = (*tras)->item->getComponent<T>();
|
||||
if(component != nullptr) itemsFound.push_back(component);
|
||||
itemsToCheck.erase(item);
|
||||
transformsToCheck.erase(tras);
|
||||
}
|
||||
|
||||
return itemsFound;
|
||||
|
@ -18,7 +18,7 @@ Camera::Camera(SceneItem *item) :
|
||||
orthoBottom(0.0f),
|
||||
orthoTop(1.0f),
|
||||
clipNear(0.001f),
|
||||
clipFar(50.0f)
|
||||
clipFar(1000.0f)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "UICanvas.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
#include "UIComponent.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
@ -13,10 +14,47 @@ UICanvas * UICanvas::create(Scene *scene) {
|
||||
return item->addComponent<UICanvas>();
|
||||
}
|
||||
|
||||
UICanvas::UICanvas(SceneItem *item) : SceneItemComponent(item) {
|
||||
UICanvas::UICanvas(SceneItem *item) :
|
||||
SceneItemComponent(item),
|
||||
camera(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
float_t UICanvas::getWidth() {
|
||||
return w;
|
||||
}
|
||||
|
||||
float_t UICanvas::getHeight() {
|
||||
return h;
|
||||
}
|
||||
|
||||
float_t UICanvas::getContentWidth() {
|
||||
return this->getWidth();
|
||||
}
|
||||
|
||||
float_t UICanvas::getContentHeight() {
|
||||
return this->getHeight();
|
||||
}
|
||||
|
||||
void UICanvas::onStart() {
|
||||
if(camera == nullptr) camera = getScene()->findComponent<Camera>();
|
||||
|
||||
useEffectWithTeardown([&]{
|
||||
if(camera == nullptr) return evtRenderResize = [&] {};
|
||||
this->w = camera->getRenderTarget()->getWidth();
|
||||
this->h = camera->getRenderTarget()->getHeight();
|
||||
return evtRenderResize = useEvent([&](float_t w, float_t h){
|
||||
this->w = w;
|
||||
this->h = h;
|
||||
|
||||
auto comps = this->item->findChildren<UIComponent>();
|
||||
auto itComps = comps.begin();
|
||||
while(itComps != comps.end()) {
|
||||
(*itComps)->alignmentNeedsUpdating = true;
|
||||
++itComps;
|
||||
}
|
||||
}, camera->eventRenderTargetResized);
|
||||
}, camera)();
|
||||
}
|
||||
|
||||
void UICanvas::onDispose() {
|
||||
|
@ -9,13 +9,26 @@
|
||||
#include "scene/components/display/Camera.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIComponentDimensional {
|
||||
public:
|
||||
virtual float_t getWidth() = 0;
|
||||
virtual float_t getHeight() = 0;
|
||||
virtual float_t getContentWidth() = 0;
|
||||
virtual float_t getContentHeight() = 0;
|
||||
};
|
||||
|
||||
enum UIDrawType {
|
||||
UI_DRAW_TYPE_WORLD_ABSOLUTE,
|
||||
UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE,
|
||||
UI_DRAW_TYPE_CAMERA_OVERLAY
|
||||
// UI_DRAW_TYPE_CAMERA_OVERLAY
|
||||
};
|
||||
|
||||
class UICanvas : public SceneItemComponent {
|
||||
class UICanvas : public SceneItemComponent, public UIComponentDimensional {
|
||||
private:
|
||||
std::function<void()> evtRenderResize;
|
||||
float_t w = 1;
|
||||
float_t h = 1;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a UI Canvas Scene Item Element, and attaches it to the provided
|
||||
@ -27,7 +40,7 @@ namespace Dawn {
|
||||
static UICanvas * create(Scene *scene);
|
||||
|
||||
//======================================================================//
|
||||
|
||||
StateProperty<Camera*> camera;
|
||||
enum UIDrawType drawType = UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE;
|
||||
|
||||
/**
|
||||
@ -37,6 +50,11 @@ namespace Dawn {
|
||||
*/
|
||||
UICanvas(SceneItem *item);
|
||||
|
||||
float_t getWidth() override;
|
||||
float_t getHeight() override;
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
|
||||
void onStart() override;
|
||||
void onDispose() override;
|
||||
};
|
||||
|
@ -7,6 +7,113 @@
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIComponent::UIComponent(SceneItem *item) : SceneItemComponent(item) {
|
||||
UIComponent::UIComponent(SceneItem *item) :
|
||||
SceneItemComponent(item),
|
||||
alignment(glm::vec4(0, 0, 128, 128)),
|
||||
alignX(UI_COMPONENT_ALIGN_START),
|
||||
alignY(UI_COMPONENT_ALIGN_START),
|
||||
alignmentNeedsUpdating(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
UIComponentDimensional * UIComponent::getParentDimensional() {
|
||||
auto parent = this->transform->getParent();
|
||||
if(!parent) return nullptr;
|
||||
auto dimensional = parent->item->getComponent<UIComponentDimensional>();
|
||||
assertNotNull(dimensional);
|
||||
return dimensional;
|
||||
}
|
||||
|
||||
void UIComponent::updateAlignment() {
|
||||
if(!this->alignmentNeedsUpdating) return;
|
||||
|
||||
auto dimensional = this->getParentDimensional();
|
||||
auto align = (glm::vec4)this->alignment;
|
||||
auto translate = this->transform->getLocalPosition();
|
||||
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignX,
|
||||
&translate.x,
|
||||
&this->width,
|
||||
dimensional->getWidth(),
|
||||
this->getContentWidth(),
|
||||
glm::vec2(align[0], align[2])
|
||||
);
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignY,
|
||||
&translate.y,
|
||||
&this->height,
|
||||
dimensional->getHeight(),
|
||||
this->getContentHeight(),
|
||||
glm::vec2(align[1], align[3])
|
||||
);
|
||||
|
||||
this->transform->setLocalPosition(translate);
|
||||
this->alignmentNeedsUpdating = false;
|
||||
|
||||
this->eventAlignmentUpdated.invoke();
|
||||
}
|
||||
|
||||
void UIComponent::calculateDimensions(
|
||||
enum UIComponentAlign align,
|
||||
float_t *position,
|
||||
float_t *size,
|
||||
float_t outerSize,
|
||||
float_t innerSize,
|
||||
glm::vec2 alignment
|
||||
) {
|
||||
assertNotNull(position);
|
||||
assertNotNull(size);
|
||||
|
||||
switch(align) {
|
||||
case UI_COMPONENT_ALIGN_STRETCH:
|
||||
*position = alignment[0];
|
||||
*size = outerSize + (alignment[0] + alignment[1]);
|
||||
break;
|
||||
|
||||
case UI_COMPONENT_ALIGN_START:
|
||||
*position = alignment[0];
|
||||
*size = alignment[1];
|
||||
break;
|
||||
|
||||
case UI_COMPONENT_ALIGN_MIDDLE:
|
||||
*size = mathMax<float_t>(innerSize, alignment[1]);
|
||||
*position = (outerSize / 2.0f) - (innerSize / 2.0f) + alignment[0];
|
||||
break;
|
||||
|
||||
case UI_COMPONENT_ALIGN_END:
|
||||
*size = alignment[0];
|
||||
*position = outerSize - innerSize - alignment[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float_t UIComponent::getWidth() {
|
||||
return this->width;
|
||||
}
|
||||
|
||||
float_t UIComponent::getHeight() {
|
||||
return this->height;
|
||||
}
|
||||
|
||||
void UIComponent::onStart() {
|
||||
useEffect([&]{
|
||||
this->alignmentNeedsUpdating = true;
|
||||
}, { &alignment, &alignX, &alignY });
|
||||
|
||||
useEffect([&]{
|
||||
this->updateAlignment();
|
||||
|
||||
auto child = this->item->findChildren<UIComponent>();
|
||||
auto itChild = child.begin();
|
||||
while(itChild != child.end()) {
|
||||
(*itChild)->alignmentNeedsUpdating = true;
|
||||
++itChild;
|
||||
}
|
||||
}, alignmentNeedsUpdating)();
|
||||
}
|
@ -6,20 +6,71 @@
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "UICanvas.hpp"
|
||||
#include "display/shader/Shader.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIComponentRendaerable {
|
||||
public:
|
||||
int32_t cum;
|
||||
enum UIComponentAlign {
|
||||
UI_COMPONENT_ALIGN_START,
|
||||
UI_COMPONENT_ALIGN_MIDDLE,
|
||||
UI_COMPONENT_ALIGN_END,
|
||||
UI_COMPONENT_ALIGN_STRETCH
|
||||
};
|
||||
|
||||
class UIComponent : public SceneItemComponent {
|
||||
private:
|
||||
UICanvas *canvas = nullptr;
|
||||
class UIComponentRenderable {
|
||||
public:
|
||||
virtual std::vector<struct ShaderPassItem> getPassItems(
|
||||
glm::mat4 projection,
|
||||
glm::mat4 view
|
||||
) = 0;
|
||||
};
|
||||
|
||||
class UIComponent : public SceneItemComponent, public UIComponentDimensional {
|
||||
protected:
|
||||
// Calculated (and cached) values
|
||||
float_t width = 1;
|
||||
float_t height = 1;
|
||||
|
||||
StateEvent<> eventAlignmentUpdated;
|
||||
UIComponentDimensional * getParentDimensional();
|
||||
|
||||
void updateAlignment();
|
||||
|
||||
public:
|
||||
StateProperty<bool_t> alignmentNeedsUpdating;
|
||||
|
||||
/**
|
||||
* Method used to calculate alignment dimensions.
|
||||
*
|
||||
* @param align Alignment value enumator.
|
||||
* @param position Output position floating point.
|
||||
* @param size Output size floating point.
|
||||
* @param outerSize Outer size (of the parent).
|
||||
* @param innerSize Inner size (of this element's content).
|
||||
* @param alignment Alignment settings.
|
||||
*/
|
||||
static void calculateDimensions(
|
||||
enum UIComponentAlign align,
|
||||
float_t *position,
|
||||
float_t *size,
|
||||
float_t outerSize,
|
||||
float_t innerSize,
|
||||
glm::vec2 alignment
|
||||
);
|
||||
|
||||
//
|
||||
|
||||
StateProperty<UIComponentAlign> alignX;
|
||||
StateProperty<UIComponentAlign> alignY;
|
||||
StateProperty<glm::vec4> alignment;
|
||||
|
||||
UIComponent(SceneItem *item);
|
||||
|
||||
float_t getWidth() override;
|
||||
float_t getHeight() override;
|
||||
|
||||
void onStart() override;
|
||||
|
||||
friend class UICanvas;
|
||||
};
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UILabel.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
@ -11,39 +12,100 @@ UILabel::UILabel(SceneItem *item) :
|
||||
UIComponent(item),
|
||||
text(""),
|
||||
fontSize(10.0f),
|
||||
font(nullptr)
|
||||
font(nullptr),
|
||||
maxWidth(UI_LABEL_MAX_WIDTH_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
bool_t UILabel::hasText() {
|
||||
return (
|
||||
this->font != nullptr &&
|
||||
this->font->isReady() &&
|
||||
((std::string)this->text).size() > 0
|
||||
);
|
||||
}
|
||||
|
||||
void UILabel::updateMesh() {
|
||||
if(!this->needsRebuffering || !this->hasText) return;
|
||||
if(((Font*)this->font) == nullptr || !this->font->isReady()) return;
|
||||
if(!this->needsRebuffering) return;
|
||||
if(!this->hasText()) return;
|
||||
|
||||
// float_t width = this->width;
|
||||
// if(width == 0) width = -1;
|
||||
|
||||
// std::string text = this->getGame()->localeManager.getString(key);
|
||||
float_t width = this->maxWidth;
|
||||
assertTrue(width == 0 || width == -1 || width > 0);
|
||||
if(width == 0) {
|
||||
auto dimensional = this->getParentDimensional();
|
||||
auto align = (glm::vec4)this->alignment;
|
||||
float_t x;
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignX,
|
||||
&x,
|
||||
&width,
|
||||
dimensional->getWidth(),
|
||||
0,
|
||||
glm::vec2(align[0], align[2])
|
||||
);
|
||||
}
|
||||
|
||||
this->font->buffer(
|
||||
text,
|
||||
fontSize,
|
||||
-1,
|
||||
width,
|
||||
&this->mesh,
|
||||
&this->measure
|
||||
);
|
||||
|
||||
this->needsRebuffering = false;
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> UILabel::getPassItems(
|
||||
glm::mat4 proj, glm::mat4 view
|
||||
) {
|
||||
if(!this->hasText()) return {};
|
||||
this->updateMesh();
|
||||
|
||||
struct ShaderPassItem item;
|
||||
auto shader = &getGame()->renderManager.uiShaderProgram;
|
||||
item.shaderProgram = shader;
|
||||
item.colorValues[shader->paramColor] = textColor;
|
||||
item.matrixValues[shader->paramProjection] = proj;
|
||||
item.matrixValues[shader->paramView] = view;
|
||||
item.matrixValues[shader->paramModel] = this->transform->getWorldTransform();
|
||||
item.boolValues[shader->paramHasTexture] = true;
|
||||
item.textureSlots[0] = this->font->getTexture();
|
||||
item.textureValues[shader->paramTexture] = 0;
|
||||
item.start = this->startQuad * QUAD_INDICE_COUNT;
|
||||
item.count = this->quadCount == -1 ? -1 : this->quadCount * QUAD_INDICE_COUNT;
|
||||
item.w = this->transform->getWorldPosition().z;
|
||||
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
|
||||
item.mesh = &mesh;
|
||||
|
||||
return { item };
|
||||
}
|
||||
|
||||
float_t UILabel::getContentWidth() {
|
||||
if(this->maxWidth > 0) return this->maxWidth;
|
||||
if(!this->hasText()) return 0;
|
||||
this->updateMesh();
|
||||
return this->measure.getWidth();
|
||||
}
|
||||
|
||||
float_t UILabel::getContentHeight() {
|
||||
if(!this->hasText()) return 0;
|
||||
this->updateMesh();
|
||||
return this->measure.getHeight();
|
||||
}
|
||||
|
||||
void UILabel::onStart() {
|
||||
UIComponent::onStart();
|
||||
|
||||
useEffect([&]{
|
||||
hasText = ((std::string)text).size() > 0;
|
||||
needsRebuffering = true;
|
||||
}, text);
|
||||
alignmentNeedsUpdating = true;
|
||||
}, { &fontSize, &font, &text, &maxWidth });
|
||||
|
||||
useEffect([&]{
|
||||
needsRebuffering = true;
|
||||
}, fontSize);
|
||||
}, alignmentNeedsUpdating);
|
||||
|
||||
useEffect([&]{
|
||||
useEvent([&]{
|
||||
needsRebuffering = true;
|
||||
}, font);
|
||||
}, eventAlignmentUpdated);
|
||||
}
|
@ -7,20 +7,23 @@
|
||||
#include "UIComponent.hpp"
|
||||
#include "display/font/Font.hpp"
|
||||
|
||||
#define UI_LABEL_MAX_WIDTH_NONE -1
|
||||
#define UI_LABEL_MAX_WIDTH_ALIGN 0
|
||||
|
||||
namespace Dawn {
|
||||
class UILabel : public UIComponent {
|
||||
class UILabel : public UIComponent, public UIComponentRenderable {
|
||||
private:
|
||||
bool_t needsRebuffering = true;
|
||||
bool_t hasText = false;
|
||||
|
||||
Mesh mesh;
|
||||
|
||||
bool_t hasText();
|
||||
void updateMesh();
|
||||
|
||||
public:
|
||||
StateProperty<std::string> text;
|
||||
StateProperty<float_t> fontSize;
|
||||
StateProperty<Font*> font;
|
||||
StateProperty<float_t> maxWidth;
|
||||
struct Color textColor = COLOR_MAGENTA;
|
||||
struct FontMeasure measure;
|
||||
int32_t startQuad = 0;
|
||||
@ -28,6 +31,11 @@ namespace Dawn {
|
||||
|
||||
UILabel(SceneItem *item);
|
||||
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
std::vector<struct ShaderPassItem> getPassItems(
|
||||
glm::mat4 projection, glm::mat4 view
|
||||
) override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,98 +1,98 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "StateInterfaces.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
template<class V>
|
||||
class StateProperty : public IStateProperty {
|
||||
private:
|
||||
/**
|
||||
* Method that is invoked every time that the value of this state property
|
||||
* is updated.
|
||||
*
|
||||
* @param val Value that is to be used for this property.
|
||||
*/
|
||||
void setInternal(V val) {
|
||||
if(val == this->_realValue) return;// TODO: can I omit this? kinda bad tbh.
|
||||
|
||||
// Run the teardowns
|
||||
auto itTeardown = this->_effectTeardowns.begin();
|
||||
while(itTeardown != this->_effectTeardowns.end()) {
|
||||
(*itTeardown)();
|
||||
++itTeardown;
|
||||
}
|
||||
this->_effectTeardowns.clear();
|
||||
|
||||
// Update the values
|
||||
this->previous = this->_realValue;
|
||||
this->_realValue = val;
|
||||
|
||||
// Notify the effect listeners
|
||||
auto itEffect = this->_effectListners.begin();
|
||||
while(itEffect != this->_effectListners.end()) {
|
||||
(*itEffect)();
|
||||
++itEffect;
|
||||
}
|
||||
|
||||
// Notify the teardown effect listeners
|
||||
auto itWithTeardown = this->_effectListnersWithTeardown.begin();
|
||||
while(itWithTeardown != this->_effectListnersWithTeardown.end()) {
|
||||
auto teardown = (*itWithTeardown)();
|
||||
this->_effectTeardowns.push_back(teardown);
|
||||
++itWithTeardown;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
V _realValue;
|
||||
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), previous(initial) {}
|
||||
|
||||
const StateProperty& operator += (const V &value) {
|
||||
this->setInternal(this->_realValue + value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const bool_t operator != (const V &value) {
|
||||
return value != this->_realValue;
|
||||
}
|
||||
|
||||
const bool_t operator == (const V &value) {
|
||||
return value == this->_realValue;
|
||||
}
|
||||
|
||||
const StateProperty& operator = (const V &val) {
|
||||
this->setInternal(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const V operator->() const {
|
||||
return this->_realValue;
|
||||
}
|
||||
|
||||
operator V() const {
|
||||
return this->_realValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor for StateProperty.
|
||||
*/
|
||||
~StateProperty() {}
|
||||
|
||||
friend class StateOwner;
|
||||
};
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "StateInterfaces.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
template<class V>
|
||||
class StateProperty : public IStateProperty {
|
||||
private:
|
||||
/**
|
||||
* Method that is invoked every time that the value of this state property
|
||||
* is updated.
|
||||
*
|
||||
* @param val Value that is to be used for this property.
|
||||
*/
|
||||
void setInternal(V val) {
|
||||
if(val == this->_realValue) return;// TODO: can I omit this? kinda bad tbh.
|
||||
|
||||
// Run the teardowns
|
||||
auto itTeardown = this->_effectTeardowns.begin();
|
||||
while(itTeardown != this->_effectTeardowns.end()) {
|
||||
(*itTeardown)();
|
||||
++itTeardown;
|
||||
}
|
||||
this->_effectTeardowns.clear();
|
||||
|
||||
// Update the values
|
||||
this->previous = this->_realValue;
|
||||
this->_realValue = val;
|
||||
|
||||
// Notify the effect listeners
|
||||
auto itEffect = this->_effectListners.begin();
|
||||
while(itEffect != this->_effectListners.end()) {
|
||||
(*itEffect)();
|
||||
++itEffect;
|
||||
}
|
||||
|
||||
// Notify the teardown effect listeners
|
||||
auto itWithTeardown = this->_effectListnersWithTeardown.begin();
|
||||
while(itWithTeardown != this->_effectListnersWithTeardown.end()) {
|
||||
auto teardown = (*itWithTeardown)();
|
||||
this->_effectTeardowns.push_back(teardown);
|
||||
++itWithTeardown;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
V _realValue;
|
||||
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), previous(initial) {}
|
||||
|
||||
const StateProperty& operator += (const V &value) {
|
||||
this->setInternal(this->_realValue + value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const bool_t operator != (const V &value) {
|
||||
return value != this->_realValue;
|
||||
}
|
||||
|
||||
const bool_t operator == (const V &value) {
|
||||
return value == this->_realValue;
|
||||
}
|
||||
|
||||
const StateProperty& operator = (const V &val) {
|
||||
this->setInternal(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const V operator->() const {
|
||||
return this->_realValue;
|
||||
}
|
||||
|
||||
operator V() const {
|
||||
return this->_realValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor for StateProperty.
|
||||
*/
|
||||
~StateProperty() {}
|
||||
|
||||
friend class StateOwner;
|
||||
};
|
||||
}
|
@ -1,43 +1,14 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "SimpleTexturedShaderProgram.hpp"
|
||||
|
||||
#define UI_SHADER_PROGRAM_PRIORITY 100
|
||||
|
||||
namespace Dawn {
|
||||
class UIShaderProgram : public SimpleTexturedShaderProgram {
|
||||
public:
|
||||
struct ShaderPassItem getUIPassItem(
|
||||
glm::mat4 projection,
|
||||
glm::mat4 view,
|
||||
glm::mat4 transform,
|
||||
Texture *texture,
|
||||
struct Color color,
|
||||
Mesh *mesh,
|
||||
float_t z
|
||||
) {
|
||||
struct ShaderPassItem item;
|
||||
item.shaderProgram = this;
|
||||
item.colorValues[this->paramColor] = color;
|
||||
if(texture == nullptr) {
|
||||
item.boolValues[this->paramHasTexture] = false;
|
||||
} else {
|
||||
item.textureSlots[0] = texture;
|
||||
item.textureValues[this->paramTexture] = 0;
|
||||
item.boolValues[this->paramHasTexture] = true;
|
||||
}
|
||||
item.matrixValues[this->paramProjection] = projection;
|
||||
item.matrixValues[this->paramView] = view;
|
||||
item.matrixValues[this->paramModel] = transform;
|
||||
item.priority = UI_SHADER_PROGRAM_PRIORITY;
|
||||
item.w = z;
|
||||
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
|
||||
item.mesh = mesh;
|
||||
return item;
|
||||
}
|
||||
};
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "SimpleTexturedShaderProgram.hpp"
|
||||
|
||||
#define UI_SHADER_PROGRAM_PRIORITY 100
|
||||
|
||||
namespace Dawn {
|
||||
class UIShaderProgram : public SimpleTexturedShaderProgram {
|
||||
};
|
||||
}
|
@ -86,7 +86,7 @@ void TicTacToeGame::onStart() {
|
||||
}
|
||||
|
||||
if(isPlayerMove) {
|
||||
if(getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK)) {
|
||||
if(getGame()->inputManager.isPressed(INPUT_BIND_MOUSE_CLICK) && hovered != nullptr) {
|
||||
this->makeMove(hovered->tile, nextMove);
|
||||
}
|
||||
} else if(nextMove != TIC_TAC_TOE_NOUGHT) {
|
||||
|
@ -15,15 +15,18 @@
|
||||
|
||||
namespace Dawn {
|
||||
|
||||
class TicTacToeScene : public Scene {
|
||||
class TicTacToeScene : public Scene, public StateOwner {
|
||||
protected:
|
||||
Camera *camera;
|
||||
int32_t age = 0;
|
||||
std::function<void()> evtUnsub;
|
||||
|
||||
UILabel *label;
|
||||
StateProperty<int32_t> test;
|
||||
|
||||
void stage() override {
|
||||
camera = Camera::create(this);
|
||||
camera->transform->lookAt(glm::vec3(0, 0, 8), glm::vec3(0, 0, 0));
|
||||
// camera->transform->lookAt(glm::vec3(0, 0, 8), glm::vec3(0, 0, 0));
|
||||
camera->transform->lookAt(glm::vec3(32, 32, 32), glm::vec3(0, 0, 0));
|
||||
|
||||
float_t s = 2.0f;
|
||||
camera->orthoTop = s;
|
||||
@ -49,10 +52,24 @@ namespace Dawn {
|
||||
auto canvas = canvasItem->addComponent<UICanvas>();
|
||||
|
||||
auto labelItem = this->createSceneItem();
|
||||
auto label = labelItem->addComponent<UILabel>();
|
||||
label = labelItem->addComponent<UILabel>();
|
||||
label->font = &this->game->assetManager.get<TrueTypeAsset>("truetype_bizudp")->font;
|
||||
label->text = "Hello World";
|
||||
label->fontSize = 36.0f;
|
||||
labelItem->transform.setParent(canvas->transform);
|
||||
|
||||
label->alignX = UI_COMPONENT_ALIGN_MIDDLE;
|
||||
label->alignY = UI_COMPONENT_ALIGN_MIDDLE;
|
||||
label->alignment = glm::vec4(0, 0, 350, 100);
|
||||
label->maxWidth = 0;
|
||||
|
||||
useEffect([&]{
|
||||
label->text = "Hello " + std::to_string(test) + " world";
|
||||
}, test);
|
||||
|
||||
useEvent([&](float_t delta){
|
||||
test = test + 1;
|
||||
}, this->eventSceneUpdate);
|
||||
}
|
||||
|
||||
std::vector<Asset*> getRequiredAssets() override {
|
||||
@ -65,6 +82,6 @@ namespace Dawn {
|
||||
}
|
||||
|
||||
public:
|
||||
TicTacToeScene(DawnGame *game) : Scene(game) {}
|
||||
TicTacToeScene(DawnGame *game) : Scene(game), test(0) {}
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user