Base refactor

This commit is contained in:
2023-11-14 09:16:48 -06:00
parent 214082d00f
commit 1817dcaf3a
410 changed files with 749 additions and 20823 deletions

View File

@ -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()

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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();
}
}

View File

@ -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();
};
}

View File

@ -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() {
}

View File

@ -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>();
}
}

View File

@ -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)

View File

@ -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
)

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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;
};
}

View File

@ -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();
}

View File

@ -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();
};
}

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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();
}

View File

@ -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;
};
}

View File

@ -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
})();
}

View File

@ -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;
};
}

View File

@ -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
)

View File

@ -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 })();
}

View File

@ -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;
};
}

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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)
{
}

View File

@ -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);
};
}

View File

@ -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;
}
}

View File

@ -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;
};
}

View File

@ -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 })();
}

View File

@ -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;
};
}

View File

@ -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
)

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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
)

View File

@ -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();
}

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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() {
}

View File

@ -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;
};
}

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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();
}

View File

@ -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;
};
}

View File

@ -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; }

View File

@ -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;
};
}

View File

@ -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
);
}

View File

@ -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;
};
}

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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
)

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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();
};
}

View File

@ -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
)

View File

@ -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();
}

View File

@ -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);
};
}

View File

@ -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)();
}

View File

@ -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;
};
}

View File

@ -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
})();
}

View File

@ -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;
};
}

View File

@ -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
)

View File

@ -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;
}
}

View File

@ -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
);
};
}