UI Hello World

This commit is contained in:
2022-10-23 01:01:16 -07:00
parent be529b70c1
commit 182eb70361
25 changed files with 663 additions and 41 deletions

View File

@ -18,4 +18,5 @@ target_include_directories(${DAWN_TARGET_NAME}
# Subdirs
add_subdirectory(asset)
add_subdirectory(display)
add_subdirectory(scene)
add_subdirectory(scene)
add_subdirectory(ui)

View File

@ -5,6 +5,7 @@
#include "RenderPipeline.hpp"
#include "game/DawnGame.hpp"
#include "display/mesh/QuadMesh.hpp"
using namespace Dawn;
@ -44,6 +45,14 @@ void RenderPipeline::renderScene(Scene &scene) {
// Now render the backbuffer camera.
if(backBufferCamera == nullptr) return;
this->renderSceneCamera(scene, *backBufferCamera);
// Now we try and render UI components
auto uiCanvasList = scene.findComponents<UICanvas>();
auto itCanvas = uiCanvasList.begin();
while(itCanvas != uiCanvasList.end()) {
this->renderUI(scene, *backBufferCamera, **itCanvas);
++itCanvas;
}
}
void RenderPipeline::renderSceneCamera(Scene &scene, Camera &camera) {
@ -53,6 +62,10 @@ void RenderPipeline::renderSceneCamera(Scene &scene, Camera &camera) {
RENDER_TARGET_CLEAR_FLAG_DEPTH |
RENDER_TARGET_CLEAR_FLAG_COLOR
);
this->renderManager.setRenderFlags(
RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST |
RENDER_MANAGER_RENDER_FLAG_BLEND
);
auto meshes = scene.findComponents<MeshRenderer>();
auto it = meshes.begin();
@ -77,6 +90,51 @@ void RenderPipeline::renderSceneCamera(Scene &scene, Camera &camera) {
}
}
void RenderPipeline::renderUI(
Scene &scene,
Camera &camera,
UICanvas &canvas
) {
// Get the
RenderTarget *renderTarget;
glm::mat4 transform;
glm::mat4 projection;
switch(canvas.drawType) {
case UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE:
transform = glm::mat4(1.0f);
projection = glm::ortho(0.0f, canvas.getWidth(), canvas.getHeight(), 0.0f);
renderTarget = &camera.getRenderTarget();
break;
default:
throw "UI Draw modes are not yet supported.";
}
// Clear / Bind / Update the render target.
renderTarget->bind();
renderTarget->clear(
RENDER_TARGET_CLEAR_FLAG_DEPTH |
RENDER_TARGET_CLEAR_FLAG_COLOR
);
this->renderManager.setRenderFlags(
RENDER_MANAGER_RENDER_FLAG_BLEND |
RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST
);
// Prepare the UI Shader
auto shader = this->renderManager.getUIShader();
shader->bind();
shader->setUICamera(transform, projection);
// Render the children
glm::mat4 rootMatrix = canvas.transform.getWorldTransform();
auto it = canvas.children.begin();
while(it != canvas.children.end()) {
(*it)->draw(*shader, rootMatrix);
++it;
}
}
RenderPipeline::~RenderPipeline() {
}

View File

@ -8,6 +8,8 @@
#include "display/RenderManager.hpp"
#include "scene/Scene.hpp"
#include "scene/components/Components.hpp"
#include "scene/components/ui/UICanvas.hpp"
#include "ui/UIComponent.hpp"
namespace Dawn {
class RenderPipeline {
@ -49,6 +51,19 @@ namespace Dawn {
*/
virtual void renderSceneCamera(Scene &scene, Camera &camera);
/**
* Renders a UI Canvas to the back buffer.
*
* @param scene Scene for the UI canvas.
* @param camera Main backbuffer camera for the canvas.
* @param canvas Canvas to render.
*/
virtual void renderUI(
Scene &scene,
Camera &camera,
UICanvas &canvas
);
/**
* Cleanup a render pipeline that has been initialized.
*/

View File

@ -79,7 +79,7 @@ void Transform::setLocalPosition(glm::vec3 position) {
}
glm::vec3 Transform::getLocalScale() {
return this->scale;
return this->localScale;
}
void Transform::setLocalScale(glm::vec3 scale) {
@ -140,6 +140,9 @@ void Transform::setParent(Transform *parent) {
this->parent = parent;
if(parent != nullptr) parent->children.push_back(this);
this->updateLocalTransformFromWorldTransform();
this->updateChildrenTransforms();
}
Transform * Transform::getParent() {
@ -148,6 +151,7 @@ Transform * Transform::getParent() {
Transform::~Transform() {
this->setParent(nullptr);
auto it = this->parent->children.begin();
while(it != this->parent->children.end()) {
(*it)->setParent(nullptr);

View File

@ -21,9 +21,9 @@ namespace Dawn {
glm::mat4 transformLocal;
glm::mat4 transformWorld;
glm::vec3 position;
glm::vec3 scale;
glm::quat rotation;
// glm::vec3 position;
// glm::vec3 scale;
// glm::quat rotation;
// Heirarchy
Transform *parent = nullptr;

View File

@ -6,12 +6,22 @@
#pragma once
#include "RenderTarget.hpp"
#include "display/shader/Shader.hpp"
#include "display/shader/UIShader.hpp"
#include "util/flag.hpp"
#define RENDER_MANAGER_RENDER_FLAG_DEPTH_TEST FLAG_DEFINE(0)
#define RENDER_MANAGER_RENDER_FLAG_BLEND FLAG_DEFINE(1)
typedef flag_t renderflag_t;
namespace Dawn {
class DawnGame;
class RenderPipeline;
class IRenderManager {
protected:
renderflag_t renderFlags = 0;
public:
DawnGame &game;
std::shared_ptr<RenderPipeline> renderPipeline;
@ -47,6 +57,20 @@ namespace Dawn {
*/
virtual std::shared_ptr<Shader> getDefaultShader() = 0;
/**
* Returns the UI Shader used by the game's UI engine.
*
* @return Pointer to the UI Shader.
*/
virtual std::shared_ptr<UIShader> getUIShader() = 0;
/**
* Sets the render flags for the render manager to use.
*
* @param renderFlags Render flags to use.
*/
virtual void setRenderFlags(renderflag_t renderFlags) = 0;
/**
* Initialize / Start the Render Manager.
*

View File

@ -35,4 +35,15 @@ void QuadMesh::bufferQuadMeshWithZ(
verticeStart + 1, verticeStart + 2, verticeStart + 3
}}
);
}
void QuadMesh::bufferQuadMesh(
Mesh &mesh,
glm::vec2 xy0, glm::vec2 uv0,
glm::vec2 xy1, glm::vec2 uv1,
int32_t verticeStart, int32_t indiceStart
) {
QuadMesh::bufferQuadMeshWithZ(
mesh, xy0, uv0, xy1, uv1, 0, verticeStart, indiceStart
);
}

View File

@ -35,5 +35,4 @@ std::shared_ptr<SceneItem> Scene::createSceneItem() {
}
Scene::~Scene() {
std::cout << "What the dick" << std::endl;
}

View File

@ -71,6 +71,42 @@ namespace Dawn {
}
return nullptr;
}
/**
* 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->transform.children.begin();
while(it != this->transform.children.end()) {
auto child = (*it)->item.getComponent<T>();
if(child != nullptr) return child;
++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->transform.children.begin();
std::vector<std::shared_ptr<T>> children;
while(it != this->transform.children.end()) {
auto child = (*it)->item.getComponent<T>();
if(child != nullptr) children.push_back(child);
++it;
}
return children;
}
/**
* Destroy this SceneItem.

View File

@ -4,4 +4,5 @@
# https://opensource.org/licenses/MIT
# Subdirs
add_subdirectory(display)
add_subdirectory(display)
add_subdirectory(ui)

View File

@ -0,0 +1,10 @@
# 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
)

View File

@ -0,0 +1,32 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UICanvas.hpp"
#include "scene/Scene.hpp"
#include "ui/UIComponent.hpp"
#include "game/DawnGame.hpp"
using namespace Dawn;
std::shared_ptr<UICanvas> UICanvas::createCanvas(std::shared_ptr<Scene> scene) {
auto item = scene->createSceneItem();
return item->addComponent<UICanvas>();
}
UICanvas::UICanvas(SceneItem &item) : SceneItemComponent(item) {
}
float_t UICanvas::getWidth() {
return this->getGame().renderManager.getBackBuffer().getWidth();
}
float_t UICanvas::getHeight() {
return this->getGame().renderManager.getBackBuffer().getHeight();
}
void UICanvas::start() {
}

View File

@ -0,0 +1,42 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/SceneItemComponent.hpp"
namespace Dawn {
enum UIDrawType {
UI_DRAW_TYPE_WORLD_ABSOLUTE,
UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE,
UI_DRAW_TYPE_CAMERA_OVERLAY
};
class UIComponent;
class UICanvas : public SceneItemComponent {
public:
static std::shared_ptr<UICanvas> createCanvas(
std::shared_ptr<Scene> scene
);
//
std::vector<std::shared_ptr<UIComponent>> children;
UIDrawType drawType = UI_DRAW_TYPE_WORLD_CAMERA_RELATIVE;
UICanvas(SceneItem &item);
template<class T>
std::shared_ptr<T> addElement() {
auto item = std::make_shared<T>(*this);
this->children.push_back(item);
return item;
}
float_t getWidth();
float_t getHeight();
void start() override;
};
}

View File

@ -0,0 +1,11 @@
# 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
UIComponent.cpp
UISprite.cpp
)

119
src/dawn/ui/UIComponent.cpp Normal file
View File

@ -0,0 +1,119 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UIComponent.hpp"
using namespace Dawn;
UIComponent::UIComponent(UICanvas &canvas) :
canvas(canvas)
{
}
void UIComponent::updatePositions() {
// X Alignment
if(this->alignX == UI_COMPONENT_ALIGN_STRETCH) {
if(this->parent == nullptr) {
this->width = this->canvas.getWidth();
} else {
this->width = this->parent->getWidth();
}
this->relativeX = this->alignment[0];
this->width -= (this->alignment[0] + this->alignment[2]);
} else {
this->relativeX = this->alignment[0];
this->width = this->alignment[2];
}
// Y Alignment
if(this->alignY == UI_COMPONENT_ALIGN_STRETCH) {
if(this->parent == nullptr) {
this->height = this->canvas.getHeight();
} else {
this->height = this->parent->getHeight();
}
this->relativeY = this->alignment[1];
this->height -= (this->alignment[1] + this->alignment[3]);
} else {
this->relativeY = this->alignment[1];
this->height = this->alignment[3];
}
// Update children
auto it = this->children.begin();
while(it != this->children.end()) {
(*it)->updatePositions();
++it;
}
}
float_t UIComponent::getWidth() {
return this->width;
}
float_t UIComponent::getHeight() {
return this->height;
}
float_t UIComponent::getRelativeX() {
return this->relativeX;
}
float_t UIComponent::getRelativeY() {
return this->relativeY;
}
void UIComponent::setTransform(
UIComponentAlign xAlign,
UIComponentAlign yAlign,
glm::vec4 alignment,
float_t z
) {
this->alignX = xAlign;
this->alignY = yAlign;
this->alignment = alignment;
this->z = z;
this->updatePositions();
}
void UIComponent::draw(UIShader &uiShader, glm::mat4 parentTransform) {
// Calculate self transform matrix
glm::mat4 selfTransform = parentTransform * glm::translate(
glm::mat4(1.0f), glm::vec3(this->relativeX, this->relativeY, this->z)
);
// Draw Self
this->drawSelf(uiShader, selfTransform);
// Render children
auto it = this->children.begin();
while(it != this->children.end()) {
(*it)->draw(uiShader, selfTransform);
++it;
}
}
void UIComponent::addChild(std::shared_ptr<UIComponent> child) {
if(child->parent == this) return;
if(child->parent != nullptr) child->parent->removeChild(child);
this->children.push_back(child);
child->parent = this;
}
void UIComponent::removeChild(std::shared_ptr<UIComponent> child) {
if(child->parent != this) throw "Invalid child";
auto it = this->children.begin();
while(it != this->children.end()) {
if(it->get() == child.get()) {
this->children.erase(it);
break;
}
++it;
}
}
UIComponent::~UIComponent() {
}

View File

@ -0,0 +1,75 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/components/ui/UICanvas.hpp"
#include "scene/Scene.hpp"
#include "display/Color.hpp"
#include "display/shader/UIShader.hpp"
namespace Dawn {
enum UIComponentAlign {
UI_COMPONENT_ALIGN_START,
UI_COMPONENT_ALIGN_MIDDLE,
UI_COMPONENT_ALIGN_END,
UI_COMPONENT_ALIGN_STRETCH
};
class UIComponent {
protected:
// Calculated (and cached) values
float_t width = 1;
float_t height = 1;
float_t relativeX = 0;
float_t relativeY = 0;
// Setting values
UIComponentAlign alignX = UI_COMPONENT_ALIGN_START;
UIComponentAlign alignY = UI_COMPONENT_ALIGN_START;
glm::vec4 alignment = glm::vec4(0, 0, 1, 1);
float_t z = 0;
std::vector<std::shared_ptr<UIComponent>> children;
UIComponent *parent = nullptr;
// I currently don't support rotation or scale. Not because I can't but
// because it's basically un-necessary. Unity does support rotation but
// it doesn't affect how the alignment side of things work (similar to how
// CSS would handle things) When I need to support these I will add the
// code but right now it's not necessary
/**
* Updates the cached/stored values based on the setting internal values.
* You should watchdog this if you intend to do something when values are
* updated, e.g. if you need to resize a quad, or something.
*/
virtual void updatePositions();
public:
UICanvas &canvas;
UIComponent(UICanvas &canvas);
float_t getWidth();
float_t getHeight();
float_t getRelativeX();
float_t getRelativeY();
void setTransform(
UIComponentAlign xAlign,
UIComponentAlign yAlign,
glm::vec4 alignment,
float_t z
);
// virtual void update() = 0;
void draw(UIShader &uiShader, glm::mat4 parentTransform);
virtual void drawSelf(UIShader &uiShader, glm::mat4 selfTransform) = 0;
void addChild(std::shared_ptr<UIComponent> chidl);
void removeChild(std::shared_ptr<UIComponent> child);
virtual ~UIComponent();
};
}

34
src/dawn/ui/UISprite.cpp Normal file
View File

@ -0,0 +1,34 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "UISprite.hpp"
using namespace Dawn;
UISprite::UISprite(UICanvas &canvas) : UIComponent(canvas) {
this->mesh.createBuffers(QUAD_VERTICE_COUNT, QUAD_INDICE_COUNT);
}
void UISprite::updatePositions() {
UIComponent::updatePositions();
std::cout << "Updating" << std::endl;
QuadMesh::bufferQuadMesh(
this->mesh,
glm::vec2(0, 0), glm::vec2(0, 0),
glm::vec2(this->width, this->height), glm::vec2(1, 1),
0, 0
);
}
void UISprite::drawSelf(UIShader &uiShader, glm::mat4 selfTransform) {
uiShader.setUITexture(nullptr);
uiShader.setUIModel(selfTransform);
uiShader.setUIModel(glm::mat4(1.0f));
uiShader.setUIColor(COLOR_WHITE);
this->mesh.draw(MESH_DRAW_MODE_TRIANGLES, 0, -1);
}

23
src/dawn/ui/UISprite.hpp Normal file
View File

@ -0,0 +1,23 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "UIComponent.hpp"
#include "display/mesh/QuadMesh.hpp"
namespace Dawn {
class UISprite : public UIComponent {
protected:
void updatePositions() override;
public:
Mesh mesh;
UISprite(UICanvas &canvas);
// void update() override;
void drawSelf(UIShader &uiShader, glm::mat4 selfTransform) override;
};
}

View File

@ -7,5 +7,9 @@
#include "dawnlibs.hpp"
typedef uint_fast8_t flag8_t;
typedef uint_fast16_t flag16_t;
typedef uint_fast32_t flag32_t;
typedef flag32_t flag_t;
#define FLAG_DEFINE(n) (1 << n)