Base refactor
This commit is contained in:
@ -1,19 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Scene.cpp
|
||||
SceneItem.cpp
|
||||
SceneItemComponent.cpp
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(components)
|
||||
|
||||
if(DAWN_DEBUG_BUILD)
|
||||
add_subdirectory(debug)
|
||||
endif()
|
@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Scene.hpp"
|
||||
#include "SceneItem.hpp"
|
||||
#include "SceneItemComponent.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
Scene::Scene(const std::weak_ptr<DawnGame> game) {
|
||||
this->game = game;
|
||||
this->nextId = 0;
|
||||
}
|
||||
|
||||
void Scene::update() {
|
||||
// Finsh adding scene items that were trying to add from the last frame.
|
||||
auto it = this->itemsNotInitialized.begin();
|
||||
while(it != this->itemsNotInitialized.end()) {
|
||||
this->items[it->first] = it->second;
|
||||
it->second->init();
|
||||
++it;
|
||||
}
|
||||
this->itemsNotInitialized.clear();
|
||||
|
||||
// TODO: Cleanup old scene items
|
||||
|
||||
// TODO: Tick scene items(?)
|
||||
auto game = this->game.lock();
|
||||
this->eventSceneUpdate.invoke(game->timeManager.delta);
|
||||
if(!game->timeManager.isPaused) this->eventSceneUnpausedUpdate.invoke(game->timeManager.delta);
|
||||
}
|
||||
|
||||
std::shared_ptr<SceneItem> Scene::createSceneItem() {
|
||||
return this->createSceneItemOfType<SceneItem>();
|
||||
}
|
||||
|
||||
Scene::~Scene() {
|
||||
// Invoke cleanup.
|
||||
auto it = this->items.begin();
|
||||
while(it != this->items.end()) {
|
||||
it->second->destroy();
|
||||
++it;
|
||||
}
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "asset/Asset.hpp"
|
||||
#include "state/StateEvent.hpp"
|
||||
#include "state/StateOwner.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class DawnGame;
|
||||
class RenderPipeline;
|
||||
class SceneItem;
|
||||
class SceneItemComponent;
|
||||
|
||||
typedef int32_t sceneitemid_t;
|
||||
|
||||
// Scene Item Forwarders
|
||||
template<class T>
|
||||
std::shared_ptr<T> _sceneForwardGetComponent(std::shared_ptr<SceneItem> item);
|
||||
|
||||
template<class T>
|
||||
std::vector<std::shared_ptr<T>> _sceneForwardGetComponents(
|
||||
std::shared_ptr<SceneItem> item
|
||||
);
|
||||
|
||||
class Scene : public StateOwner, public std::enable_shared_from_this<Scene> {
|
||||
private:
|
||||
sceneitemid_t nextId;
|
||||
std::map<sceneitemid_t, std::shared_ptr<SceneItem>> items;
|
||||
std::map<sceneitemid_t, std::shared_ptr<SceneItem>> itemsNotInitialized;
|
||||
|
||||
public:
|
||||
std::weak_ptr<DawnGame> game;
|
||||
StateEvent<float_t> eventSceneUpdate;
|
||||
StateEvent<float_t> eventSceneUnpausedUpdate;
|
||||
|
||||
/**
|
||||
* Construct a new Scene instance.
|
||||
*
|
||||
* @param game Reference to the game that this scene belongs to.
|
||||
*/
|
||||
Scene(const std::weak_ptr<DawnGame> game);
|
||||
|
||||
/**
|
||||
* Perform a one frame synchronous tick on the current scene. This may
|
||||
* change in future to be more event-like.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Create a Scene Item object and add to the current scene.
|
||||
*
|
||||
* @return A shared pointer to the created SceneItem.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> createSceneItemOfType() {
|
||||
sceneitemid_t id = this->nextId++;
|
||||
auto item = std::make_shared<T>(weak_from_this(), id);
|
||||
assertNotNull(item, "Failed to create SceneItem (Memory Filled?)");
|
||||
this->itemsNotInitialized[id] = item;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Scene Item object and add to the current scene.
|
||||
*
|
||||
* @return A shared pointer to the created SceneItem.
|
||||
*/
|
||||
std::shared_ptr<SceneItem> createSceneItem();
|
||||
|
||||
/**
|
||||
* Returns the required assets for this scene. Assets required are meant
|
||||
* to be referenced back to the loader so that special loading actions can
|
||||
* be performed against them.
|
||||
*
|
||||
* @return List of assets required by this scene.
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<Asset>> getRequiredAssets() = 0;
|
||||
|
||||
/**
|
||||
* Method to begin the actual staging of the scene, typically called after
|
||||
* the scene has finished loading.
|
||||
*/
|
||||
virtual void stage() = 0;
|
||||
|
||||
/**
|
||||
* Finds an existing component on the scene (Root Level Only) that has a
|
||||
* component matching the given component type. Returns nullptr if no item
|
||||
* with the specified component could be found.
|
||||
*
|
||||
* @tparam Component type to look for.
|
||||
* @return Pointer to the found component (and by extension the item).
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> findComponent() {
|
||||
auto it = this->itemsNotInitialized.begin();
|
||||
while(it != this->itemsNotInitialized.end()) {
|
||||
auto component = _sceneForwardGetComponent<T>(it->second);
|
||||
if(component != nullptr) return component;
|
||||
++it;
|
||||
}
|
||||
auto it2 = this->items.begin();
|
||||
while(it2 != this->items.end()) {
|
||||
auto component = _sceneForwardGetComponent<T>(it2->second);
|
||||
if(component != nullptr) return component;
|
||||
++it2;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all exisitng components on the scene (Root Level Only) that has a
|
||||
* matching component of the given component type.
|
||||
*
|
||||
* @tparam Component type to look for.
|
||||
* @return List of matching compnoents.
|
||||
*/
|
||||
template<class T>
|
||||
std::vector<std::shared_ptr<T>> findComponents() {
|
||||
std::vector<std::shared_ptr<T>> components;
|
||||
|
||||
auto it = this->itemsNotInitialized.begin();
|
||||
while(it != this->itemsNotInitialized.end()) {
|
||||
auto component = _sceneForwardGetComponent<T>(it->second);
|
||||
if(component != nullptr) components.push_back(component);
|
||||
++it;
|
||||
}
|
||||
|
||||
auto it2 = this->items.begin();
|
||||
while(it2 != this->items.end()) {
|
||||
auto component = _sceneForwardGetComponent<T>(it2->second);
|
||||
if(component != nullptr) components.push_back(component);
|
||||
++it2;
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a previously initialized Scene.
|
||||
*/
|
||||
virtual ~Scene();
|
||||
|
||||
friend class RenderPipeline;
|
||||
};
|
||||
}
|
@ -1,249 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SceneItem.hpp"
|
||||
#include "SceneItemComponent.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
SceneItem::SceneItem(const std::weak_ptr<Scene> scene, const sceneitemid_t id) :
|
||||
transformLocal(1.0f),
|
||||
transformWorld(1.0f),
|
||||
scene(scene),
|
||||
id(id)
|
||||
{
|
||||
this->updateLocalValuesFromLocalTransform();
|
||||
}
|
||||
|
||||
void SceneItem::init() {
|
||||
// Keep checking all components until they have all inited
|
||||
int32_t waitingOn;
|
||||
do {
|
||||
waitingOn = 0;
|
||||
|
||||
// For each component
|
||||
auto it = this->components.begin();
|
||||
while(it != this->components.end()) {
|
||||
// Has this component already inited?
|
||||
if((*it)->hasInitialized) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
// For each dependency.
|
||||
auto deps = (*it)->getDependencies();
|
||||
bool_t waiting = false;
|
||||
auto it2 = deps.begin();
|
||||
while(it2 != deps.end()) {
|
||||
if(*it2 == nullptr) {
|
||||
++it2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Has the dep not yet inited?
|
||||
if(!(*it2)->hasInitialized) {
|
||||
waiting = true;
|
||||
break;
|
||||
}
|
||||
++it2;
|
||||
}
|
||||
|
||||
// Are we waiting for a dep?
|
||||
if(waiting) {
|
||||
waitingOn++;
|
||||
} else {
|
||||
(*it)->init();
|
||||
}
|
||||
++it;
|
||||
}
|
||||
} while(waitingOn != 0);
|
||||
}
|
||||
|
||||
void SceneItem::destroy() {
|
||||
this->components.clear();
|
||||
}
|
||||
|
||||
void SceneItem::updateLocalValuesFromLocalTransform() {
|
||||
glm::vec3 skew;
|
||||
glm::vec4 perspective;
|
||||
glm::decompose(
|
||||
this->transformLocal,
|
||||
this->localScale,
|
||||
this->localRotation,
|
||||
this->localPosition,
|
||||
skew, perspective
|
||||
);
|
||||
}
|
||||
|
||||
void SceneItem::updateLocalTransformFromLocalValues() {
|
||||
glm::mat4 translate = glm::translate(glm::mat4(1.0), this->localPosition);
|
||||
glm::mat4 rotate = glm::mat4_cast(this->localRotation);
|
||||
glm::mat4 scale = glm::scale(glm::mat4(1.0), this->localScale);
|
||||
this->transformLocal = translate * rotate * scale;
|
||||
this->updateWorldTransformFromLocalTransform();
|
||||
}
|
||||
|
||||
void SceneItem::updateWorldTransformFromLocalTransform() {
|
||||
auto parent = this->getParent();
|
||||
if(parent != nullptr) {
|
||||
auto newWorld = parent->getWorldTransform();
|
||||
this->transformWorld = newWorld * transformLocal;
|
||||
} else {
|
||||
this->transformWorld = transformLocal;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneItem::updateLocalTransformFromWorldTransform() {
|
||||
glm::mat4 parentMat(1.0f);
|
||||
auto parent = this->getParent();
|
||||
if(parent != nullptr) parentMat = parent->getWorldTransform();
|
||||
this->transformLocal = parentMat / this->transformWorld;
|
||||
this->updateLocalValuesFromLocalTransform();
|
||||
}
|
||||
|
||||
void SceneItem::updateChildrenTransforms() {
|
||||
auto it = this->children.begin();
|
||||
while(it != this->children.end()) {
|
||||
auto childTrans = it->lock();
|
||||
if(childTrans) childTrans->updateWorldTransformFromLocalTransform();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void SceneItem::lookAt(glm::vec3 pos, glm::vec3 look) {
|
||||
this->lookAt(pos, look, glm::vec3(0, 1, 0));
|
||||
}
|
||||
|
||||
void SceneItem::lookAt(glm::vec3 pos, glm::vec3 look, glm::vec3 up) {
|
||||
this->setWorldTransform(glm::lookAt(pos, look, up));
|
||||
}
|
||||
|
||||
float_t SceneItem::lookAtPixelPerfect(
|
||||
glm::vec3 position, glm::vec3 look, float_t viewportHeight, float_t fov
|
||||
) {
|
||||
float_t z = (
|
||||
tanf((mathDeg2Rad(180.0f) - fov) / 2.0f) *
|
||||
(viewportHeight/2.0f)
|
||||
);
|
||||
this->lookAt(glm::vec3(position.x, position.y, position.z + z), look);
|
||||
return z;
|
||||
}
|
||||
|
||||
glm::vec3 SceneItem::getLocalPosition() {
|
||||
return this->localPosition;
|
||||
}
|
||||
|
||||
void SceneItem::setLocalPosition(glm::vec3 position) {
|
||||
this->localPosition = position;
|
||||
this->updateLocalTransformFromLocalValues();
|
||||
this->updateChildrenTransforms();
|
||||
this->eventTransformUpdated.invoke();
|
||||
}
|
||||
|
||||
glm::vec3 SceneItem::getLocalScale() {
|
||||
return this->localScale;
|
||||
}
|
||||
|
||||
void SceneItem::setLocalScale(glm::vec3 scale) {
|
||||
this->localScale = scale;
|
||||
this->updateLocalTransformFromLocalValues();
|
||||
this->updateChildrenTransforms();
|
||||
this->eventTransformUpdated.invoke();
|
||||
}
|
||||
|
||||
glm::quat SceneItem::getLocalRotation() {
|
||||
return this->localRotation;
|
||||
}
|
||||
|
||||
void SceneItem::setLocalRotation(glm::quat rotation) {
|
||||
this->localRotation = rotation;
|
||||
this->updateLocalTransformFromLocalValues();
|
||||
this->updateChildrenTransforms();
|
||||
this->eventTransformUpdated.invoke();
|
||||
}
|
||||
|
||||
|
||||
glm::mat4 SceneItem::getLocalTransform() {
|
||||
return this->transformLocal;
|
||||
}
|
||||
|
||||
void SceneItem::setLocalTransform(glm::mat4 transform) {
|
||||
this->transformLocal = transform;
|
||||
|
||||
this->updateLocalValuesFromLocalTransform();
|
||||
this->updateChildrenTransforms();
|
||||
this->eventTransformUpdated.invoke();
|
||||
}
|
||||
|
||||
glm::vec3 SceneItem::getWorldPosition() {
|
||||
return this->transformWorld[3];
|
||||
}
|
||||
|
||||
glm::mat4 SceneItem::getWorldTransform() {
|
||||
return this->transformWorld;
|
||||
}
|
||||
|
||||
void SceneItem::setWorldTransform(glm::mat4 transform) {
|
||||
this->transformWorld = transform;
|
||||
this->updateLocalTransformFromWorldTransform();
|
||||
this->updateChildrenTransforms();
|
||||
this->eventTransformUpdated.invoke();
|
||||
}
|
||||
|
||||
|
||||
void SceneItem::setParent(std::shared_ptr<SceneItem> parent) {
|
||||
assertTrue(
|
||||
parent == nullptr || parent != shared_from_this(),
|
||||
"SceneItem::setParent: Cannot set parent to self"
|
||||
);
|
||||
|
||||
auto currentParent = this->getParent();
|
||||
if(currentParent == parent) return;
|
||||
|
||||
if(currentParent != nullptr) {
|
||||
auto it = currentParent->children.begin();
|
||||
while(it != currentParent->children.end()) {
|
||||
auto child = (*it).lock();
|
||||
if(child == shared_from_this()) {
|
||||
currentParent->children.erase(it);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
this->parent = parent;
|
||||
if(parent != nullptr) parent->children.push_back(shared_from_this());
|
||||
|
||||
this->updateLocalTransformFromWorldTransform();
|
||||
this->updateChildrenTransforms();
|
||||
this->eventTransformUpdated.invoke();
|
||||
}
|
||||
|
||||
std::shared_ptr<SceneItem> SceneItem::getParent() {
|
||||
return this->parent.lock();
|
||||
}
|
||||
|
||||
bool_t SceneItem::isChildOf(std::shared_ptr<SceneItem> parent) {
|
||||
auto current = this->getParent();
|
||||
std::shared_ptr<SceneItem> currentLocked;
|
||||
while(currentLocked = current) {
|
||||
if(currentLocked == parent) return true;
|
||||
current = currentLocked->getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SceneItem::~SceneItem() {
|
||||
this->setParent(nullptr);
|
||||
|
||||
auto it = this->children.begin();
|
||||
while(it != this->children.end()) {
|
||||
auto child = (*it).lock();
|
||||
if(child != nullptr) child->setParent(nullptr);
|
||||
it = this->children.begin();
|
||||
}
|
||||
}
|
@ -1,328 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/Scene.hpp"
|
||||
#include "util/array.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class SceneItemComponent;
|
||||
|
||||
class SceneItem :
|
||||
public StateOwner,
|
||||
public std::enable_shared_from_this<SceneItem>
|
||||
{
|
||||
private:
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> components;
|
||||
// Local (real) values
|
||||
glm::vec3 localPosition;
|
||||
glm::vec3 localScale;
|
||||
glm::quat localRotation;
|
||||
|
||||
// Cached (non-real) values
|
||||
glm::mat4 transformLocal;
|
||||
glm::mat4 transformWorld;
|
||||
|
||||
// glm::vec3 position;
|
||||
// glm::vec3 scale;
|
||||
// glm::quat rotation;
|
||||
|
||||
// Heirarchy
|
||||
std::weak_ptr<SceneItem> parent;
|
||||
std::vector<std::weak_ptr<SceneItem>> children;
|
||||
|
||||
// Hidden methods
|
||||
void updateLocalValuesFromLocalTransform();
|
||||
void updateLocalTransformFromLocalValues();
|
||||
void updateWorldTransformFromLocalTransform();
|
||||
void updateLocalTransformFromWorldTransform();
|
||||
void updateChildrenTransforms();
|
||||
|
||||
public:
|
||||
const std::weak_ptr<Scene> scene;
|
||||
const sceneitemid_t id;
|
||||
StateEvent<> eventTransformUpdated;
|
||||
|
||||
/**
|
||||
* Constructor for a SceneItem. Scene Items should only be called and
|
||||
* initialized by the scene itself.
|
||||
*
|
||||
* @param scene Weak pointer to the Scene that this SceneItem belongs to.
|
||||
* @param id Scene Item ID that the Scene assigned this SceneItem.
|
||||
*/
|
||||
SceneItem(const std::weak_ptr<Scene> scene, const sceneitemid_t id);
|
||||
|
||||
/**
|
||||
* Called by the Scene the frame after we were constructed so we can begin
|
||||
* existing.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Called by the Scene when cleanup needs to occur but before anything in
|
||||
* the scene has been disposed.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Adds a component to this scene item. Components will only have their
|
||||
* init methods invoked on the first frame we enter the scene. If you add
|
||||
* a component to this item after this time you will either need to try
|
||||
* manually invoking its' init method, or ensure the component is aware of
|
||||
* the entire SceneItem lifecycle and listen for added callbacks.
|
||||
*
|
||||
* @tparam T Type of component being added to this scene item.
|
||||
* @return A shared pointer to the newly added component.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> addComponent() {
|
||||
auto component = std::make_shared<T>(weak_from_this());
|
||||
this->components.push_back(component);
|
||||
return component;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a component attached to this SceneItem. This method will return
|
||||
* either a shared pointer to the component, or nullptr if the item does
|
||||
* not have the queried component.
|
||||
*
|
||||
* @tparam T Type of component to be fetched.
|
||||
* @return A shared pointer to the component, or nullptr if not found.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> getComponent() {
|
||||
auto it = this->components.begin();
|
||||
while(it != this->components.end()) {
|
||||
std::shared_ptr<T> castedAs = std::dynamic_pointer_cast<T>(*it);
|
||||
if(castedAs != nullptr) return castedAs;
|
||||
++it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all components attached to this SceneItem that match the
|
||||
* queried component type. This method will return an array of shared
|
||||
* pointers to the components, or an empty array if the item does not have
|
||||
* any components of the queried type.
|
||||
*
|
||||
* @tparam T Type of component to be fetched.
|
||||
* @return An array of pointers to the components.
|
||||
*/
|
||||
template<class T>
|
||||
std::vector<std::shared_ptr<T>> getComponents() {
|
||||
std::vector<std::shared_ptr<T>> components;
|
||||
auto it = this->components.begin();
|
||||
while(it != this->components.end()) {
|
||||
T *castedAs = std::dynamic_pointer_cast<T>(it);
|
||||
if(castedAs != nullptr) components.push_back(castedAs);
|
||||
++it;
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a (direct) child of this component that has a matching component.
|
||||
*
|
||||
* @tparam T Component to find child of.
|
||||
* @return Pointer to the child, or nullptr if not found.
|
||||
*/
|
||||
template<class T>
|
||||
std::shared_ptr<T> findChild() {
|
||||
auto it = this->children.begin();
|
||||
while(it != this->children.end()) {
|
||||
auto childItem = it->lock();
|
||||
if(childItem == nullptr) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto childComponent = childItem->getComponent<T>();
|
||||
if(childComponent != nullptr) return childComponent;
|
||||
++it;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all (direct) children of this component that match the queried
|
||||
* component.
|
||||
*
|
||||
* @tparam T Component to find children for.
|
||||
* @return Array of pointers to matching children.
|
||||
*/
|
||||
template<class T>
|
||||
std::vector<std::shared_ptr<T>> findChildren() {
|
||||
auto it = this->children.begin();
|
||||
std::vector<std::shared_ptr<T>> children;
|
||||
while(it != this->children.end()) {
|
||||
auto childItem = it->lock();
|
||||
if(childItem == nullptr) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
auto childComponent = childItem->getComponent<T>();
|
||||
if(childComponent != nullptr) children.push_back(childComponent);
|
||||
++it;
|
||||
}
|
||||
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<std::shared_ptr<T>> findChildrenDeep() {
|
||||
auto childrenToCheck = this->children;
|
||||
std::vector<std::shared_ptr<T>> itemsFound;
|
||||
|
||||
while(childrenToCheck.size() > 0) {
|
||||
auto it = *childrenToCheck.begin();
|
||||
auto otherItem = it.lock();
|
||||
if(otherItem != nullptr) {
|
||||
vectorAppend(childrenToCheck, otherItem->children);
|
||||
}
|
||||
auto component = otherItem->getComponent<T>();
|
||||
if(component != nullptr) itemsFound.push_back(component);
|
||||
childrenToCheck.erase(childrenToCheck.begin());
|
||||
}
|
||||
|
||||
return itemsFound;
|
||||
}
|
||||
|
||||
// // // // // // // // // // // // // // // // // // // // // // // // //
|
||||
|
||||
/**
|
||||
* Orients this transform to look at a given point in world space.
|
||||
*
|
||||
* @param position Position of the origin of this transform.
|
||||
* @param look Position in world space this transform looks at.
|
||||
*/
|
||||
void lookAt(const glm::vec3 position, const glm::vec3 look);
|
||||
void lookAt(
|
||||
const glm::vec3 position,
|
||||
const glm::vec3 look,
|
||||
const glm::vec3 up
|
||||
);
|
||||
|
||||
/**
|
||||
* Shorthand combined for lookAt and perspectivePixelPerfectDistance
|
||||
* to allow you to create pixel perfect lookAt camera view matricies.
|
||||
*
|
||||
* @param position Position of the camera. Z is for an offset.
|
||||
* @param look Position in world space this transform looks at.
|
||||
* @param viewportHeight Height of the viewport.
|
||||
* @param fov Field of view (in radians).
|
||||
* @return The Z distance that was calculated.
|
||||
*/
|
||||
float_t lookAtPixelPerfect(
|
||||
const glm::vec3 position,
|
||||
const glm::vec3 look,
|
||||
const float_t viewportHeight,
|
||||
const float_t fov
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the local position (position relative to "my parent").
|
||||
* @return The 3D local position in parent-relative space.
|
||||
*/
|
||||
glm::vec3 getLocalPosition();
|
||||
|
||||
/**
|
||||
* Update / Set the local position of this transform relative to my parent
|
||||
* @param position Position to set for the local transform.
|
||||
*/
|
||||
void setLocalPosition(const glm::vec3 position);
|
||||
|
||||
/**
|
||||
* Retusn the scale of this item, relative to my parent.
|
||||
* @return 3D Scale vector of this item in parent-relative space.
|
||||
*/
|
||||
glm::vec3 getLocalScale();
|
||||
|
||||
/**
|
||||
* Set the local scale of this item.
|
||||
* @param scale Scale of this item, relative to its parent.
|
||||
*/
|
||||
void setLocalScale(const glm::vec3 scale);
|
||||
|
||||
/**
|
||||
* Returns the local rotation for this transform.
|
||||
* @return The local rotation (parent-relative).
|
||||
*/
|
||||
glm::quat getLocalRotation();
|
||||
|
||||
/**
|
||||
* Set the local (parent-relative) rotation for this transform.
|
||||
* @param rotation Rotation in parent relative space.
|
||||
*/
|
||||
void setLocalRotation(const glm::quat rotation);
|
||||
|
||||
/**
|
||||
* Returns the transform matrix for this transform, in parent-relative
|
||||
* space.
|
||||
* @return The transform origin in parent-relative space.
|
||||
*/
|
||||
glm::mat4 getLocalTransform();
|
||||
|
||||
/**
|
||||
* Sets the local transform matrix for this transform.
|
||||
* @param transform Local (parent-relative) transform to set.
|
||||
*/
|
||||
void setLocalTransform(const glm::mat4 transform);
|
||||
|
||||
/**
|
||||
* Returns the position of the origin of this transform in world-space.
|
||||
*
|
||||
* @return Transform origin in world-space.
|
||||
*/
|
||||
glm::vec3 getWorldPosition();
|
||||
|
||||
/**
|
||||
* Returns the transformation matrix for this transform, in world-space.
|
||||
* @return The transform origin in world-space.
|
||||
*/
|
||||
glm::mat4 getWorldTransform();
|
||||
|
||||
/**
|
||||
* Updates the transform's world-space.
|
||||
* @param transform Sets the transform position in world-space.
|
||||
*/
|
||||
void setWorldTransform(const glm::mat4 transform);
|
||||
|
||||
/**
|
||||
* Updates the transform that this transform is a child of. Will also
|
||||
* handle disconnecting any existing parent.
|
||||
*
|
||||
* @param p Parent that this transform is now a child of.
|
||||
*/
|
||||
void setParent(const std::shared_ptr<SceneItem> p);
|
||||
|
||||
/**
|
||||
* Returns the parent transform of this transform, or nullptr if there is
|
||||
* no parent for this transform.
|
||||
* @return Pointer to the parent transform, or nullptr.
|
||||
*/
|
||||
std::shared_ptr<SceneItem> getParent();
|
||||
|
||||
/**
|
||||
* Returns true if this transform is a child of the given transform, this
|
||||
* climbs up the heirarchy until it finds a match.
|
||||
*
|
||||
* @param p Transform to check if this transform is a child of.
|
||||
* @return True if this transform is a child of the given transform.
|
||||
*/
|
||||
bool_t isChildOf(std::shared_ptr<SceneItem> p);
|
||||
|
||||
/**
|
||||
* Destroy this SceneItem.
|
||||
*/
|
||||
~SceneItem();
|
||||
};
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SceneItemComponent.hpp"
|
||||
#include "SceneItem.hpp"
|
||||
#include "Scene.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
SceneItemComponent::SceneItemComponent(const std::weak_ptr<SceneItem> item) :
|
||||
item(item)
|
||||
{
|
||||
}
|
||||
|
||||
void SceneItemComponent::init() {
|
||||
this->onStart();
|
||||
this->hasInitialized = true;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> SceneItemComponent::getDependencies() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr<Scene> SceneItemComponent::getScene() {
|
||||
auto scene = this->item.lock()->scene.lock();
|
||||
assertNotNull(scene, "Scene cannot be null!");
|
||||
return scene;
|
||||
}
|
||||
|
||||
std::shared_ptr<DawnGame> SceneItemComponent::getGame() {
|
||||
auto game = this->getScene()->game.lock();
|
||||
assertNotNull(game, "Game cannot be null!");
|
||||
return game;
|
||||
}
|
||||
|
||||
void SceneItemComponent::onStart() {
|
||||
|
||||
}
|
||||
|
||||
void SceneItemComponent::onDispose() {
|
||||
|
||||
}
|
||||
|
||||
void SceneItemComponent::onStateUpdate() {
|
||||
|
||||
}
|
||||
|
||||
SceneItemComponent::~SceneItemComponent() {
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "scene/SceneItem.hpp"
|
||||
#include "state/StateOwner.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class DawnGame;
|
||||
|
||||
class SceneItemComponent : public StateOwner {
|
||||
public:
|
||||
const std::weak_ptr<SceneItem> item;
|
||||
bool_t hasInitialized = false;
|
||||
|
||||
/**
|
||||
* Constructs a new SceneItemComponent. Components are attached to
|
||||
* SceneItems and will be individual responsibility components, and must
|
||||
* communicate to other items/components using methods and events.
|
||||
*
|
||||
* @param item Scene Item thsi component belongs to.
|
||||
*/
|
||||
SceneItemComponent(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/**
|
||||
* Requested on the first frame that the parent scene item has become
|
||||
* active, after all of my dependencies are ready.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Optionally return all dependencies for this component to wait for init
|
||||
* for before the component will be initialized.
|
||||
*
|
||||
* @return Array of dependencies.
|
||||
*/
|
||||
virtual std::vector<std::shared_ptr<SceneItemComponent>> getDependencies();
|
||||
|
||||
/**
|
||||
* Shorthand to return the scene that this component's item belongs to.
|
||||
* @return The current scene.
|
||||
*/
|
||||
std::shared_ptr<Scene> getScene();
|
||||
|
||||
/**
|
||||
* Shorthand to return the game that this scene belongs to.
|
||||
* @return The current game.
|
||||
*/
|
||||
std::shared_ptr<DawnGame> getGame();
|
||||
|
||||
/**
|
||||
* Same as init, but intended for your subclass to override.
|
||||
*/
|
||||
virtual void onStart();
|
||||
|
||||
/**
|
||||
* Intended for subclasses to detect when they need to clean themselves up
|
||||
* but before anything has been completely free'd from memory.
|
||||
*/
|
||||
virtual void onDispose();
|
||||
|
||||
virtual void onStateUpdate();
|
||||
|
||||
/**
|
||||
* Cleanup the SceneItemComponent.
|
||||
*/
|
||||
virtual ~SceneItemComponent();
|
||||
};
|
||||
|
||||
// Fowarded methods
|
||||
template<class T>
|
||||
std::shared_ptr<T> _sceneForwardGetComponent(
|
||||
std::shared_ptr<SceneItem> item
|
||||
) {
|
||||
return item->getComponent<T>();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::shared_ptr<T> _sceneForwardGetComponents(
|
||||
std::shared_ptr<SceneItem> item
|
||||
) {
|
||||
return item->getComponents<T>();
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Subdirs
|
||||
add_subdirectory(debug)
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(example)
|
||||
add_subdirectory(scene)
|
||||
add_subdirectory(ui)
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
FPSLabelComponent.cpp
|
||||
)
|
@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "FPSLabelComponent.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
FPSLabelComponent::FPSLabelComponent(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FPSLabelComponent::onStart() {
|
||||
useEvent([&](float_t delta){
|
||||
if(this->label == nullptr) return;
|
||||
std::string strFps = std::to_string((int32_t)(1.0f / delta));
|
||||
std::string strTick = std::to_string((int32_t)(delta * 1000.0f));
|
||||
assertUnreachable("FPSLabelComponent::onStart: Not yet implemented");// Needs updating to new UI Label
|
||||
// label->text = strFps + "FPS (" + strTick + "ms)";
|
||||
}, getScene()->eventSceneUnpausedUpdate);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/components/ui/text/UILabel.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class FPSLabelComponent : public SceneItemComponent {
|
||||
public:
|
||||
/* @optional */
|
||||
UILabel *label = nullptr;
|
||||
|
||||
FPSLabelComponent(std::weak_ptr<SceneItem> item);
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
Camera.cpp
|
||||
Material.cpp
|
||||
PixelPerfectCamera.cpp
|
||||
TiledSprite.cpp
|
||||
SimpleRenderTargetQuad.cpp
|
||||
CameraTexture.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(mesh)
|
@ -1,117 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Camera.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
Camera::Camera(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
renderTarget(this->getGame()->renderManager->getBackBuffer()),
|
||||
fov(0.785398f),// 45 degrees,
|
||||
type(CAMERA_TYPE_PERSPECTIVE),
|
||||
orthoLeft(-0.5f),
|
||||
orthoRight(0.5f),
|
||||
orthoBottom(-0.5f),
|
||||
orthoTop(0.5f),
|
||||
clipNear(0.001f),
|
||||
clipFar(1000.0f)
|
||||
{
|
||||
}
|
||||
|
||||
glm::mat4 Camera::getProjection() {
|
||||
if(this->projectionNeedsUpdating) {
|
||||
switch(this->type) {
|
||||
case CAMERA_TYPE_ORTHONOGRAPHIC:
|
||||
this->projection = glm::ortho(
|
||||
(float_t)this->orthoLeft,
|
||||
(float_t)this->orthoRight,
|
||||
(float_t)this->orthoBottom,
|
||||
(float_t)this->orthoTop,
|
||||
(float_t)this->clipNear,
|
||||
(float_t)this->clipFar
|
||||
);
|
||||
break;
|
||||
|
||||
case CAMERA_TYPE_PERSPECTIVE:
|
||||
this->projection = glm::perspective(
|
||||
(float_t)this->fov,
|
||||
this->getAspect(),
|
||||
(float_t)this->clipNear,
|
||||
(float_t)this->clipFar
|
||||
);
|
||||
break;
|
||||
}
|
||||
this->projectionNeedsUpdating = false;
|
||||
}
|
||||
|
||||
return this->projection;
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderTarget> Camera::getRenderTarget() {
|
||||
return this->renderTarget;
|
||||
}
|
||||
|
||||
float_t Camera::getAspect() {
|
||||
auto target = this->getRenderTarget();
|
||||
return target->getWidth() / target->getHeight();
|
||||
}
|
||||
|
||||
glm::vec3 Camera::getRayDirectionFromScreenSpace(glm::vec2 screenSpace) {
|
||||
glm::vec4 clipCoords(screenSpace.x, -screenSpace.y, -1.0f, 1.0f);
|
||||
glm::mat4 inverseProjectionMatrix = glm::inverse(this->projection);
|
||||
glm::vec4 eyeCoords = inverseProjectionMatrix * clipCoords;
|
||||
eyeCoords = glm::vec4(eyeCoords.x, eyeCoords.y, -1.0f, 0.0f);
|
||||
|
||||
glm::mat4 inverseViewMatrix = glm::inverse(item.lock()->getWorldTransform());
|
||||
glm::vec4 t = inverseViewMatrix * eyeCoords;
|
||||
|
||||
return glm::normalize(glm::vec3(t.x, t.y, t.z));
|
||||
}
|
||||
|
||||
void Camera::onStart() {
|
||||
useEffectWithTeardown([&]{
|
||||
auto rt = this->getRenderTarget();
|
||||
this->projectionNeedsUpdating = true;
|
||||
if(rt == nullptr) {
|
||||
return evtResized = [&]{
|
||||
|
||||
};
|
||||
}
|
||||
this->eventRenderTargetResized.invoke(rt->getWidth(), rt->getHeight());
|
||||
|
||||
// Subscribe to new render target resized.
|
||||
return evtResized = useEvent([&](
|
||||
RenderTarget &rt,
|
||||
const float_t w,
|
||||
const float_t h
|
||||
) {
|
||||
this->projectionNeedsUpdating = true;
|
||||
this->eventRenderTargetResized.invoke(w, h);
|
||||
}, rt->eventRenderTargetResized);
|
||||
}, renderTarget);
|
||||
|
||||
// All regular properties.
|
||||
useEffect([&]{
|
||||
this->projectionNeedsUpdating = true;
|
||||
}, {
|
||||
&fov, &type,
|
||||
&orthoLeft, &orthoRight, &orthoBottom, &orthoTop,
|
||||
&clipNear, &clipFar
|
||||
});
|
||||
|
||||
// Sub to evt legacy, we don't invoke the useTeardown to avoid invoking
|
||||
// the state event for this camera when we don't need to.
|
||||
if(!this->getRenderTarget()) return;
|
||||
evtResized = useEvent([&](
|
||||
RenderTarget &rt,
|
||||
const float_t w,
|
||||
const float_t h
|
||||
) {
|
||||
this->projectionNeedsUpdating = true;
|
||||
this->eventRenderTargetResized.invoke(w, h);
|
||||
}, getRenderTarget()->eventRenderTargetResized);
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "display/RenderTarget.hpp"
|
||||
#include "scene/Scene.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum CameraType {
|
||||
CAMERA_TYPE_ORTHONOGRAPHIC,
|
||||
CAMERA_TYPE_PERSPECTIVE
|
||||
};
|
||||
|
||||
class Camera : public SceneItemComponent {
|
||||
protected:
|
||||
bool_t projectionNeedsUpdating = true;
|
||||
glm::mat4 projection;
|
||||
std::function<void()> evtResized;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<Camera> create(std::shared_ptr<Scene> scene) {
|
||||
auto item = scene->createSceneItem();
|
||||
auto cam = item->addComponent<Camera>();
|
||||
return cam;
|
||||
}
|
||||
|
||||
// @optional
|
||||
StateProperty<std::shared_ptr<RenderTarget>> renderTarget;
|
||||
// @optional
|
||||
StateProperty<float_t> fov;
|
||||
// @optional
|
||||
StateProperty<enum CameraType> type;
|
||||
|
||||
// @optional
|
||||
StateProperty<float_t> orthoLeft;
|
||||
// @optional
|
||||
StateProperty<float_t> orthoRight;
|
||||
// @optional
|
||||
StateProperty<float_t> orthoBottom;
|
||||
// @optional
|
||||
StateProperty<float_t> orthoTop;
|
||||
// @optional
|
||||
StateProperty<float_t> clipNear;
|
||||
// @optional
|
||||
StateProperty<float_t> clipFar;
|
||||
|
||||
StateEvent<float_t, float_t> eventRenderTargetResized;
|
||||
|
||||
/**
|
||||
* Create a new Camera Component.
|
||||
*
|
||||
* @param item SceneItem that this component belongs to.
|
||||
*/
|
||||
Camera(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/**
|
||||
* Returns the current projection matrix.
|
||||
*
|
||||
* @return Projection matrix for this camera.
|
||||
*/
|
||||
glm::mat4 getProjection();
|
||||
|
||||
/**
|
||||
* Returns the intended render target for this camera to render to, will
|
||||
* automatically revert to the back buffer if no frame buffer is provided.
|
||||
*
|
||||
* @return The target render target framebuffer.
|
||||
*/
|
||||
std::shared_ptr<RenderTarget> getRenderTarget();
|
||||
|
||||
/**
|
||||
* Returs the aspect ratio of the camera.
|
||||
*
|
||||
* @return The aspect ratio of the camera.
|
||||
*/
|
||||
float_t getAspect();
|
||||
|
||||
/**
|
||||
* Creates the directional vector for a given point on the screen space
|
||||
* coordinates provided. This is useful if you want to, say, cast a ray
|
||||
* based on a position on the screen. The directional vector is normalized
|
||||
* between -1 and 1 where -1 is the near clipping plane, and 1 is the
|
||||
* far clipping plane.
|
||||
*
|
||||
* @param screenSpace Screen space vector (-1,-1 to 1,1) on the screen.
|
||||
* @return The vector for the direction to cast from.
|
||||
*/
|
||||
glm::vec3 getRayDirectionFromScreenSpace(glm::vec2 screenSpace);
|
||||
|
||||
/**
|
||||
* Event triggered by the scene item when the item is added to the scene.
|
||||
*/
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "CameraTexture.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
CameraTexture::CameraTexture(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
camera(nullptr)
|
||||
{
|
||||
renderTarget = std::make_shared<TextureRenderTarget>(32, 32);
|
||||
}
|
||||
|
||||
void CameraTexture::onStart() {
|
||||
if(this->camera == nullptr) this->camera = item.lock()->getComponent<Camera>();
|
||||
|
||||
useEffect([&]{
|
||||
if(this->camera == nullptr) return;
|
||||
this->camera->renderTarget = this->renderTarget;
|
||||
}, camera)();
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/components/display/Camera.hpp"
|
||||
#include "display/TextureRenderTarget.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class CameraTexture : public SceneItemComponent {
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<std::shared_ptr<Camera>> camera;
|
||||
std::shared_ptr<TextureRenderTarget> renderTarget;
|
||||
|
||||
CameraTexture(std::weak_ptr<SceneItem> item);
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class Scene;
|
||||
class Camera;
|
||||
class RenderPipeline;
|
||||
|
||||
struct IRenderableContext {
|
||||
std::shared_ptr<Scene> scene;
|
||||
std::shared_ptr<Camera> camera;
|
||||
std::shared_ptr<RenderPipeline> renderPipeline;
|
||||
};
|
||||
|
||||
class IRenderable {
|
||||
public:
|
||||
/**
|
||||
* Returns the render passes for this renderable item, typically a scene
|
||||
* item component, e.g. a Material or a UI Item.
|
||||
*
|
||||
* @param context Context about the current renderer state.
|
||||
* @return Array of renderable passes.
|
||||
*/
|
||||
virtual std::vector<struct ShaderPassItem> getRenderPasses(
|
||||
struct IRenderableContext &context
|
||||
) = 0;
|
||||
};
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "Material.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
Material::Material(std::weak_ptr<SceneItem> item) : SceneItemComponent(item) {
|
||||
}
|
||||
|
||||
ShaderManager & Material::getShaderManager() {
|
||||
return *this->getGame()->renderManager->getShaderManager();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "display/shader/ShaderManager.hpp"
|
||||
#include "scene/components/display/IRenderable.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class Material : public SceneItemComponent, public IRenderable {
|
||||
public:
|
||||
/**
|
||||
* Material component constructor.
|
||||
*
|
||||
* @param item Scene Item this component belongs to.
|
||||
*/
|
||||
Material(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/**
|
||||
* Returns the shader manager for the game.
|
||||
* @return The shader manager for the game.
|
||||
*/
|
||||
ShaderManager & getShaderManager();
|
||||
};
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PixelPerfectCamera.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
PixelPerfectCamera::PixelPerfectCamera(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
scale(1.0f),
|
||||
camera(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PixelPerfectCamera::updateDimensions() {
|
||||
if(this->camera == nullptr) return;
|
||||
|
||||
float_t w, h;
|
||||
|
||||
auto target = this->camera->getRenderTarget();
|
||||
switch(this->camera->type) {
|
||||
case CAMERA_TYPE_ORTHONOGRAPHIC:
|
||||
w = target->getWidth() / 2.0f / (float_t)this->scale;
|
||||
h = target->getHeight() / 2.0f / (float_t)this->scale;
|
||||
camera->orthoLeft = -w;
|
||||
camera->orthoRight = w;
|
||||
camera->orthoTop = h;
|
||||
camera->orthoBottom = -h;
|
||||
break;
|
||||
|
||||
case CAMERA_TYPE_PERSPECTIVE:
|
||||
item.lock()->lookAtPixelPerfect(
|
||||
glm::vec3(0, 0, 0),
|
||||
glm::vec3(0, 0, 0),
|
||||
target->getHeight() / this->scale,
|
||||
this->camera->fov
|
||||
);
|
||||
// this->lookAt(glm::vec3(360, 360, 360), glm::vec3(0, 0, 0));
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("PixelPerfectCamera::updateDimensions: Unknown camera type");
|
||||
}
|
||||
}
|
||||
|
||||
void PixelPerfectCamera::onStart() {
|
||||
if(camera == nullptr) camera = item.lock()->getComponent<Camera>();
|
||||
|
||||
useEffect([&]{
|
||||
this->updateDimensions();
|
||||
}, scale);
|
||||
|
||||
useEffectWithTeardown([&]{
|
||||
if(!camera._realValue) {
|
||||
return teardown = [&]{};
|
||||
}
|
||||
|
||||
this->updateDimensions();
|
||||
|
||||
return teardown = [&]{
|
||||
useEvent([&](float_t w, float_t h){
|
||||
this->updateDimensions();
|
||||
}, this->camera->eventRenderTargetResized);
|
||||
};
|
||||
}, camera)();
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "Camera.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class PixelPerfectCamera : public SceneItemComponent {
|
||||
protected:
|
||||
std::function<void()> teardown;
|
||||
|
||||
/**
|
||||
* Updates the underlying camera's projection information.
|
||||
*/
|
||||
void updateDimensions();
|
||||
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<std::shared_ptr<Camera>> camera;
|
||||
|
||||
// @optional
|
||||
StateProperty<float_t> scale;
|
||||
|
||||
/**
|
||||
* Create a new PixelPerfectCamera Component.
|
||||
*
|
||||
* @param item Item that this component belongs to.
|
||||
*/
|
||||
PixelPerfectCamera(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SimpleRenderTargetQuad.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
SimpleRenderTargetQuad::SimpleRenderTargetQuad(std::weak_ptr<SceneItem> i) :
|
||||
SceneItemComponent(i),
|
||||
renderTarget(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> SimpleRenderTargetQuad::getDependencies() {
|
||||
return {
|
||||
(this->meshHost = this->item.lock()->getComponent<MeshHost>())
|
||||
};
|
||||
}
|
||||
|
||||
void SimpleRenderTargetQuad::onStart() {
|
||||
assertNotNull(this->meshHost, "SimpleRenderTargetQuad::onStart: MeshHost cannot be null");
|
||||
|
||||
// Create quad mesh
|
||||
this->meshHost->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
|
||||
|
||||
// Create teardown effect and keep track.
|
||||
auto initial = useEffectWithTeardown([&]{
|
||||
// No teardown needed.
|
||||
if(this->renderTarget == nullptr) return evtResized = [&]{ };
|
||||
|
||||
// Update mesh
|
||||
QuadMesh::bufferQuadMesh(
|
||||
this->meshHost->mesh,
|
||||
glm::vec2(0, 0), glm::vec2(0, 0),
|
||||
glm::vec2(
|
||||
this->renderTarget._realValue->getWidth(),
|
||||
this->renderTarget._realValue->getHeight()
|
||||
),
|
||||
glm::vec2(1, 1),
|
||||
0, 0
|
||||
);
|
||||
|
||||
// Subscribe to resize event.
|
||||
evtResized = useEvent([&](
|
||||
RenderTarget &target,
|
||||
const float_t w,
|
||||
const float_t h
|
||||
) {
|
||||
QuadMesh::bufferQuadMesh(
|
||||
this->meshHost->mesh,
|
||||
glm::vec2(0, 0), glm::vec2(0, 0),
|
||||
glm::vec2(w, h), glm::vec2(1, 1),
|
||||
0, 0
|
||||
);
|
||||
}, this->renderTarget->eventRenderTargetResized);
|
||||
|
||||
// Teardown
|
||||
return evtResized;
|
||||
}, this->renderTarget);
|
||||
|
||||
// Invoke immediate
|
||||
initial();
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/components/display/mesh/MeshHost.hpp"
|
||||
#include "display/RenderTarget.hpp"
|
||||
#include "display/mesh/QuadMesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class SimpleRenderTargetQuad : public SceneItemComponent {
|
||||
protected:
|
||||
std::shared_ptr<MeshHost> meshHost;
|
||||
std::function<void()> evtResized;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<RenderTarget*> renderTarget;
|
||||
|
||||
/**
|
||||
* Creates a SimpleRenderTargetQuad scene item component. This component
|
||||
* will update the attached MeshHost any time the render target provided
|
||||
* is updated / resized.
|
||||
*
|
||||
* @param item Item that this component is attached to.
|
||||
*/
|
||||
SimpleRenderTargetQuad(std::weak_ptr<SceneItem> item);
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> getDependencies() override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "TiledSprite.hpp"
|
||||
#include "scene/SceneItem.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
TiledSprite::TiledSprite(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
tile(-1),
|
||||
tileset(nullptr),
|
||||
meshHost(nullptr),
|
||||
flip(TILED_SPRITE_FLIP_Y),
|
||||
sizeType(TILED_SPRITE_SIZE_TYPE_SCALE),
|
||||
size(1.0f)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> TiledSprite::getDependencies() {
|
||||
if(this->meshHost == nullptr) {
|
||||
this->meshHost = item.lock()->getComponent<QuadMeshHost>();
|
||||
}
|
||||
|
||||
return { this->meshHost._realValue };
|
||||
}
|
||||
|
||||
void TiledSprite::onStart() {
|
||||
SceneItemComponent::onStart();
|
||||
|
||||
useEffect([&]{
|
||||
if(this->meshHost == nullptr || this->tileset == nullptr) return;
|
||||
auto tile = this->tileset->getTile(this->tile);
|
||||
this->meshHost->uv0 = glm::vec2(
|
||||
(((flag_t)this->flip) & TILED_SPRITE_FLIP_X) == 0 ? tile.uv0.x : tile.uv1.x,
|
||||
(((flag_t)this->flip) & TILED_SPRITE_FLIP_Y) == 0 ? tile.uv0.y : tile.uv1.y
|
||||
);
|
||||
this->meshHost->uv1 = glm::vec2(
|
||||
(((flag_t)this->flip) & TILED_SPRITE_FLIP_X) == 0 ? tile.uv1.x : tile.uv0.x,
|
||||
(((flag_t)this->flip) & TILED_SPRITE_FLIP_Y) == 0 ? tile.uv1.y : tile.uv0.y
|
||||
);
|
||||
}, {
|
||||
&this->tile,
|
||||
&this->meshHost,
|
||||
&this->tileset,
|
||||
&this->flip
|
||||
})();
|
||||
|
||||
useEffect([&]{
|
||||
if(this->meshHost == nullptr || this->tileset == nullptr) return;
|
||||
auto tile = this->tileset->getTile(this->tile);
|
||||
|
||||
glm::vec2 quadSize;
|
||||
|
||||
switch(this->sizeType) {
|
||||
case TILED_SPRITE_SIZE_TYPE_SCALE: {
|
||||
quadSize = glm::vec2(
|
||||
this->tileset->getTileWidth(this->tile),
|
||||
this->tileset->getTileHeight(this->tile)
|
||||
) * (float_t)this->size;
|
||||
break;
|
||||
}
|
||||
|
||||
case TILED_SPRITE_SIZE_TYPE_WIDTH_RATIO: {
|
||||
float_t rw = this->tileset->getTileHeight(this->tile) / this->tileset->getTileWidth(this->tile);
|
||||
quadSize.x = (float_t)this->size;
|
||||
quadSize.y = quadSize.x * rw;
|
||||
break;
|
||||
}
|
||||
|
||||
case TILED_SPRITE_SIZE_TYPE_HEIGHT_RATIO: {
|
||||
float_t rh = this->tileset->getTileWidth(this->tile) / this->tileset->getTileHeight(this->tile);
|
||||
quadSize.y = (float_t)this->size;
|
||||
quadSize.x = quadSize.y * rh;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertUnreachable("TiledSprite::onStart: Size type not implemented");
|
||||
}
|
||||
|
||||
this->meshHost->xy0 = -quadSize;
|
||||
this->meshHost->xy1 = quadSize;
|
||||
}, {
|
||||
&this->tile,
|
||||
&this->meshHost,
|
||||
&this->tileset,
|
||||
&this->size
|
||||
})();
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "util/flag.hpp"
|
||||
#include "display/Tileset.hpp"
|
||||
#include "scene/components/display/mesh/QuadMeshHost.hpp"
|
||||
|
||||
#define TILED_SPRITE_FLIP_Y FLAG_DEFINE(1)
|
||||
#define TILED_SPRITE_FLIP_X FLAG_DEFINE(2)
|
||||
|
||||
namespace Dawn {
|
||||
enum TiledSpriteSizeType {
|
||||
TILED_SPRITE_SIZE_TYPE_SCALE,
|
||||
TILED_SPRITE_SIZE_TYPE_WIDTH_RATIO,
|
||||
TILED_SPRITE_SIZE_TYPE_HEIGHT_RATIO
|
||||
};
|
||||
|
||||
class TiledSprite : public SceneItemComponent {
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<Tileset*> tileset;
|
||||
// @optional
|
||||
StateProperty<std::shared_ptr<QuadMeshHost>> meshHost;
|
||||
// @optional
|
||||
StateProperty<int32_t> tile;
|
||||
// @optional
|
||||
StateProperty<flag_t> flip;
|
||||
// @optional
|
||||
StateProperty<enum TiledSpriteSizeType> sizeType;
|
||||
// @optional
|
||||
StateProperty<float_t> size;
|
||||
|
||||
TiledSprite(std::weak_ptr<SceneItem> item);
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> getDependencies();
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
MeshRenderer.cpp
|
||||
CubeMeshHost.cpp
|
||||
CapsuleMeshHost.cpp
|
||||
QuadMeshHost.cpp
|
||||
MeshHost.cpp
|
||||
)
|
@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "CapsuleMeshHost.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
CapsuleMeshHost::CapsuleMeshHost(std::weak_ptr<SceneItem> item) :
|
||||
MeshHost(item),
|
||||
radius(0.5f),
|
||||
height(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
void CapsuleMeshHost::onStart() {
|
||||
useEffect([&]{
|
||||
CapsuleMesh::create(this->mesh, radius, height);
|
||||
}, { &this->radius, &this->height })();
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "MeshHost.hpp"
|
||||
#include "display/mesh/CapsuleMesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class CapsuleMeshHost : public MeshHost {
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<float> radius;
|
||||
// @optional
|
||||
StateProperty<float> height;
|
||||
|
||||
CapsuleMeshHost(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "CubeMeshHost.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
CubeMeshHost::CubeMeshHost(std::weak_ptr<SceneItem> item) :
|
||||
MeshHost(item),
|
||||
size(glm::vec3(1,1,1))
|
||||
{
|
||||
}
|
||||
|
||||
void CubeMeshHost::onStart() {
|
||||
this->mesh.createBuffers(
|
||||
CUBE_VERTICE_COUNT,
|
||||
CUBE_INDICE_COUNT
|
||||
);
|
||||
|
||||
useEffect([&]{
|
||||
CubeMesh::buffer(
|
||||
this->mesh,
|
||||
glm::vec3(this->size) * -0.5f,
|
||||
this->size,
|
||||
0,
|
||||
0
|
||||
);
|
||||
}, this->size)();
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "MeshHost.hpp"
|
||||
#include "display/mesh/CubeMesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class CubeMeshHost : public MeshHost {
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<glm::vec3> size;
|
||||
|
||||
CubeMeshHost(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "MeshHost.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
MeshHost::MeshHost(std::weak_ptr<SceneItem> item) :
|
||||
mesh(),
|
||||
SceneItemComponent(item)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class MeshHost : public SceneItemComponent {
|
||||
public:
|
||||
Mesh mesh;
|
||||
|
||||
MeshHost(std::weak_ptr<SceneItem> item);
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "MeshRenderer.hpp"
|
||||
#include "MeshHost.hpp"
|
||||
#include "scene/SceneItem.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
MeshRenderer::MeshRenderer(std::weak_ptr<SceneItem> item) : SceneItemComponent(item) {
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> MeshRenderer::getDependencies() {
|
||||
return {
|
||||
meshHost = item.lock()->getComponent<MeshHost>()
|
||||
};
|
||||
}
|
||||
|
||||
void MeshRenderer::onStart() {
|
||||
SceneItemComponent::onStart();
|
||||
|
||||
if(this->mesh == nullptr && this->meshHost != nullptr) {
|
||||
this->mesh = &this->meshHost->mesh;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class MeshHost;
|
||||
|
||||
class MeshRenderer : public SceneItemComponent {
|
||||
protected:
|
||||
std::shared_ptr<MeshHost> meshHost;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
Mesh * mesh = nullptr;
|
||||
|
||||
/**
|
||||
* Constructs a MeshRenderer scene item component.
|
||||
*
|
||||
* @param item Scene Item this mesh renderer belongs to.
|
||||
*/
|
||||
MeshRenderer(std::weak_ptr<SceneItem> item);
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> getDependencies() override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "QuadMeshHost.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
QuadMeshHost::QuadMeshHost(std::weak_ptr<SceneItem> item) :
|
||||
xy0(glm::vec2(-0.5f, -0.5f)), xy1(glm::vec2(0.5f, 0.5f)),
|
||||
uv0(glm::vec2(0, 0)), uv1(glm::vec2(1, 1)),
|
||||
MeshHost(item)
|
||||
{
|
||||
}
|
||||
|
||||
void QuadMeshHost::onStart() {
|
||||
this->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
|
||||
|
||||
useEffect([&]{
|
||||
QuadMesh::bufferQuadMesh(
|
||||
this->mesh,
|
||||
glm::vec2(this->xy0),
|
||||
glm::vec2(this->uv0),
|
||||
glm::vec2(this->xy1),
|
||||
glm::vec2(this->uv1),
|
||||
0, 0
|
||||
);
|
||||
}, { &this->xy0, &this->xy1, &this->uv0, &this->uv1 })();
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "MeshHost.hpp"
|
||||
#include "display/mesh/QuadMesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class QuadMeshHost : public MeshHost {
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<glm::vec2> xy0;
|
||||
// @optional
|
||||
StateProperty<glm::vec2> xy1;
|
||||
// @optional
|
||||
StateProperty<glm::vec2> uv0;
|
||||
// @optional
|
||||
StateProperty<glm::vec2> uv1;
|
||||
|
||||
QuadMeshHost(std::weak_ptr<SceneItem> item);
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
ExampleSpin.cpp
|
||||
)
|
@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "ExampleSpin.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
#include "scene/components/display/mesh/MeshRenderer.hpp"
|
||||
#include "display/mesh/CubeMesh.hpp"
|
||||
#include "scene/components/display/material/SimpleTexturedMaterial.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
std::shared_ptr<SceneItem> ExampleSpin::create(Scene *scene) {
|
||||
auto item = scene->createSceneItem();
|
||||
auto mr = item->addComponent<MeshRenderer>();
|
||||
mr->mesh = new Mesh();
|
||||
mr->mesh->createBuffers(CUBE_VERTICE_COUNT, CUBE_INDICE_COUNT);
|
||||
CubeMesh::buffer(
|
||||
*mr->mesh,
|
||||
glm::vec3(-0.5f, -0.5f, -0.5f),
|
||||
glm::vec3(1, 1, 1),
|
||||
0,
|
||||
0
|
||||
);
|
||||
auto mat = item->addComponent<SimpleTexturedMaterial>();
|
||||
item->addComponent<ExampleSpin>();
|
||||
return item;
|
||||
}
|
||||
|
||||
ExampleSpin::ExampleSpin(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item)
|
||||
{
|
||||
}
|
||||
|
||||
void ExampleSpin::onStart() {
|
||||
useEvent([&](float_t delta){
|
||||
auto i = item.lock();
|
||||
auto quat = i->getLocalRotation();
|
||||
quat = glm::rotate(quat, delta, glm::vec3(0, 1, 0));
|
||||
quat = glm::rotate(quat, delta / 2.0f, glm::vec3(1, 0, 0));
|
||||
quat = glm::rotate(quat, delta / 4.0f, glm::vec3(0, 0, 1));
|
||||
i->setLocalRotation(quat);
|
||||
}, getScene()->eventSceneUnpausedUpdate);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "display/shader/Shader.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class ExampleSpin : public SceneItemComponent {
|
||||
public:
|
||||
static std::shared_ptr<SceneItem> create(Scene *scene);
|
||||
|
||||
ExampleSpin(std::weak_ptr<SceneItem> item);
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
SubSceneCameraAlign.cpp
|
||||
SubSceneController.cpp
|
||||
)
|
@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SubSceneCameraAlign.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
SubSceneCameraAlign::SubSceneCameraAlign(std::weak_ptr<SceneItem> i) :
|
||||
SceneItemComponent(i),
|
||||
camera(nullptr),
|
||||
renderTarget(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void SubSceneCameraAlign::realign() {
|
||||
float_t diff;
|
||||
if(this->camera == nullptr) return;
|
||||
if(this->renderTarget == nullptr) return;
|
||||
|
||||
float_t ratio = this->renderTarget->getWidth() / this->renderTarget->getHeight();
|
||||
float_t myRatio = this->camera->getAspect();
|
||||
|
||||
this->camera->type = CAMERA_TYPE_ORTHONOGRAPHIC;
|
||||
this->camera->item.lock()->lookAt(glm::vec3(0, 0, 10), glm::vec3(0, 0, 0));
|
||||
|
||||
if(ratio > myRatio) {
|
||||
// My Ratio is narrower
|
||||
this->camera->orthoLeft = 0;
|
||||
this->camera->orthoRight = this->renderTarget->getWidth();
|
||||
diff = (this->renderTarget->getHeight() - (this->renderTarget->getWidth() / myRatio)) / 2.0f;
|
||||
this->camera->orthoTop = this->renderTarget->getHeight() - diff;
|
||||
this->camera->orthoBottom = diff;
|
||||
} else {
|
||||
// My ratio is wider
|
||||
this->camera->orthoBottom = 0;
|
||||
this->camera->orthoTop = this->renderTarget->getHeight();
|
||||
diff = (this->renderTarget->getWidth() - (this->renderTarget->getHeight() * myRatio)) / 2.0f;
|
||||
this->camera->orthoLeft = diff;
|
||||
this->camera->orthoRight = this->renderTarget->getWidth() - diff;
|
||||
}
|
||||
}
|
||||
|
||||
void SubSceneCameraAlign::onStart() {
|
||||
auto cameraEffect = useEffectWithTeardown([&]{
|
||||
if(camera == nullptr) return evtCameraResized = [&] {};
|
||||
|
||||
this->realign();
|
||||
|
||||
return evtCameraResized = useEvent([&](float_t w, float_t h){
|
||||
this->realign();
|
||||
}, this->camera->eventRenderTargetResized);
|
||||
}, this->camera);
|
||||
|
||||
auto renderEffect = useEffectWithTeardown([&]{
|
||||
if(renderTarget == nullptr) return evtRenderResized = [&]{};
|
||||
|
||||
this->realign();
|
||||
|
||||
return evtRenderResized = useEvent([&](
|
||||
RenderTarget &rt,
|
||||
const float_t w,
|
||||
const float_t h
|
||||
) {
|
||||
this->realign();
|
||||
}, renderTarget->eventRenderTargetResized);
|
||||
}, this->renderTarget);
|
||||
|
||||
cameraEffect();
|
||||
renderEffect();
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/Scene.hpp"
|
||||
#include "display/TextureRenderTarget.hpp"
|
||||
#include "scene/components/display/Camera.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class SubSceneCameraAlign : public SceneItemComponent {
|
||||
protected:
|
||||
std::function<void()> evtCameraResized;
|
||||
std::function<void()> evtRenderResized;
|
||||
|
||||
/**
|
||||
* Realigns the camera to match the render target quad.
|
||||
*/
|
||||
void realign();
|
||||
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<Camera*> camera;
|
||||
// @optional
|
||||
StateProperty<TextureRenderTarget*> renderTarget;
|
||||
|
||||
/**
|
||||
* Create the sub scene camera align component. This will align a camera
|
||||
* to match a render target quad (Refer SimpleRenderTargetQuad)
|
||||
*
|
||||
* @param item Scene Item that this component belongs to.
|
||||
*/
|
||||
SubSceneCameraAlign(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SubSceneController.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
SubSceneController::SubSceneController(std::weak_ptr<SceneItem> i) : SceneItemComponent(i) {
|
||||
|
||||
}
|
||||
|
||||
void SubSceneController::onStart() {
|
||||
auto myScene = this->getScene();
|
||||
|
||||
useEvent([&](float_t d){
|
||||
if(!this->onlyUpdateUnpaused) return;
|
||||
if(this->subScene == nullptr) return;
|
||||
this->subScene->update();
|
||||
}, myScene->eventSceneUnpausedUpdate);
|
||||
|
||||
useEvent([&](float_t d){
|
||||
if(this->onlyUpdateUnpaused) return;
|
||||
if(this->subScene == nullptr) return;
|
||||
this->subScene->update();
|
||||
}, myScene->eventSceneUpdate);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class SubSceneController : public SceneItemComponent {
|
||||
public:
|
||||
// @optional
|
||||
std::shared_ptr<Scene> subScene = nullptr;
|
||||
// @optional
|
||||
bool_t onlyUpdateUnpaused = false;
|
||||
|
||||
SubSceneController(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
UICanvas.cpp
|
||||
UIComponent.cpp
|
||||
UIComponentRenderable.cpp
|
||||
UIImage.cpp
|
||||
UIEmpty.cpp
|
||||
UIBorder.cpp
|
||||
UIMesh.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(menu)
|
||||
add_subdirectory(text)
|
@ -1,122 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIBorder.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIBorder::UIBorder(std::weak_ptr<SceneItem> item) :
|
||||
texture(nullptr),
|
||||
borderSize(glm::vec2(8, 8)),
|
||||
UIComponentRenderable(item)
|
||||
{
|
||||
}
|
||||
|
||||
float_t UIBorder::getContentWidth() {
|
||||
return this->width - this->borderSize._realValue.x * 2.0f;
|
||||
}
|
||||
|
||||
float_t UIBorder::getContentHeight() {
|
||||
return this->height - this->borderSize._realValue.y * 2.0f;
|
||||
}
|
||||
|
||||
float_t UIBorder::getChildOffsetX() {
|
||||
return this->borderSize._realValue.x;
|
||||
}
|
||||
|
||||
float_t UIBorder::getChildOffsetY() {
|
||||
return this->borderSize._realValue.y;
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> UIBorder::getUIRenderPasses() {
|
||||
struct ShaderPassItem item;
|
||||
auto shader = getGame()->renderManager->uiShader;
|
||||
item.shader = shader;
|
||||
item.colorValues[shader->paramColor] = COLOR_WHITE;
|
||||
item.parameterBuffers[shader->bufferUiCanvas] = &this->getCanvas()->shaderBuffer;
|
||||
item.matrixValues[shader->paramModel] = this->item.lock()->getWorldTransform();
|
||||
if(this->texture == nullptr) {
|
||||
item.boolValues[shader->paramHasTexture] = false;
|
||||
} else {
|
||||
item.boolValues[shader->paramHasTexture] = true;
|
||||
item.textureSlots[0] = this->texture;
|
||||
item.textureValues[shader->paramTexture] = 0;
|
||||
}
|
||||
item.w = this->item.lock()->getWorldPosition().z;
|
||||
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
|
||||
item.mesh = &mesh;
|
||||
|
||||
return { item };
|
||||
}
|
||||
|
||||
void UIBorder::onStart() {
|
||||
UIComponent::onStart();
|
||||
|
||||
auto rebufferQuad = [&] {
|
||||
glm::vec2 tSize = glm::vec2(1, 1) / 3.0f;
|
||||
glm::vec2 bSize = (glm::vec2)borderSize;
|
||||
glm::vec2 iSize = glm::vec2(this->getWidth(), this->getHeight()) - ( bSize * 2.0f );
|
||||
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(0, 0), glm::vec2(0, 0),
|
||||
bSize, tSize,
|
||||
0, 0
|
||||
);
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(bSize.x, 0), glm::vec2(tSize.x, 0),
|
||||
glm::vec2(iSize.x + bSize.x, bSize.y), glm::vec2(tSize.x * 2, tSize.y),
|
||||
QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT
|
||||
);
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(iSize.x + bSize.x, 0), glm::vec2(tSize.x + tSize.x, 0),
|
||||
glm::vec2(this->getWidth(), bSize.y), glm::vec2(1.0f, tSize.y),
|
||||
2 * QUAD_VERTICE_COUNT, 2 * QUAD_INDICE_COUNT
|
||||
);
|
||||
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(0, bSize.y), glm::vec2(0, tSize.y),
|
||||
bSize + glm::vec2(0, iSize.y), tSize + glm::vec2(0, tSize.y),
|
||||
3 * QUAD_VERTICE_COUNT, 3 * QUAD_INDICE_COUNT
|
||||
);
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
bSize, tSize,
|
||||
bSize + iSize, tSize + tSize,
|
||||
4 * QUAD_VERTICE_COUNT, 4 * QUAD_INDICE_COUNT
|
||||
);
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(iSize.x + bSize.x, bSize.y), tSize + glm::vec2(tSize.x, 0),
|
||||
glm::vec2(this->getWidth(), bSize.y + iSize.y), glm::vec2(1.0f, tSize.y + tSize.y),
|
||||
5 * QUAD_VERTICE_COUNT, 5 * QUAD_INDICE_COUNT
|
||||
);
|
||||
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(0, iSize.y + bSize.y), glm::vec2(0, tSize.y + tSize.y),
|
||||
glm::vec2(bSize.x, this->getHeight()), glm::vec2(tSize.x, 1.0f),
|
||||
6 * QUAD_VERTICE_COUNT, 6 * QUAD_INDICE_COUNT
|
||||
);
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
glm::vec2(bSize.x, iSize.y + bSize.y), glm::vec2(tSize.x, tSize.y + tSize.y),
|
||||
glm::vec2(iSize.x + bSize.x, this->getHeight()), glm::vec2(tSize.x * 2, 1.0f),
|
||||
7 * QUAD_VERTICE_COUNT, 7 * QUAD_INDICE_COUNT
|
||||
);
|
||||
QuadMesh::bufferQuadMesh(mesh,
|
||||
bSize + iSize, tSize + tSize,
|
||||
glm::vec2(this->getWidth(), this->getHeight()), glm::vec2(1.0f, 1.0f),
|
||||
8 * QUAD_VERTICE_COUNT, 8 * QUAD_INDICE_COUNT
|
||||
);
|
||||
};
|
||||
|
||||
this->mesh.createBuffers(
|
||||
QUAD_VERTICE_COUNT * UI_BORDER_QUAD_COUNT,
|
||||
QUAD_INDICE_COUNT * UI_BORDER_QUAD_COUNT
|
||||
);
|
||||
rebufferQuad();
|
||||
|
||||
useEvent(rebufferQuad, this->eventAlignmentUpdated);
|
||||
useEffect([&]{
|
||||
this->alignmentNeedsUpdating = true;
|
||||
}, this->borderSize);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UIComponentRenderable.hpp"
|
||||
#include "display/mesh/QuadMesh.hpp"
|
||||
|
||||
#define UI_BORDER_QUAD_COUNT 9
|
||||
|
||||
namespace Dawn {
|
||||
class UIBorder : public UIComponentRenderable {
|
||||
private:
|
||||
Mesh mesh;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<glm::vec2> borderSize;
|
||||
// @optional
|
||||
StateProperty<Texture*> texture;
|
||||
|
||||
UIBorder(std::weak_ptr<SceneItem> item);
|
||||
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
float_t getChildOffsetX() override;
|
||||
float_t getChildOffsetY() override;
|
||||
std::vector<struct ShaderPassItem> getUIRenderPasses() override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UICanvas.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
#include "UIComponent.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
std::shared_ptr<UICanvas> UICanvas::create(Scene *scene) {
|
||||
auto item = scene->createSceneItem();
|
||||
return item->addComponent<UICanvas>();
|
||||
}
|
||||
|
||||
UICanvas::UICanvas(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
camera(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void UICanvas::rebufferShaderParameters() {
|
||||
struct UICanvasShaderBufferData data;
|
||||
|
||||
switch(this->drawType) {
|
||||
case UI_DRAW_TYPE_WORLD_ABSOLUTE:
|
||||
data.projection = camera->getProjection();
|
||||
data.view = camera->item.lock()->getWorldTransform();
|
||||
break;
|
||||
|
||||
case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE:
|
||||
data.projection = glm::ortho(
|
||||
0.0f,
|
||||
camera->getRenderTarget()->getWidth() / this->getScale(),
|
||||
camera->getRenderTarget()->getHeight() / this->getScale(),
|
||||
0.0f
|
||||
);
|
||||
data.view = glm::mat4(1.0f);
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("UICanvas::rebufferShaderParameters: Unknown draw type");
|
||||
}
|
||||
|
||||
this->shaderBuffer.buffer(&data);
|
||||
}
|
||||
|
||||
float_t UICanvas::getScale() {
|
||||
return this->camera->getRenderTarget()->getScale();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
float_t UICanvas::getChildOffsetX() {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float_t UICanvas::getChildOffsetY() {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void UICanvas::onStart() {
|
||||
if(camera == nullptr) camera = getScene()->findComponent<Camera>();
|
||||
|
||||
this->shaderBuffer.init();
|
||||
this->rebufferShaderParameters();
|
||||
|
||||
useEffectWithTeardown([&]{
|
||||
if(camera == nullptr) return evtRenderResize = [&] {};
|
||||
this->w = camera->getRenderTarget()->getWidth() / this->getScale();
|
||||
this->h = camera->getRenderTarget()->getHeight() / this->getScale();
|
||||
this->rebufferShaderParameters();
|
||||
|
||||
return evtRenderResize = useEvent([&](float_t w, float_t h){
|
||||
this->w = w / this->getScale();
|
||||
this->h = h / this->getScale();
|
||||
this->rebufferShaderParameters();
|
||||
|
||||
auto comps = this->item.lock()->findChildren<UIComponent>();
|
||||
auto itComps = comps.begin();
|
||||
while(itComps != comps.end()) {
|
||||
(*itComps)->alignmentNeedsUpdating = true;
|
||||
++itComps;
|
||||
}
|
||||
}, camera->eventRenderTargetResized);
|
||||
}, camera)();
|
||||
}
|
||||
|
||||
void UICanvas::onDispose() {
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "display/RenderTarget.hpp"
|
||||
#include "scene/components/display/Camera.hpp"
|
||||
#include "display/shader/shaders/UIShader.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIComponentDimensional {
|
||||
public:
|
||||
/**
|
||||
* Returns the width of this dimensional UI item.
|
||||
*
|
||||
* @return Width of this item.
|
||||
*/
|
||||
virtual float_t getWidth() = 0;
|
||||
|
||||
/**
|
||||
* Returns the height of this dimensional UI item.
|
||||
*
|
||||
* @return Height of this item.
|
||||
*/
|
||||
virtual float_t getHeight() = 0;
|
||||
|
||||
/**
|
||||
* Returns the content width of this dimensional UI item.
|
||||
*
|
||||
* @return Content width of this item.
|
||||
*/
|
||||
virtual float_t getContentWidth() = 0;
|
||||
|
||||
/**
|
||||
* Returns the content height of this dimensional UI item.
|
||||
*
|
||||
* @return Content height of this item.
|
||||
*/
|
||||
virtual float_t getContentHeight() = 0;
|
||||
|
||||
/**
|
||||
* Returns the offset of the child elements of this UI item.
|
||||
*
|
||||
* @return Offset of the child elements of this UI item.
|
||||
*/
|
||||
virtual float_t getChildOffsetX() = 0;
|
||||
|
||||
/**
|
||||
* Returns the offset of the child elements of this UI item.
|
||||
*
|
||||
* @return Offset of the child elements of this UI item.
|
||||
*/
|
||||
virtual float_t getChildOffsetY() = 0;
|
||||
};
|
||||
|
||||
enum UIDrawType {
|
||||
UI_DRAW_TYPE_WORLD_ABSOLUTE,
|
||||
UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE,
|
||||
// UI_DRAW_TYPE_CAMERA_OVERLAY
|
||||
};
|
||||
|
||||
class UICanvas : public SceneItemComponent, public UIComponentDimensional {
|
||||
private:
|
||||
std::function<void()> evtRenderResize;
|
||||
float_t w = 1;
|
||||
float_t h = 1;
|
||||
|
||||
/**
|
||||
* Rebuffers all of the necessary shader buffer data for this canvas to
|
||||
* the GPU.
|
||||
*/
|
||||
void rebufferShaderParameters();
|
||||
|
||||
public:
|
||||
UICanvasShaderBuffer shaderBuffer;
|
||||
|
||||
/**
|
||||
* Creates a UI Canvas Scene Item Element, and attaches it to the provided
|
||||
* scene.
|
||||
*
|
||||
* @param scene Scene to create the UI Canvas for.
|
||||
* @return Created UI Canvas.
|
||||
*/
|
||||
static std::shared_ptr<UICanvas> create(Scene *scene);
|
||||
|
||||
//======================================================================//
|
||||
StateProperty<std::shared_ptr<Camera>> camera;
|
||||
enum UIDrawType drawType = UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE;
|
||||
|
||||
/**
|
||||
* Constructs the UI Canvas Scene Item Component.
|
||||
*
|
||||
* @param item Item that this canvas item belongs to.
|
||||
*/
|
||||
UICanvas(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/**
|
||||
* Returns the scale of this canvas.
|
||||
*
|
||||
* @return The scale of the canvas, where 1 is default scaling.
|
||||
*/
|
||||
float_t getScale();
|
||||
|
||||
float_t getWidth() override;
|
||||
float_t getHeight() override;
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
float_t getChildOffsetX() override;
|
||||
float_t getChildOffsetY() override;
|
||||
void onStart() override;
|
||||
void onDispose() override;
|
||||
};
|
||||
}
|
@ -1,284 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIComponent.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIComponent::UIComponent(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
alignment(glm::vec4(0, 0, 128, 128)),
|
||||
alignUnitLeft(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
||||
alignUnitTop(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
||||
alignUnitRight(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
||||
alignUnitBottom(UI_COMPONENT_ALIGN_UNIT_SCALE),
|
||||
alignX(UI_COMPONENT_ALIGN_START),
|
||||
alignY(UI_COMPONENT_ALIGN_START),
|
||||
alignmentNeedsUpdating(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<UIComponentDimensional> UIComponent::getParentDimensional() {
|
||||
auto parent = item.lock()->getParent();
|
||||
if(parent == nullptr) return nullptr;
|
||||
auto dimensional = parent->getComponent<UIComponentDimensional>();
|
||||
assertNotNull(dimensional, "UIComponent::getParentDimensional: Parent must have a UIComponentDimensional");
|
||||
return dimensional;
|
||||
}
|
||||
|
||||
void UIComponent::updateAlignment() {
|
||||
if(!this->alignmentNeedsUpdating) return;
|
||||
|
||||
auto align = (glm::vec4)this->alignment;
|
||||
auto dimensional = this->getParentDimensional();
|
||||
auto translate = item.lock()->getLocalPosition();
|
||||
|
||||
assertNotNull(dimensional, "UIComponent::updateAlignment: Parent must have a UIComponentDimensional");
|
||||
|
||||
parentInnerWidth = dimensional->getContentWidth();
|
||||
parentInnerHeight = dimensional->getContentHeight();
|
||||
|
||||
// Should we be doing width first, or height first?
|
||||
bool_t heightFirst = (
|
||||
this->alignUnitLeft == UI_COMPONENT_ALIGN_UNIT_RATIO ||
|
||||
this->alignUnitRight == UI_COMPONENT_ALIGN_UNIT_RATIO
|
||||
);
|
||||
|
||||
if(heightFirst) {
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignY,
|
||||
this->alignUnitTop,
|
||||
this->alignUnitBottom,
|
||||
&translate.y,
|
||||
&this->height,
|
||||
parentInnerHeight,
|
||||
this->getContentHeight(),
|
||||
this->width,
|
||||
glm::vec2(align[1], align[3])
|
||||
);
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignX,
|
||||
this->alignUnitLeft,
|
||||
this->alignUnitRight,
|
||||
&translate.x,
|
||||
&this->width,
|
||||
parentInnerWidth,
|
||||
this->getContentWidth(),
|
||||
this->height,
|
||||
glm::vec2(align[0], align[2])
|
||||
);
|
||||
} else {
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignX,
|
||||
this->alignUnitLeft,
|
||||
this->alignUnitRight,
|
||||
&translate.x,
|
||||
&this->width,
|
||||
parentInnerWidth,
|
||||
this->getContentWidth(),
|
||||
this->height,
|
||||
glm::vec2(align[0], align[2])
|
||||
);
|
||||
UIComponent::calculateDimensions(
|
||||
this->alignY,
|
||||
this->alignUnitTop,
|
||||
this->alignUnitBottom,
|
||||
&translate.y,
|
||||
&this->height,
|
||||
parentInnerHeight,
|
||||
this->getContentHeight(),
|
||||
this->width,
|
||||
glm::vec2(align[1], align[3])
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
translate.x += dimensional->getChildOffsetX();
|
||||
translate.y += dimensional->getChildOffsetY();
|
||||
|
||||
item.lock()->setLocalPosition(translate);
|
||||
this->alignmentNeedsUpdating = false;
|
||||
this->eventAlignmentUpdated.invoke();
|
||||
}
|
||||
|
||||
float_t UIComponent::getWidthFromAlignment() {
|
||||
switch(this->alignX) {
|
||||
case UI_COMPONENT_ALIGN_STRETCH:
|
||||
case UI_COMPONENT_ALIGN_START:
|
||||
case UI_COMPONENT_ALIGN_MIDDLE:
|
||||
return alignment._realValue[2];
|
||||
|
||||
case UI_COMPONENT_ALIGN_END:
|
||||
return alignment._realValue[0];
|
||||
|
||||
default:
|
||||
assertUnreachable("UIComponent::getWidthFromAlignment: Unknown alignment");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
float_t UIComponent::getHeightFromAlignment() {
|
||||
switch(this->alignY) {
|
||||
case UI_COMPONENT_ALIGN_STRETCH:
|
||||
case UI_COMPONENT_ALIGN_START:
|
||||
case UI_COMPONENT_ALIGN_MIDDLE:
|
||||
return alignment._realValue[3];
|
||||
|
||||
case UI_COMPONENT_ALIGN_END:
|
||||
return alignment._realValue[1];
|
||||
|
||||
default:
|
||||
assertUnreachable("UIComponent::getWidthFromAlignment: Unknown alignment");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
float_t UIComponent::calculateAlignmentValue(
|
||||
float_t alignmentValue,
|
||||
float_t parentSize,
|
||||
float_t ratioSize,
|
||||
enum UIComponentAlignUnit unit
|
||||
) {
|
||||
if(unit == UI_COMPONENT_ALIGN_UNIT_SCALE) return alignmentValue;
|
||||
if(unit == UI_COMPONENT_ALIGN_UNIT_PERCENT) return (alignmentValue / 100.0f) * parentSize;
|
||||
if(unit == UI_COMPONENT_ALIGN_UNIT_RATIO) return (alignmentValue / 100.0f) * ratioSize;
|
||||
assertUnreachable("UIComponent::calculateAlignmentValue: Unknown alignment unit");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void UIComponent::calculateDimensions(
|
||||
enum UIComponentAlign align,
|
||||
enum UIComponentAlignUnit unitStart,
|
||||
enum UIComponentAlignUnit unitEnd,
|
||||
float_t *position,
|
||||
float_t *size,
|
||||
float_t outerSize,
|
||||
float_t innerSize,
|
||||
float_t ratioSize,
|
||||
glm::vec2 alignment
|
||||
) {
|
||||
assertNotNull(position, "UIComponent::calculateDimensions: Position cannot be null");
|
||||
assertNotNull(size, "UIComponent::calculateDimensions: Size cannot be null");
|
||||
|
||||
switch(align) {
|
||||
case UI_COMPONENT_ALIGN_STRETCH: {
|
||||
// For stretch:
|
||||
// Alignment 0 becomes START offset, Alignment 1 becomes END Offset
|
||||
*position = UIComponent::calculateAlignmentValue(
|
||||
alignment[0],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitStart
|
||||
);
|
||||
*size = outerSize - (*position + UIComponent::calculateAlignmentValue(
|
||||
alignment[1],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitEnd
|
||||
));
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_COMPONENT_ALIGN_START: {
|
||||
// For start:
|
||||
// Alignment 0 becomes START offset, Alignment 1 becomes SIZE
|
||||
*position = UIComponent::calculateAlignmentValue(
|
||||
alignment[0],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitStart
|
||||
);
|
||||
*size = UIComponent::calculateAlignmentValue(
|
||||
alignment[1],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitEnd
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_COMPONENT_ALIGN_MIDDLE: {
|
||||
*size = UIComponent::calculateAlignmentValue(
|
||||
alignment[1],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitEnd
|
||||
);
|
||||
*position = (outerSize / 2.0f) - ((*size) / 2.0f) + UIComponent::calculateAlignmentValue(
|
||||
alignment[0],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitStart
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_COMPONENT_ALIGN_END: {
|
||||
*size = UIComponent::calculateAlignmentValue(
|
||||
alignment[0],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitStart
|
||||
);
|
||||
*position = outerSize - *size - UIComponent::calculateAlignmentValue(
|
||||
alignment[1],
|
||||
outerSize,
|
||||
ratioSize,
|
||||
unitEnd
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertUnreachable("UIComponent::calculateDimensions: Unknown alignment");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<UICanvas> UIComponent::getCanvas() {
|
||||
// TODO: Cache this on first hit.
|
||||
auto parent = item.lock()->getParent();
|
||||
while(parent) {
|
||||
auto canvas = parent->getComponent<UICanvas>();
|
||||
if(canvas != nullptr) return canvas;
|
||||
parent = parent->getParent();
|
||||
}
|
||||
assertUnreachable("UIComponent::getCanvas: No canvas found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float_t UIComponent::getWidth() {
|
||||
return this->width;
|
||||
}
|
||||
|
||||
float_t UIComponent::getHeight() {
|
||||
return this->height;
|
||||
}
|
||||
|
||||
float_t UIComponent::getChildOffsetX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float_t UIComponent::getChildOffsetY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UIComponent::onStart() {
|
||||
useEffect([&]{
|
||||
this->alignmentNeedsUpdating = true;
|
||||
}, { &alignment, &alignX, &alignY });
|
||||
|
||||
useEffect([&]{
|
||||
this->updateAlignment();
|
||||
|
||||
auto child = this->item.lock()->findChildren<UIComponent>();
|
||||
auto itChild = child.begin();
|
||||
while(itChild != child.end()) {
|
||||
(*itChild)->alignmentNeedsUpdating = true;
|
||||
++itChild;
|
||||
}
|
||||
}, alignmentNeedsUpdating)();
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
#include "scene/components/display/IRenderable.hpp"
|
||||
#include "display/RenderPipeline.hpp"
|
||||
#include "display/RenderManager.hpp"
|
||||
#include "UICanvas.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
enum UIComponentAlign {
|
||||
UI_COMPONENT_ALIGN_START,
|
||||
UI_COMPONENT_ALIGN_MIDDLE,
|
||||
UI_COMPONENT_ALIGN_END,
|
||||
UI_COMPONENT_ALIGN_STRETCH
|
||||
};
|
||||
|
||||
enum UIComponentAlignUnit {
|
||||
UI_COMPONENT_ALIGN_UNIT_SCALE,
|
||||
UI_COMPONENT_ALIGN_UNIT_PERCENT,
|
||||
UI_COMPONENT_ALIGN_UNIT_RATIO
|
||||
};
|
||||
|
||||
class UIComponent : public SceneItemComponent, public UIComponentDimensional {
|
||||
protected:
|
||||
float_t width = 1;
|
||||
float_t height = 1;
|
||||
float_t parentInnerWidth = 1;
|
||||
float_t parentInnerHeight = 1;
|
||||
|
||||
/**
|
||||
* Simply returns this UI Components' dimensional parent, used for the
|
||||
* alignment of this item.
|
||||
*
|
||||
* @return Pointer to the parent dimensional.
|
||||
*/
|
||||
std::shared_ptr<UIComponentDimensional> getParentDimensional();
|
||||
|
||||
/**
|
||||
* Internal method to update the alignment of this item.
|
||||
*/
|
||||
virtual void updateAlignment();
|
||||
|
||||
/**
|
||||
* Helper function used for UI components that intend to use whatever the
|
||||
* dimensions that are set within the alignment parameter are for their
|
||||
* width.
|
||||
*
|
||||
* @return The width as defined in the alignment.
|
||||
*/
|
||||
float_t getWidthFromAlignment();
|
||||
|
||||
/**
|
||||
* Helper function used for UI components that intend to use whatever the
|
||||
* dimensions that are set within the alignment parameter are for their
|
||||
* height.
|
||||
*
|
||||
* @return The height as defined in the alignment.
|
||||
*/
|
||||
float_t getHeightFromAlignment();
|
||||
|
||||
public:
|
||||
StateProperty<bool_t> alignmentNeedsUpdating;
|
||||
StateEvent<> eventAlignmentUpdated;
|
||||
|
||||
/**
|
||||
* Method used to calculate alignment values.
|
||||
*
|
||||
* @param alignmentValue Alignment value.
|
||||
* @param parentSize Parent size.
|
||||
* @param ratioSize The dimension that the ratio is based on.
|
||||
* @param unit Alignment unit.
|
||||
* @return The calculated alignment value.
|
||||
*/
|
||||
static float_t calculateAlignmentValue(
|
||||
float_t alignmentValue,
|
||||
float_t parentSize,
|
||||
float_t ratioSize,
|
||||
enum UIComponentAlignUnit unit
|
||||
);
|
||||
|
||||
/**
|
||||
* Method used to calculate alignment dimensions.
|
||||
*
|
||||
* @param align Alignment value enumator.
|
||||
* @param unitStart Alignment start unit.
|
||||
* @param unitEnd Alignment end unit.
|
||||
* @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 ratioSize The size that the opposite dimension is.
|
||||
* @param alignment Alignment settings.
|
||||
*/
|
||||
static void calculateDimensions(
|
||||
enum UIComponentAlign align,
|
||||
enum UIComponentAlignUnit unitStart,
|
||||
enum UIComponentAlignUnit unitEnd,
|
||||
float_t *position,
|
||||
float_t *size,
|
||||
float_t outerSize,
|
||||
float_t innerSize,
|
||||
float_t ratioSize,
|
||||
glm::vec2 alignment
|
||||
);
|
||||
|
||||
// @optional
|
||||
StateProperty<enum UIComponentAlign> alignX;
|
||||
// @optional
|
||||
StateProperty<enum UIComponentAlign> alignY;
|
||||
// @optional
|
||||
StateProperty<enum UIComponentAlignUnit> alignUnitLeft;
|
||||
// @optional
|
||||
StateProperty<enum UIComponentAlignUnit> alignUnitTop;
|
||||
// @optional
|
||||
StateProperty<enum UIComponentAlignUnit> alignUnitRight;
|
||||
// @optional
|
||||
StateProperty<enum UIComponentAlignUnit> alignUnitBottom;
|
||||
// @optional
|
||||
StateProperty<glm::vec4> alignment;
|
||||
|
||||
UIComponent(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/**
|
||||
* Returns the canvas that this UI element is belonging to.
|
||||
*
|
||||
* @return Pointer to the UI Canvas this component is a child of.
|
||||
*/
|
||||
virtual std::shared_ptr<UICanvas> getCanvas();
|
||||
|
||||
float_t getWidth() override;
|
||||
float_t getHeight() override;
|
||||
float_t getChildOffsetX() override;
|
||||
float_t getChildOffsetY() override;
|
||||
void onStart() override;
|
||||
|
||||
friend class UICanvas;
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIComponentRenderable.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIComponentRenderable::UIComponentRenderable(std::weak_ptr<SceneItem> i) : UIComponent(i) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> UIComponentRenderable::getRenderPasses(
|
||||
struct IRenderableContext &context
|
||||
) {
|
||||
auto renderManager = context.renderPipeline->renderManager.lock();
|
||||
assertNotNull(renderManager, "RenderManager cannot be null");
|
||||
|
||||
if(
|
||||
context.camera->getRenderTarget() !=
|
||||
renderManager->getBackBuffer()
|
||||
) {
|
||||
auto canvas = this->getCanvas();
|
||||
if(canvas->drawType == UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE) return {};
|
||||
}
|
||||
|
||||
return this->getUIRenderPasses();
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UIComponent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIComponentRenderable : public UIComponent, public IRenderable {
|
||||
public:
|
||||
UIComponentRenderable(std::weak_ptr<SceneItem> item);
|
||||
|
||||
std::vector<struct ShaderPassItem> getRenderPasses(
|
||||
struct IRenderableContext &context
|
||||
) override;
|
||||
|
||||
/**
|
||||
* Higher level means to determine the render passes for this UI item. We
|
||||
* handle some of the more common functionality in the above override.
|
||||
*
|
||||
* @return Array of render passes for this UI item.
|
||||
*/
|
||||
virtual std::vector<struct ShaderPassItem> getUIRenderPasses() = 0;
|
||||
};
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIEmpty.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIEmpty::UIEmpty(std::weak_ptr<SceneItem> item) : UIComponent(item) { }
|
||||
|
||||
float_t UIEmpty::getContentWidth() {
|
||||
return this->getWidthFromAlignment();
|
||||
}
|
||||
float_t UIEmpty::getContentHeight() {
|
||||
return this->getHeightFromAlignment();
|
||||
}
|
||||
float_t UIEmpty::getChildOffsetX() { return 0.0f; }
|
||||
float_t UIEmpty::getChildOffsetY() { return 0.0f; }
|
@ -1,18 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UIComponent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIEmpty : public UIComponent {
|
||||
public:
|
||||
UIEmpty(std::weak_ptr<SceneItem> item);
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
float_t getChildOffsetX() override;
|
||||
float_t getChildOffsetY() override;
|
||||
};
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIImage.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIImage::UIImage(std::weak_ptr<SceneItem> item) :
|
||||
texture(nullptr),
|
||||
UIComponentRenderable(item),
|
||||
uvs(glm::vec4(0, 1, 1, 0))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
float_t UIImage::getContentWidth() {
|
||||
if(this->texture != nullptr) return this->texture->getWidth();
|
||||
return this->width;
|
||||
}
|
||||
|
||||
float_t UIImage::getContentHeight() {
|
||||
if(this->texture != nullptr) return this->texture->getHeight();
|
||||
return this->height;
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> UIImage::getUIRenderPasses() {
|
||||
struct ShaderPassItem item;
|
||||
auto shader = getGame()->renderManager->uiShader;
|
||||
item.shader = shader;
|
||||
item.colorValues[shader->paramColor] = this->color;
|
||||
item.parameterBuffers[shader->bufferUiCanvas] = &getCanvas()->shaderBuffer;
|
||||
item.matrixValues[shader->paramModel] = this->item.lock()->getWorldTransform();
|
||||
if(this->texture == nullptr) {
|
||||
item.boolValues[shader->paramHasTexture] = false;
|
||||
} else {
|
||||
item.boolValues[shader->paramHasTexture] = true;
|
||||
item.textureSlots[0] = this->texture;
|
||||
item.textureValues[shader->paramTexture] = 0;
|
||||
}
|
||||
item.w = this->item.lock()->getWorldPosition().z;
|
||||
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
|
||||
item.mesh = &mesh;
|
||||
return { item };
|
||||
}
|
||||
|
||||
void UIImage::onStart() {
|
||||
UIComponent::onStart();
|
||||
|
||||
useEvent([&]{
|
||||
QuadMesh::bufferPositions(mesh,
|
||||
glm::vec2(0, 0),
|
||||
glm::vec2(width, height), 0
|
||||
);
|
||||
}, this->eventAlignmentUpdated);
|
||||
|
||||
useEffect([&]{
|
||||
QuadMesh::bufferCoordinates(mesh,
|
||||
glm::vec2(this->uvs._realValue[0], this->uvs._realValue[1]),
|
||||
glm::vec2(this->uvs._realValue[2], this->uvs._realValue[3]),
|
||||
0
|
||||
);
|
||||
}, this->uvs);
|
||||
|
||||
QuadMesh::initQuadMesh(mesh,
|
||||
glm::vec2(0, 0), glm::vec2(this->uvs._realValue[0], this->uvs._realValue[1]),
|
||||
glm::vec2(width, height), glm::vec2(this->uvs._realValue[2], this->uvs._realValue[3]),
|
||||
0.0f
|
||||
);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UIComponentRenderable.hpp"
|
||||
#include "display/mesh/QuadMesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIImage : public UIComponentRenderable {
|
||||
private:
|
||||
Mesh mesh;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
struct Color color = COLOR_WHITE;
|
||||
// @optional
|
||||
StateProperty<Texture*> texture;
|
||||
// @optional
|
||||
StateProperty<glm::vec4> uvs;
|
||||
|
||||
UIImage(std::weak_ptr<SceneItem> item);
|
||||
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
std::vector<struct ShaderPassItem> getUIRenderPasses() override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIMesh.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIMesh::UIMesh(std::weak_ptr<SceneItem> i) :
|
||||
texture(nullptr),
|
||||
UIComponentRenderable(i)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
float_t UIMesh::getContentWidth() {
|
||||
if(this->texture != nullptr) return this->texture->getWidth();
|
||||
return this->width;
|
||||
}
|
||||
|
||||
float_t UIMesh::getContentHeight() {
|
||||
if(this->texture != nullptr) return this->texture->getHeight();
|
||||
return this->height;
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> UIMesh::getUIRenderPasses() {
|
||||
struct ShaderPassItem shaderItem;
|
||||
auto shader = getGame()->renderManager->uiShader;
|
||||
shaderItem.shader = shader;
|
||||
shaderItem.colorValues[shader->paramColor] = this->color;
|
||||
shaderItem.parameterBuffers[shader->bufferUiCanvas] = &getCanvas()->shaderBuffer;
|
||||
shaderItem.matrixValues[shader->paramModel] = item.lock()->getWorldTransform();
|
||||
if(this->texture == nullptr) {
|
||||
shaderItem.boolValues[shader->paramHasTexture] = false;
|
||||
} else {
|
||||
shaderItem.boolValues[shader->paramHasTexture] = true;
|
||||
shaderItem.textureSlots[0] = this->texture;
|
||||
shaderItem.textureValues[shader->paramTexture] = 0;
|
||||
}
|
||||
shaderItem.w = item.lock()->getWorldPosition().z;
|
||||
shaderItem.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
|
||||
shaderItem.mesh = &mesh;
|
||||
return { shaderItem };
|
||||
}
|
||||
|
||||
void UIMesh::onStart() {
|
||||
useEffect([&]{
|
||||
|
||||
}, this->positions)();
|
||||
|
||||
useEffect([&]{
|
||||
|
||||
}, this->uvs)();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UIComponentRenderable.hpp"
|
||||
#include "display/mesh/QuadMesh.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIMesh : public UIComponentRenderable {
|
||||
private:
|
||||
Mesh mesh;
|
||||
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<std::vector<glm::vec2>> positions;
|
||||
// @optional
|
||||
StateProperty<std::vector<glm::vec2>> uvs;
|
||||
// @optional
|
||||
struct Color color = COLOR_WHITE;
|
||||
// @optional
|
||||
StateProperty<Texture*> texture;
|
||||
|
||||
UIMesh(std::weak_ptr<SceneItem> item);
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
std::vector<struct ShaderPassItem> getUIRenderPasses() override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
# Copyright (c) 2022 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
UIMenuController.cpp
|
||||
UISimpleMenu.cpp
|
||||
UISimpleMenuItem.cpp
|
||||
)
|
@ -1,68 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIMenuController.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIMenuController::UIMenuController(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item),
|
||||
active(true),
|
||||
menuX(0),
|
||||
menuY(0),
|
||||
columns(4),
|
||||
rows(4)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UIMenuController::onStart() {
|
||||
useEffectWithTeardown([&]{
|
||||
if(!active) return activeTeardown = [&]{ };
|
||||
|
||||
useEffect([&]{
|
||||
eventItemChange.invoke(menuX, menuY);
|
||||
}, menuX);
|
||||
|
||||
useEffect([&]{
|
||||
eventItemChange.invoke(menuX, menuY);
|
||||
}, menuY);
|
||||
|
||||
useEffect([&]{
|
||||
menuX = mathClamp<int32_t>(menuX, 0, rows);
|
||||
}, columns);
|
||||
|
||||
useEffect([&]{
|
||||
menuY = mathClamp<int32_t>(menuY, 0, rows);
|
||||
}, rows);
|
||||
|
||||
return activeTeardown = useEvent([&](inputbind_t bind) {
|
||||
switch(bind) {
|
||||
case INPUT_BIND_POSITIVE_X:
|
||||
menuX = mathClamp<int32_t>(menuX+1, 0, columns);
|
||||
break;
|
||||
case INPUT_BIND_POSITIVE_Y:
|
||||
menuY = mathClamp<int32_t>(menuY+1, 0, rows);
|
||||
break;
|
||||
case INPUT_BIND_NEGATIVE_X:
|
||||
menuX = mathClamp<int32_t>(menuX-1, 0, columns);
|
||||
break;
|
||||
case INPUT_BIND_NEGATIVE_Y:
|
||||
menuY = mathClamp<int32_t>(menuY-1, 0, rows);
|
||||
break;
|
||||
case INPUT_BIND_ACCEPT:
|
||||
case INPUT_BIND_MOUSE_CLICK:
|
||||
eventItemSelected.invoke(menuX, menuY);
|
||||
break;
|
||||
case INPUT_BIND_CANCEL:
|
||||
eventMenuCancel.invoke();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}, this->getGame()->inputManager.eventBindPressed);
|
||||
}, active)();
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/SceneItemComponent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIMenuController : public SceneItemComponent {
|
||||
private:
|
||||
std::function<void()> activeTeardown;
|
||||
|
||||
public:
|
||||
StateProperty<bool_t> active;
|
||||
StateProperty<int32_t> menuX;
|
||||
StateProperty<int32_t> menuY;
|
||||
StateProperty<int32_t> columns;
|
||||
StateProperty<int32_t> rows;
|
||||
|
||||
StateEvent<int32_t, int32_t> eventItemChange;
|
||||
StateEvent<int32_t, int32_t> eventItemSelected;
|
||||
StateEvent<> eventMenuCancel;
|
||||
|
||||
UIMenuController(std::weak_ptr<SceneItem> item);
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UISimpleMenu.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
#include "physics/3d/Ray3D.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UISimpleMenu::UISimpleMenu(std::weak_ptr<SceneItem> item) :
|
||||
SceneItemComponent(item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> UISimpleMenu::getDependencies() {
|
||||
return {
|
||||
(this->menu = this->item.lock()->getComponent<UIMenuController>()),
|
||||
(this->canvas == nullptr ? (this->canvas = this->item.lock()->getComponent<UICanvas>()) : nullptr)
|
||||
};
|
||||
}
|
||||
|
||||
void UISimpleMenu::onStart() {
|
||||
if(canvas == nullptr) canvas = getScene()->findComponent<UICanvas>();
|
||||
|
||||
assertNotNull(this->menu, "UISimpleMenu::onStart: Menu cannot be null");
|
||||
assertNotNull(this->canvas, "UISimpleMenu::onStart: Canvas cannot be null");
|
||||
menuItems = this->item.lock()->findChildren<UISimpleMenuItem>();
|
||||
|
||||
auto updateSimpleMenuPos = [&](int32_t x, int32_t y) {
|
||||
if(currentlySelected != nullptr) {
|
||||
currentlySelected->eventHoveredOff.invoke();
|
||||
currentlySelected = nullptr;
|
||||
}
|
||||
|
||||
// Find item
|
||||
auto itItem = menuItems.begin();
|
||||
while(itItem != menuItems.end()) {
|
||||
auto itm = *itItem;
|
||||
if(itm->menuX == x && itm->menuY == y) {
|
||||
currentlySelected = itm;
|
||||
break;
|
||||
}
|
||||
++itItem;
|
||||
}
|
||||
|
||||
// Was anything found?
|
||||
if(currentlySelected == nullptr) return;
|
||||
currentlySelected->eventHoveredOn.invoke();
|
||||
};
|
||||
|
||||
useEvent(updateSimpleMenuPos, menu->eventItemChange);
|
||||
updateSimpleMenuPos(menu->menuX, menu->menuY);
|
||||
|
||||
useEvent([&](int32_t x, int32_t y){
|
||||
if(currentlySelected == nullptr) return;
|
||||
currentlySelected->eventSelected.invoke();
|
||||
}, menu->eventItemSelected);
|
||||
|
||||
useEvent([&](float_t d){
|
||||
assertNotNull(canvas->camera, "UISimpleMenu::onStart: Camera cannot be null");
|
||||
if(!this->menu->active) return;
|
||||
|
||||
// Mouse in screen space.
|
||||
auto mouse = getGame()->inputManager.getAxis2D(INPUT_BIND_MOUSE_X, INPUT_BIND_MOUSE_Y);
|
||||
|
||||
switch(canvas->drawType) {
|
||||
case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE:
|
||||
case UI_DRAW_TYPE_WORLD_ABSOLUTE: {
|
||||
|
||||
// Calculate ray
|
||||
struct Ray3D ray;
|
||||
switch(canvas->drawType) {
|
||||
case UI_DRAW_TYPE_WORLD_ABSOLUTE:
|
||||
mouse *= 2.0f;
|
||||
mouse -= glm::vec2(1, 1);
|
||||
ray.origin = canvas->camera->item.lock()->getWorldPosition();
|
||||
ray.direction = canvas->camera->getRayDirectionFromScreenSpace(mouse);
|
||||
break;
|
||||
|
||||
case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE:
|
||||
auto rt = canvas->camera->getRenderTarget();
|
||||
mouse *= glm::vec2(rt->getWidth(), rt->getHeight());
|
||||
ray.origin = glm::vec3(mouse, 5);
|
||||
ray.direction = glm::vec3(0, 0, -10);
|
||||
break;
|
||||
}
|
||||
|
||||
// Find mouse item
|
||||
auto itItems = menuItems.begin();
|
||||
while(itItems != menuItems.end()) {
|
||||
auto item = *itItems;
|
||||
++itItems;
|
||||
auto highlight = item->getComponentForHighlighting();
|
||||
if(highlight == nullptr) continue;
|
||||
|
||||
glm::vec2 size(
|
||||
highlight->getContentWidth(),
|
||||
highlight->getContentHeight()
|
||||
);
|
||||
glm::vec3 point;
|
||||
glm::vec3 normal;
|
||||
float_t distance;
|
||||
|
||||
// TODO: Include Z axis for determining which item is hovered.
|
||||
if(!raytestQuad(
|
||||
ray,
|
||||
glm::vec2(0, 0), size,
|
||||
highlight->item.lock()->getWorldTransform(),
|
||||
point,
|
||||
normal,
|
||||
distance
|
||||
)) continue;
|
||||
|
||||
this->menu->menuX = item->menuX;
|
||||
this->menu->menuY = item->menuY;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
assertUnreachable("UISimpleMenu::onStart: Draw type not implemented");
|
||||
}
|
||||
}
|
||||
}, getScene()->eventSceneUnpausedUpdate);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UIMenuController.hpp"
|
||||
#include "UISimpleMenuItem.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UISimpleMenu : public SceneItemComponent {
|
||||
protected:
|
||||
std::shared_ptr<UIMenuController> menu;
|
||||
std::shared_ptr<UICanvas> canvas;
|
||||
std::shared_ptr<UISimpleMenuItem> currentlySelected;
|
||||
std::vector<std::shared_ptr<UISimpleMenuItem>> menuItems;
|
||||
|
||||
public:
|
||||
UISimpleMenu(std::weak_ptr<SceneItem> item);
|
||||
std::vector<std::shared_ptr<SceneItemComponent>> getDependencies() override;
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UISimpleMenuItem.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UISimpleMenuItem::UISimpleMenuItem(std::weak_ptr<SceneItem> item) : SceneItemComponent(item) {
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<UIComponent> UISimpleMenuItem::getComponentForHighlighting() {
|
||||
if(uiComponent == nullptr) uiComponent = item.lock()->getComponent<UIComponent>();
|
||||
return uiComponent;
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/components/ui/UIComponent.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UISimpleMenuItem : public SceneItemComponent {
|
||||
public:
|
||||
StateEvent<> eventHoveredOn;
|
||||
StateEvent<> eventHoveredOff;
|
||||
StateEvent<> eventSelected;
|
||||
// May make these into either state events or make a new event.
|
||||
int32_t menuX = 0;
|
||||
int32_t menuY = 0;
|
||||
std::shared_ptr<UIComponent> uiComponent = nullptr;
|
||||
|
||||
UISimpleMenuItem(std::weak_ptr<SceneItem> item);
|
||||
|
||||
/**
|
||||
* Returns the UI component that this simple UI menu item uses to figure
|
||||
* out if it is being hovered over currently or not.
|
||||
*
|
||||
* @return UI Component to use for highlighting / hovering.
|
||||
*/
|
||||
virtual std::shared_ptr<UIComponent> getComponentForHighlighting();
|
||||
};
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
UILabel.cpp
|
||||
UIRichTextLabel.cpp
|
||||
UISimpleLabel.cpp
|
||||
)
|
@ -1,494 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UILabel.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UILabel::UILabel(std::weak_ptr<SceneItem> item) :
|
||||
UIComponentRenderable(item),
|
||||
lineHeight(1.0f),
|
||||
textAlign(UI_LABEL_TEXT_ALIGN_LEFT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UILabel::onStart() {
|
||||
UIComponentRenderable::onStart();
|
||||
|
||||
this->shaderBuffer.init();
|
||||
|
||||
useEvent([&]{
|
||||
// TODO: I believe I only need to rebuffer here if maxWidth is not -1
|
||||
this->rebufferQuads(this->texts);
|
||||
}, eventAlignmentUpdated);
|
||||
|
||||
useEffect([&]{
|
||||
this->rebufferQuads(this->texts);
|
||||
}, lineHeight);
|
||||
|
||||
useEvent([&]{
|
||||
this->updateTextAlignments();
|
||||
}, eventTextChanged);
|
||||
|
||||
useEffect([&]{
|
||||
this->updateTextAlignments();
|
||||
}, this->textAlign);
|
||||
}
|
||||
|
||||
void UILabel::updateTextAlignments() {
|
||||
struct FontShaderBufferData data;
|
||||
|
||||
switch(this->textAlign) {
|
||||
case UI_LABEL_TEXT_ALIGN_LEFT: {
|
||||
auto itLine = lines.begin();
|
||||
int32_t i = 0;
|
||||
while(itLine != lines.end()) {
|
||||
data.linePositions[i] = glm::vec2(0, 0);
|
||||
++itLine;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_LABEL_TEXT_ALIGN_RIGHT: {
|
||||
float_t widthBased = this->getWidth();
|
||||
auto itLine = lines.begin();
|
||||
int32_t i = 0;
|
||||
while(itLine != lines.end()) {
|
||||
data.linePositions[i] = glm::vec2(widthBased - itLine->width, 0);
|
||||
++itLine;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UI_LABEL_TEXT_ALIGN_CENTER: {
|
||||
float_t widthBased = this->getWidth();
|
||||
auto itLine = lines.begin();
|
||||
int32_t i = 0;
|
||||
while(itLine != lines.end()) {
|
||||
float_t x = (widthBased - itLine->width) / 2.0f;
|
||||
data.linePositions[i] = glm::vec2(x, 0);
|
||||
++itLine;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
assertUnreachable("UILabel::updateTextAlignments: TextAlign invalid");
|
||||
}
|
||||
|
||||
this->shaderBuffer.buffer(&data, &data.linePositions);
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> UILabel::getUIRenderPasses() {
|
||||
if(this->textsBuffered.empty()) return {};
|
||||
|
||||
auto canvas = this->getCanvas();
|
||||
auto shader = getGame()->renderManager->fontShader;
|
||||
|
||||
// Translate
|
||||
glm::mat4 model = item.lock()->getWorldTransform();
|
||||
model = glm::translate(model, glm::vec3(this->textOffset, 0.0f));
|
||||
|
||||
struct ShaderPassItem item;
|
||||
|
||||
item.shader = shader;
|
||||
item.mesh = &this->mesh;
|
||||
item.matrixValues[shader->paramModel] = model;
|
||||
item.parameterBuffers[shader->bufferUiCanvas] = &canvas->shaderBuffer;
|
||||
item.parameterBuffers[shader->bufferFont] = &this->shaderBuffer;
|
||||
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_BLEND;
|
||||
item.start = quadStart * QUAD_INDICE_COUNT;
|
||||
item.count = quadCount == -1 ? -1 : quadCount * QUAD_INDICE_COUNT;
|
||||
|
||||
// Map texture slots
|
||||
auto it = textureMap.begin();
|
||||
while(it != textureMap.end()) {
|
||||
shaderparameter_t param;
|
||||
switch(it->second) {
|
||||
case 0:
|
||||
param = shader->paramTexture0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
param = shader->paramTexture1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
param = shader->paramTexture2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
param = shader->paramTexture3;
|
||||
break;
|
||||
|
||||
default:
|
||||
assertUnreachable("UILabel::getUIRenderPasses: Texture slot not implemented");
|
||||
}
|
||||
|
||||
item.textureSlots[it->second] = &it->first->texture;
|
||||
item.textureValues[param] = it->second;
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
std::vector<struct ShaderPassItem> items;
|
||||
items.push_back(item);
|
||||
|
||||
if(this->hasDecorations) {
|
||||
struct ShaderPassItem itemDecorations = item;
|
||||
itemDecorations.mesh = &this->meshDecorations;
|
||||
items.push_back(itemDecorations);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
float_t UILabel::getContentWidth() {
|
||||
float_t w = 0;
|
||||
auto it = lines.begin();
|
||||
while(it != lines.end()) {
|
||||
w = mathMax<float_t>(w, it->width);
|
||||
++it;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
float_t UILabel::getContentHeight() {
|
||||
float_t h = 0;
|
||||
auto it = lines.begin();
|
||||
while(it != lines.end()) {
|
||||
h += it->height;
|
||||
++it;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
void UILabel::rebufferQuads(const std::vector<struct UILabelText> newTexts) {
|
||||
if(this->ignoreAlignmentUpdate) {
|
||||
this->ignoreAlignmentUpdate = false;
|
||||
return;
|
||||
}
|
||||
|
||||
assertTrue(newTexts.size() <= FONT_SHADER_PARTS_MAX, "UILabel::rebufferQuads: Too many parts (not supported)");
|
||||
|
||||
int32_t nextTexture = 0;
|
||||
glm::vec2 position(0, 0);
|
||||
int32_t partIndex = 0;
|
||||
std::vector<std::pair<glm::vec4, glm::vec4>> vertices;
|
||||
std::vector<std::pair<glm::vec4, glm::vec4>> decorations;
|
||||
struct FontShaderBufferData fontData;
|
||||
quadCountTotal = 0;
|
||||
quadCount = -1;
|
||||
std::vector<struct UILabelText> realNewTexts;
|
||||
float_t maxWidth = this->width;
|
||||
float_t canvasScale = this->getCanvas()->getScale();
|
||||
|
||||
// Reset
|
||||
lines.clear();
|
||||
textureMap.clear();
|
||||
hasDecorations = false;
|
||||
|
||||
// Determine font dimensions.
|
||||
auto itText = newTexts.begin();
|
||||
while(itText != newTexts.end()) {
|
||||
position.y = mathMax<float_t>(position.y, itText->style.size);
|
||||
++itText;
|
||||
}
|
||||
|
||||
// Prepare values shared across all text parts/styles
|
||||
float_t lineWidth = 0;
|
||||
struct UILabelLine currentLine;
|
||||
currentLine.quadStart = quadCountTotal;
|
||||
currentLine.position = position;
|
||||
|
||||
// Now generate quads
|
||||
itText = newTexts.begin();
|
||||
while(itText != newTexts.end()) {
|
||||
auto text = *itText;
|
||||
struct UILabelText realText;
|
||||
|
||||
// Clone values
|
||||
realText.style = text.style;
|
||||
|
||||
// Lock the font
|
||||
assertNotNull(text.style.font, "UILabel::rebufferQuads: Font cannot be null");
|
||||
realText.lockId = text.style.font->lock(TrueTypeFaceTextureStyle{
|
||||
(uint32_t)(text.style.size * canvasScale),// Scale for resolution.
|
||||
text.style.style
|
||||
});
|
||||
assertTrue(realText.lockId != -1, "UILabel::rebufferQuads: Failed to lock font");
|
||||
realText.texture = text.style.font->getTexture(realText.lockId);
|
||||
|
||||
// Map texture
|
||||
if(textureMap.find(realText.texture) == textureMap.end()) {
|
||||
assertTrue(nextTexture < FONT_SHADER_TEXTURE_MAX, "UILabel::rebufferQuads: Too many textures (not supported)");
|
||||
textureMap[realText.texture] = nextTexture++;
|
||||
}
|
||||
|
||||
// Buffer shader values
|
||||
fontData.textures[partIndex].value = textureMap[realText.texture];
|
||||
fontData.colors[partIndex] = realText.style.color;
|
||||
|
||||
// Get some texture info
|
||||
glm::vec2 wh = glm::vec2(
|
||||
realText.texture->texture.getWidth(),
|
||||
realText.texture->texture.getHeight()
|
||||
);
|
||||
|
||||
// Prepare loop properties and shorthands
|
||||
auto len = text.text.length();
|
||||
float_t wordWidth = 0;
|
||||
int32_t lastSpaceCharacter = -1;
|
||||
|
||||
currentLine.height = mathMax<float_t>(currentLine.height, realText.style.size);
|
||||
|
||||
std::function<void(int32_t)> fnInsertNewline = [&](int32_t i){
|
||||
if(i != len) {
|
||||
// Update text.
|
||||
realText.text += '\n';
|
||||
|
||||
// Insert dummy quad
|
||||
glm::vec4 uvs(0, 0, 1, 1);
|
||||
glm::vec4 vert(0, 0, 0, 0);
|
||||
vertices.push_back(std::make_pair(vert, uvs));
|
||||
decorations.push_back(std::make_pair(vert, uvs));
|
||||
fontData.quadMappings[quadCountTotal].value = partIndex;
|
||||
|
||||
quadCountTotal++;
|
||||
}
|
||||
|
||||
// Finalize current line
|
||||
lineWidth += wordWidth;
|
||||
currentLine.width = lineWidth;
|
||||
currentLine.quadCount += quadCountTotal - currentLine.quadStart;
|
||||
|
||||
// Move to next line
|
||||
if(i != len) {
|
||||
position.x = 0;
|
||||
position.y += realText.style.size * this->lineHeight;
|
||||
lines.push_back(currentLine);
|
||||
}
|
||||
|
||||
// Reset line
|
||||
lastSpaceCharacter = i;
|
||||
wordWidth = 0.0f;
|
||||
|
||||
if(i != len) lineWidth = 0.0f;
|
||||
|
||||
if(i != len) {
|
||||
currentLine = UILabelLine();
|
||||
currentLine.quadStart = quadCountTotal;
|
||||
currentLine.position = position;
|
||||
currentLine.height = realText.style.size * this->lineHeight;
|
||||
// Here I subtract line height from the line position because we start
|
||||
// by moving the text down by the initial line height, so we need to
|
||||
// compensate for that.
|
||||
currentLine.position.y -= realText.style.size * this->lineHeight;
|
||||
}
|
||||
};
|
||||
|
||||
// Now, iterate each character
|
||||
for(int32_t i = 0; i < len; i++) {
|
||||
std::u32string::value_type ch = text.text[i];
|
||||
// FT_ULong ch = text.text[i];
|
||||
char c = text.text[i];
|
||||
|
||||
// Handle special characters
|
||||
if(ch == '\n') {
|
||||
fnInsertNewline(i);
|
||||
continue;
|
||||
} else if(ch == ' ') {
|
||||
lastSpaceCharacter = i;
|
||||
}
|
||||
|
||||
// Validate characters
|
||||
assertTrue(ch >= TRUE_TYPE_CHAR_BEGIN && ch < TRUE_TYPE_CHAR_END, "UILabel::rebufferQuads: Character out of range");
|
||||
assertTrue(ch != '\r', "UILabel::rebufferQuads: Character cannot be a carriage return");
|
||||
assertTrue(ch != '\t', "UILabel::rebufferQuads: Character cannot be a tab");
|
||||
assertTrue(ch != '\n', "UILabel::rebufferQuads: Character cannot be a newline");
|
||||
|
||||
// Get font data.
|
||||
auto charInfo = realText.texture->getCharacterData(ch);
|
||||
|
||||
// Now we scale down the char info here. This is because we fetch the
|
||||
// texture of the font based on the canvas scale, but the sizes that we
|
||||
// render out need to be shrunk to match the original sizes.
|
||||
glm::vec2 charSize = glm::vec2(
|
||||
charInfo.bitmapSize.x / canvasScale, charInfo.bitmapSize.y / canvasScale
|
||||
);
|
||||
glm::vec2 charAdvance = glm::vec2(
|
||||
charInfo.advanceX / canvasScale, charInfo.advanceY / canvasScale
|
||||
);
|
||||
glm::vec2 charPos = glm::vec2(
|
||||
charInfo.bitmapPosition.x / canvasScale,
|
||||
charInfo.bitmapPosition.y / canvasScale
|
||||
);
|
||||
|
||||
// Word wrapping
|
||||
if(
|
||||
ch != ' ' &&
|
||||
lastSpaceCharacter != -1 &&
|
||||
maxWidth > charSize.x &&
|
||||
(position.x + charAdvance.x) > maxWidth
|
||||
) {
|
||||
// Basically this rewinds everything we've done to the last space char,
|
||||
// changes it to a newline, and then moves the position along.
|
||||
int32_t diff = i - lastSpaceCharacter;
|
||||
for(int32_t k = 0; k < diff; k++) {
|
||||
vertices.pop_back();
|
||||
decorations.pop_back();
|
||||
}
|
||||
text.text[lastSpaceCharacter] = '\n';
|
||||
i = lastSpaceCharacter;
|
||||
lastSpaceCharacter = -1;
|
||||
quadCountTotal -= diff;
|
||||
|
||||
// Now we've rewound to the space, treat it like a newline instead.
|
||||
fnInsertNewline(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Buffer coordinates, use original (non scaled) values.
|
||||
glm::vec4 uvs;
|
||||
uvs.x = 0.0f;
|
||||
uvs.y = charInfo.textureY / wh.y;
|
||||
uvs.w = charInfo.bitmapSize.x / wh.x;
|
||||
uvs.z = uvs.y + (charInfo.bitmapSize.y / wh.y);
|
||||
|
||||
glm::vec4 vert;
|
||||
vert.x = position.x + charPos.x;
|
||||
vert.y = position.y + charPos.y;
|
||||
vert.w = vert.x + charSize.x;
|
||||
vert.z = vert.y + charSize.y;
|
||||
vertices.push_back(std::make_pair(vert, uvs));
|
||||
|
||||
// Decorations
|
||||
if(text.style.decorations != 0) {
|
||||
auto charInfo2 = realText.texture->getCharacterData('-');
|
||||
uvs.y = charInfo2.textureY / wh.y;
|
||||
uvs.w = charInfo2.bitmapSize.x / wh.x;
|
||||
uvs.z = uvs.y + (charInfo2.bitmapSize.y / wh.y);
|
||||
vert.x = position.x + charInfo2.bitmapPosition.x;
|
||||
vert.y = position.y + charInfo2.bitmapPosition.y;
|
||||
vert.w = vert.x + charInfo.advanceX;
|
||||
vert.z = vert.y + charInfo2.bitmapSize.y;
|
||||
decorations.push_back(std::make_pair(vert, uvs));
|
||||
hasDecorations = true;
|
||||
// TODO: Finish
|
||||
} else {
|
||||
uvs = glm::vec4(0, 0, 1, 1);
|
||||
vert = glm::vec4(0, 0, 0, 0);
|
||||
decorations.push_back(std::make_pair(vert, uvs));
|
||||
}
|
||||
|
||||
// Move the current position along.
|
||||
position.x += charAdvance.x;
|
||||
position.y += charAdvance.y;
|
||||
|
||||
// Update the continuous dimensions
|
||||
if(ch == ' ') {
|
||||
lineWidth += wordWidth;
|
||||
lineWidth += charAdvance.x;
|
||||
wordWidth = 0.0f;
|
||||
} else {
|
||||
wordWidth += charAdvance.x;
|
||||
}
|
||||
|
||||
// Set the part index to the quad mappings
|
||||
fontData.quadMappings[quadCountTotal].value = partIndex;
|
||||
quadCountTotal++;
|
||||
realText.text += ch;
|
||||
}
|
||||
|
||||
// Now we insert a line. We do this because there is no newline at the end
|
||||
// of the text, so we need to insert the last line manually.
|
||||
bool_t isLast = itText == (newTexts.end() - 1);
|
||||
if(isLast) fnInsertNewline(len);
|
||||
|
||||
// Next
|
||||
++partIndex;
|
||||
++itText;
|
||||
realNewTexts.push_back(realText);
|
||||
}
|
||||
|
||||
lines.push_back(currentLine);
|
||||
|
||||
// Create mesh
|
||||
if(!vertices.empty()) {
|
||||
this->mesh.createBuffers(
|
||||
QUAD_VERTICE_COUNT * vertices.size(),
|
||||
QUAD_INDICE_COUNT * vertices.size()
|
||||
);
|
||||
|
||||
if(hasDecorations) {
|
||||
assertTrue(vertices.size() == decorations.size(), "UILabel::rebufferQuads: Decoration count mismatch");
|
||||
this->meshDecorations.createBuffers(
|
||||
QUAD_VERTICE_COUNT * decorations.size(),
|
||||
QUAD_INDICE_COUNT * decorations.size()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now buffer the quads. Can be optimized probably.
|
||||
int32_t j = 0;
|
||||
auto itQuad = vertices.begin();
|
||||
while(itQuad != vertices.end()) {
|
||||
auto vert = itQuad->first;
|
||||
auto uvs = itQuad->second;
|
||||
|
||||
QuadMesh::bufferQuadMeshWithZ(this->mesh,
|
||||
glm::vec2(vert.x, vert.y), glm::vec2(uvs.x, uvs.y),
|
||||
glm::vec2(vert.w, vert.z), glm::vec2(uvs.w, uvs.z),
|
||||
0.0f,
|
||||
j * QUAD_VERTICE_COUNT, j * QUAD_INDICE_COUNT
|
||||
);
|
||||
++j;
|
||||
++itQuad;
|
||||
}
|
||||
|
||||
// Now buffer decorations
|
||||
if(hasDecorations) {
|
||||
j = 0;
|
||||
itQuad = decorations.begin();
|
||||
while(itQuad != decorations.end()) {
|
||||
auto vert = itQuad->first;
|
||||
auto uvs = itQuad->second;
|
||||
|
||||
QuadMesh::bufferQuadMeshWithZ(this->meshDecorations,
|
||||
glm::vec2(vert.x, vert.y), glm::vec2(uvs.x, uvs.y),
|
||||
glm::vec2(vert.w, vert.z), glm::vec2(uvs.w, uvs.z),
|
||||
0.0f,
|
||||
j * QUAD_VERTICE_COUNT, j * QUAD_INDICE_COUNT
|
||||
);
|
||||
++j;
|
||||
++itQuad;
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer data
|
||||
shaderBuffer.buffer(&fontData);
|
||||
|
||||
// Finally, release the old locks
|
||||
itText = textsBuffered.begin();
|
||||
while(itText != textsBuffered.end()) {
|
||||
assertTrue(itText->lockId != -1, "UILabel::rebufferQuads: Lock ID cannot be -1");
|
||||
assertNotNull(itText->style.font, "UILabel::rebufferQuads: Font cannot be null");
|
||||
itText->style.font->unlock(itText->lockId);
|
||||
++itText;
|
||||
}
|
||||
|
||||
// Update
|
||||
textsBuffered = realNewTexts;
|
||||
texts = newTexts;
|
||||
|
||||
this->ignoreAlignmentUpdate = true;
|
||||
this->alignmentNeedsUpdating = true;
|
||||
|
||||
// Event
|
||||
this->eventTextChanged.invoke();
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "scene/components/ui/UIComponentRenderable.hpp"
|
||||
#include "display/mesh/QuadMesh.hpp"
|
||||
#include "asset/assets/TrueTypeAsset.hpp"
|
||||
#include "util/Xml.hpp"
|
||||
|
||||
#define UI_LABEL_MAX_WIDTH_NONE -1
|
||||
|
||||
namespace Dawn {
|
||||
struct UILabelStyle {
|
||||
struct Color color = COLOR_WHITE;
|
||||
flag_t style = 0;
|
||||
flag_t decorations = 0;
|
||||
uint32_t size = 16;
|
||||
std::shared_ptr<TrueTypeAsset> font;
|
||||
};
|
||||
|
||||
struct UILabelText {
|
||||
std::string text;
|
||||
struct UILabelStyle style;
|
||||
int32_t lineStart = 0;
|
||||
int32_t lineCount = 0;
|
||||
usagelockid_t lockId = -1;
|
||||
struct TrueTypeFaceTexture *texture = nullptr;
|
||||
};
|
||||
|
||||
struct UILabelLine {
|
||||
float_t width = 0.0f;
|
||||
float_t height = 0.0f;
|
||||
glm::vec2 position;
|
||||
int32_t quadStart = -1;
|
||||
int32_t quadCount = 0;
|
||||
};
|
||||
|
||||
enum UILabelVerticalAlign {
|
||||
UI_LABEL_VERTICAL_ALIGN_TOP,
|
||||
UI_LABEL_VERTICAL_ALIGN_MIDDLE,
|
||||
UI_LABEL_VERTICAL_ALIGN_BOTTOM
|
||||
};
|
||||
|
||||
enum UILabelTextAlign {
|
||||
UI_LABEL_TEXT_ALIGN_LEFT,
|
||||
UI_LABEL_TEXT_ALIGN_CENTER,
|
||||
UI_LABEL_TEXT_ALIGN_RIGHT
|
||||
};
|
||||
|
||||
class UILabel : public UIComponentRenderable {
|
||||
private:
|
||||
Mesh mesh;
|
||||
Mesh meshDecorations;
|
||||
FontShaderBuffer shaderBuffer;
|
||||
std::map<TrueTypeFaceTexture*, int32_t> textureMap;
|
||||
bool_t ignoreAlignmentUpdate = false;
|
||||
bool_t hasDecorations = false;
|
||||
|
||||
void updateTextAlignments();
|
||||
|
||||
public:
|
||||
int32_t quadStart = 0;
|
||||
int32_t quadCount = -1;
|
||||
int32_t quadCountTotal = -1;
|
||||
|
||||
glm::vec2 textOffset = glm::vec2(0.0f, 0.0f);
|
||||
|
||||
std::vector<struct UILabelText> texts;
|
||||
std::vector<struct UILabelText> textsBuffered;
|
||||
std::vector<struct UILabelLine> lines;
|
||||
|
||||
StateEvent<> eventTextChanged;
|
||||
|
||||
// @optional
|
||||
StateProperty<float_t> lineHeight;
|
||||
|
||||
// @optional
|
||||
StateProperty<enum UILabelTextAlign> textAlign;
|
||||
|
||||
UILabel(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
std::vector<struct ShaderPassItem> getUIRenderPasses() override;
|
||||
float_t getContentWidth() override;
|
||||
float_t getContentHeight() override;
|
||||
|
||||
/**
|
||||
* Rebuffer the quads for this label. This method will perform all the
|
||||
* necessary difference calculations from where the current state of this text is.
|
||||
*
|
||||
* @param texts Texts to buffer.
|
||||
*/
|
||||
void rebufferQuads(std::vector<struct UILabelText> texts);
|
||||
};
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UIRichTextLabel.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UIRichTextLabel::UIRichTextLabel(std::weak_ptr<SceneItem> item) :
|
||||
UILabel(item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UIRichTextLabel::onStart() {
|
||||
UILabel::onStart();
|
||||
|
||||
useEffect([&]{
|
||||
std::vector<struct UILabelStyle> styleStack;
|
||||
struct UILabelStyle current;
|
||||
styleStack.push_back(current);
|
||||
std::vector<struct UILabelText> bufferTexts;
|
||||
|
||||
if(this->richText._realValue.empty()) {
|
||||
this->rebufferQuads(bufferTexts);
|
||||
return;
|
||||
}
|
||||
|
||||
std::function<void(Xml*)> parseChildren = [&](Xml *node) {
|
||||
auto itChildren = node->childNodes.begin();
|
||||
while(itChildren != node->childNodes.end()) {
|
||||
auto child = *itChildren;
|
||||
if(child.nodeType == XML_NODE_TYPE_TEXT) {
|
||||
struct UILabelText text;
|
||||
text.style = current;
|
||||
text.text = child.value;
|
||||
bufferTexts.push_back(text);
|
||||
} else if(child.nodeType == XML_NODE_TYPE_ELEMENT) {
|
||||
auto node = child.child;
|
||||
assertTrue(node->node == "font", "UIRichTextLabel::onStart: Unknown node type '%s'", node->node.c_str());
|
||||
|
||||
struct UILabelStyle style;
|
||||
if(node->attributes.contains("font")) {
|
||||
style.font = this->getGame()->assetManager.get<TrueTypeAsset>(node->attributes["font"]);
|
||||
} else {
|
||||
style.font = current.font;
|
||||
}
|
||||
|
||||
if(node->attributes.contains("size")) {
|
||||
style.size = std::stoi(node->attributes["size"]);
|
||||
} else {
|
||||
style.size = current.size;
|
||||
}
|
||||
|
||||
if(node->attributes.contains("style")) {
|
||||
std::string s = node->attributes["style"];
|
||||
style.style = 0;
|
||||
if(s.find("bold") != std::string::npos) style.style |= TRUE_TYPE_VARIANT_BOLD;
|
||||
if(s.find("italic") != std::string::npos) style.style |= TRUE_TYPE_VARIANT_ITALICS;
|
||||
} else {
|
||||
style.style = current.style;
|
||||
}
|
||||
|
||||
if(node->attributes.contains("decoration")) {
|
||||
std::string s = node->attributes["decoration"];
|
||||
style.decorations = 0;
|
||||
if(s.find("underline") != std::string::npos) style.decorations |= TRUE_TYPE_DECORATION_UNDERLINE;
|
||||
if(s.find("strikethrough") != std::string::npos) style.decorations |= TRUE_TYPE_DECORATION_STRIKETHROUGH;
|
||||
} else {
|
||||
style.decorations = current.decorations;
|
||||
}
|
||||
|
||||
if(node->attributes.contains("color")) {
|
||||
style.color = Color::fromString(node->attributes["color"]);
|
||||
} else {
|
||||
style.color = current.color;
|
||||
}
|
||||
|
||||
styleStack.push_back(style);
|
||||
current = style;
|
||||
parseChildren(node);
|
||||
styleStack.pop_back();
|
||||
current = styleStack.back();
|
||||
}
|
||||
++itChildren;
|
||||
}
|
||||
};
|
||||
|
||||
auto root = Xml::load("<root>" + ((std::string)this->richText) + "</root>");
|
||||
parseChildren(&root);
|
||||
this->rebufferQuads(bufferTexts);
|
||||
}, this->richText)();
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UILabel.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UIRichTextLabel : public UILabel {
|
||||
public:
|
||||
// @innerXml
|
||||
StateProperty<std::string> richText;
|
||||
|
||||
UIRichTextLabel(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "UISimpleLabel.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
UISimpleLabel::UISimpleLabel(std::weak_ptr<SceneItem> i) :
|
||||
UILabel(i),
|
||||
text("Hello World"),
|
||||
font(nullptr),
|
||||
size(12),
|
||||
style(0),
|
||||
decorations(0),
|
||||
color(COLOR_WHITE)
|
||||
{
|
||||
}
|
||||
|
||||
void UISimpleLabel::onStart() {
|
||||
UILabel::onStart();
|
||||
|
||||
useEffect([&] {
|
||||
if(this->font == nullptr) {
|
||||
this->rebufferQuads({ });
|
||||
return;
|
||||
}
|
||||
|
||||
struct UILabelText text;
|
||||
struct UILabelStyle style;
|
||||
style.font = this->font;
|
||||
style.size = this->size;
|
||||
style.style = this->style;
|
||||
style.decorations = this->decorations;
|
||||
style.color = this->color;
|
||||
|
||||
text.style = style;
|
||||
text.text = this->text;
|
||||
this->rebufferQuads({ text });
|
||||
}, {
|
||||
&this->text,
|
||||
&this->font,
|
||||
&this->size,
|
||||
&this->style,
|
||||
&this->decorations,
|
||||
&this->color
|
||||
})();
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "UILabel.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class UISimpleLabel : public UILabel {
|
||||
public:
|
||||
// @optional
|
||||
StateProperty<std::string> text;
|
||||
// @optional
|
||||
StateProperty<std::shared_ptr<TrueTypeAsset>> font;
|
||||
// @optional
|
||||
StateProperty<uint32_t> size;
|
||||
// @optional
|
||||
StateProperty<flag_t> style;
|
||||
// @optional
|
||||
StateProperty<flag_t> decorations;
|
||||
// @optional
|
||||
StateProperty<struct Color> color;
|
||||
|
||||
UISimpleLabel(std::weak_ptr<SceneItem> item);
|
||||
|
||||
void onStart() override;
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
SceneDebugLine.cpp
|
||||
)
|
@ -1,208 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "SceneDebugLine.hpp"
|
||||
#include "display/shader/shaders/SimpleTexturedShader.hpp"
|
||||
#include "scene/components/display/Camera.hpp"
|
||||
#include "scene/Scene.hpp"
|
||||
#include "scene/components/physics/3d/Collider3D.hpp"
|
||||
#include "scene/components/physics/3d/CubeCollider.hpp"
|
||||
#include "scene/components/physics/2d/Collider2D.hpp"
|
||||
#include "scene/components/physics/2d/BoxCollider.hpp"
|
||||
#include "game/DawnGame.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
|
||||
struct ShaderPassItem SceneDebugLine::createShaderItem(
|
||||
Mesh *mesh,
|
||||
int32_t *lineIndex,
|
||||
Camera *camera,
|
||||
SimpleTexturedShader *shader
|
||||
) {
|
||||
assertNotNull(mesh, "SceneDebugLine::createShaderItem: Mesh cannot be null");
|
||||
assertNotNull(lineIndex, "SceneDebugLine::createShaderItem: Line Index cannot be null");
|
||||
assertNotNull(camera, "SceneDebugLine::createShaderItem: Camera cannot be null");
|
||||
assertNotNull(shader, "SceneDebugLine::createShaderItem: Shader cannot be null");
|
||||
|
||||
struct ShaderPassItem item;
|
||||
item.shader = shader;
|
||||
item.priority = this->priority;
|
||||
item.colorValues[shader->paramColor] = this->color;
|
||||
item.matrixValues[shader->paramModel] = this->transform;
|
||||
item.parameterBuffers[shader->bufferRenderPipeline] = &camera->getGame()->renderManager.getRenderPipeline()->shaderBuffer;
|
||||
item.boolValues[shader->paramHasTexture] = false;
|
||||
|
||||
auto i = *lineIndex;
|
||||
item.mesh = mesh;
|
||||
item.drawMode = MESH_DRAW_MODE_LINES;
|
||||
item.renderFlags = RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST;
|
||||
item.start = i * SCENE_DEBUG_LINE_INDICE_COUNT;
|
||||
item.count = SCENE_DEBUG_LINE_INDICE_COUNT;
|
||||
|
||||
glm::vec3 positions[SCENE_DEBUG_LINE_VERTICE_COUNT] = { this->v0, this->v1 };
|
||||
mesh->bufferPositions(
|
||||
i * SCENE_DEBUG_LINE_VERTICE_COUNT,
|
||||
positions,
|
||||
SCENE_DEBUG_LINE_VERTICE_COUNT
|
||||
);
|
||||
|
||||
meshindice_t indices[SCENE_DEBUG_LINE_INDICE_COUNT] = {
|
||||
i * SCENE_DEBUG_LINE_VERTICE_COUNT,
|
||||
(i*SCENE_DEBUG_LINE_VERTICE_COUNT) + 1
|
||||
};
|
||||
mesh->bufferIndices(
|
||||
i * SCENE_DEBUG_LINE_INDICE_COUNT,
|
||||
indices,
|
||||
SCENE_DEBUG_LINE_INDICE_COUNT
|
||||
);
|
||||
return item;
|
||||
}
|
||||
|
||||
// Scene Implementations (done here to keep things cleaner in scene)
|
||||
void Scene::debugLine(struct SceneDebugLine line) {
|
||||
this->debugLines.push_back(line);
|
||||
}
|
||||
|
||||
void Scene::debugRay(struct SceneDebugRay ray) {
|
||||
struct SceneDebugLine line;
|
||||
line.v0 = ray.start;
|
||||
line.v1 = ray.start + ray.direction;
|
||||
line.color = ray.color;
|
||||
this->debugLine(line);
|
||||
}
|
||||
|
||||
void Scene::debugCube(struct SceneDebugCube cube) {
|
||||
auto min = cube.min;
|
||||
auto max = cube.max;
|
||||
|
||||
struct SceneDebugLine line;
|
||||
line.color = cube.color;
|
||||
line.transform = cube.transform;
|
||||
|
||||
// Bottom Face
|
||||
line.v0 = glm::vec3(min.x, min.y, min.z), line.v1 = glm::vec3(max.x, min.y, min.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(min.x, min.y, min.z), line.v1 = glm::vec3(min.x, min.y, max.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(max.x, min.y, min.z), line.v1 = glm::vec3(max.x, min.y, max.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(min.x, min.y, max.z), line.v1 = glm::vec3(max.x, min.y, max.z);
|
||||
this->debugLine(line);
|
||||
|
||||
// Top Face
|
||||
line.v0 = glm::vec3(min.x, max.y, min.z), line.v1 = glm::vec3(max.x, max.y, min.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(min.x, max.y, min.z), line.v1 = glm::vec3(min.x, max.y, max.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(max.x, max.y, min.z), line.v1 = glm::vec3(max.x, max.y, max.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(min.x, max.y, max.z), line.v1 = glm::vec3(max.x, max.y, max.z);
|
||||
this->debugLine(line);
|
||||
|
||||
// Rails
|
||||
line.v0 = glm::vec3(min.x, min.y, min.z), line.v1 = glm::vec3(min.x, max.y, min.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(max.x, min.y, min.z), line.v1 = glm::vec3(max.x, max.y, min.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(min.x, min.y, max.z), line.v1 = glm::vec3(min.x, max.y, max.z);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(max.x, min.y, max.z), line.v1 = glm::vec3(max.x, max.y, max.z);
|
||||
this->debugLine(line);
|
||||
}
|
||||
|
||||
void Scene::debugOrigin() {
|
||||
struct SceneDebugLine line;
|
||||
line.v1 = glm::vec3(1, 0, 0), line.color = COLOR_RED;
|
||||
this->debugLine(line);
|
||||
line.v1 = glm::vec3(0, 1, 0), line.color = COLOR_GREEN;
|
||||
this->debugLine(line);
|
||||
line.v1 = glm::vec3(0, 0, 1), line.color = COLOR_BLUE;
|
||||
this->debugLine(line);
|
||||
}
|
||||
|
||||
void Scene::debugGrid() {
|
||||
float_t s = 10.0f;
|
||||
float_t t = 1.0f;
|
||||
|
||||
struct SceneDebugLine line;
|
||||
line.color = COLOR_LIGHT_GREY;
|
||||
line.color.a = 0.2f;
|
||||
|
||||
line.v0 = glm::vec3(-s, 0, -s), line.v1 = glm::vec3(s, 0, -s);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(-s, 0, -s), line.v1 = glm::vec3(-s, 0, s);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(s, 0, -s), line.v1 = glm::vec3(s, 0, s);
|
||||
this->debugLine(line);
|
||||
line.v0 = glm::vec3(-s, 0, s), line.v1 = glm::vec3(s, 0, s);
|
||||
this->debugLine(line);
|
||||
|
||||
for(float_t x = -s+t; x < s; x += t) {
|
||||
line.v0 = glm::vec3(x, 0, -s), line.v1 = glm::vec3(x, 0, s);
|
||||
this->debugLine(line);
|
||||
}
|
||||
|
||||
for(float_t z = -s+t; z < s; z += t) {
|
||||
line.v0 = glm::vec3(-s, 0, z), line.v1 = glm::vec3(s, 0, z);
|
||||
this->debugLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::debugHitboxes() {
|
||||
auto colliders = this->findComponents<Collider3D>();
|
||||
auto itColliders = colliders.begin();
|
||||
while(itColliders != colliders.end()) {
|
||||
auto c = *itColliders;
|
||||
switch(c->getColliderType()) {
|
||||
case COLLIDER3D_TYPE_CUBE:
|
||||
auto asCube = dynamic_cast<CubeCollider*>(c);
|
||||
struct SceneDebugCube c2;
|
||||
c2.min = asCube->min;
|
||||
c2.max = asCube->max;
|
||||
c2.color = COLOR_BLUE;
|
||||
c2.transform = asCube->transform->getWorldTransform();
|
||||
|
||||
this->debugCube(c2);
|
||||
break;
|
||||
}
|
||||
++itColliders;
|
||||
}
|
||||
|
||||
auto colliders2d = this->findComponents<Collider2D>();
|
||||
auto itColliders2 = colliders2d.begin();
|
||||
while(itColliders2 != colliders2d.end()) {
|
||||
auto c = *itColliders2;
|
||||
switch(c->getColliderType()) {
|
||||
case COLLIDER2D_TYPE_BOX:
|
||||
auto asBox = dynamic_cast<BoxCollider*>(c);
|
||||
this->debugLine({
|
||||
.v0 = glm::vec3(asBox->min.x, 0, asBox->min.y),
|
||||
.v1 = glm::vec3(asBox->max.x, 0, asBox->min.y),
|
||||
.color = COLOR_BLUE,
|
||||
.transform = c->transform->getWorldTransform()
|
||||
});
|
||||
this->debugLine({
|
||||
.v0 = glm::vec3(asBox->max.x, 0, asBox->min.y),
|
||||
.v1 = glm::vec3(asBox->max.x, 0, asBox->max.y),
|
||||
.color = COLOR_BLUE,
|
||||
.transform = c->transform->getWorldTransform()
|
||||
});
|
||||
this->debugLine({
|
||||
.v0 = glm::vec3(asBox->max.x, 0, asBox->max.y),
|
||||
.v1 = glm::vec3(asBox->min.x, 0, asBox->max.y),
|
||||
.color = COLOR_BLUE,
|
||||
.transform = c->transform->getWorldTransform()
|
||||
});
|
||||
this->debugLine({
|
||||
.v0 = glm::vec3(asBox->min.x, 0, asBox->max.y),
|
||||
.v1 = glm::vec3(asBox->min.x, 0, asBox->min.y),
|
||||
.color = COLOR_BLUE,
|
||||
.transform = c->transform->getWorldTransform()
|
||||
});
|
||||
break;
|
||||
}
|
||||
++itColliders2;
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "display/Color.hpp"
|
||||
#include "display/mesh/Mesh.hpp"
|
||||
#include "display/shader/ShaderManager.hpp"
|
||||
#include "display/shader/ShaderPass.hpp"
|
||||
|
||||
#define SCENE_DEBUG_LINE_VERTICE_COUNT 2
|
||||
#define SCENE_DEBUG_LINE_INDICE_COUNT 2
|
||||
#define SCENE_DEBUG_LINE_PRIORITY 100
|
||||
|
||||
namespace Dawn {
|
||||
class SimpleTexturedShader;
|
||||
class Camera;
|
||||
|
||||
struct SceneDebugCube {
|
||||
glm::vec3 min;
|
||||
glm::vec3 max;
|
||||
struct Color color = COLOR_RED;
|
||||
glm::mat4 transform = glm::mat4(1.0f);
|
||||
};
|
||||
|
||||
struct SceneDebugRay {
|
||||
glm::vec3 start;
|
||||
glm::vec3 direction;
|
||||
struct Color color = COLOR_RED;
|
||||
};
|
||||
|
||||
struct SceneDebugLine {
|
||||
glm::vec3 v0 = glm::vec3(0, 0, 0);
|
||||
glm::vec3 v1 = glm::vec3(1, 1, 1);
|
||||
struct Color color = COLOR_RED;
|
||||
glm::mat4 transform = glm::mat4(1.0f);
|
||||
int32_t priority = SCENE_DEBUG_LINE_PRIORITY;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a renderable shader item for this debug line.
|
||||
*
|
||||
* @param mesh Mesh that this debug line will buffer its indices in to
|
||||
* @param lineIndex Currently iterated line index.
|
||||
* @param camera Camera for this line index to set the shader params for.
|
||||
* @param shader Shader that the params will be set for.
|
||||
* @return The queueable shader pass item.
|
||||
*/
|
||||
struct ShaderPassItem createShaderItem(
|
||||
Mesh *mesh,
|
||||
int32_t *lineIndex,
|
||||
Camera *camera,
|
||||
SimpleTexturedShader *shader
|
||||
);
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user