New scene items system

This commit is contained in:
2023-11-15 18:56:25 -06:00
parent 1817dcaf3a
commit 6c6203a41d
38 changed files with 1309 additions and 36 deletions

View File

@ -20,6 +20,7 @@ target_include_directories(${DAWN_TARGET_NAME}
add_subdirectory(assert)
# add_subdirectory(asset)
# add_subdirectory(audio)
add_subdirectory(component)
# add_subdirectory(display)
add_subdirectory(game)
# add_subdirectory(games)
@ -28,7 +29,7 @@ add_subdirectory(game)
# add_subdirectory(prefab)
# add_subdirectory(physics)
# add_subdirectory(save)
# add_subdirectory(scene)
add_subdirectory(scene)
# add_subdirectory(state)
# add_subdirectory(time)
# add_subdirectory(util)

View File

@ -0,0 +1,12 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# target_sources(${DAWN_TARGET_NAME}
# PRIVATE
# Game.cpp
# )
# Subdirs
add_subdirectory(display)

View File

@ -0,0 +1,9 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Camera.cpp
)

View File

@ -0,0 +1,37 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Camera.hpp"
using namespace Dawn;
void Camera::onInit() {
std::cout << "Camera" << std::endl;
}
glm::mat4 Camera::getProjection() {
switch(this->type) {
case CameraType::ORTHOGONAL:
return 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
);
case CameraType::PERSPECTIVE:
return glm::perspective(
(float_t)this->fov,
this->getAspect(),
(float_t)this->clipNear,
(float_t)this->clipFar
);
}
assertUnreachable("Invalid Camera Type!");
return glm::mat4(1.0f);
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/SceneItem.hpp"
namespace Dawn {
enum CameraType {
PERSPECTIVE,
ORTHOGONAL
};
class Camera : public SceneComponent {
public:
float_t clipNear = 0.01f;
float_t clipFar = 1000.0f;
enum CameraType type = CameraType::PERSPECTIVE;
float_t fov = 0.785398f;
float_t orthoLeft = -1.0f;
float_t orthoRight = 1.0f;
float_t orthoBottom = -1.0f;
float_t orthoTop = 1.0f;
// std::shared_ptr<RenderTarget> renderTarget;
void onInit() override;
/**
* Returns the aspect ratio that the camera is using. In future I may
* allow you to specify a custom ratio for stylistic reasons but for now I
* just take the ratio of the specific frame buffer.
*
* @return The aspect ratio as a ratio of w/h.
*/
float_t getAspect();
/**
* Returns the projection matrix for this camera.
*
* @return Projection matrix.
*/
glm::mat4 getProjection();
};
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/SceneItem.hpp"
namespace Dawn {
class MeshRenderer : public SceneComponent {
public:
std::shared_ptr<Mesh> mesh;
void onInit() override;
};
}

View File

@ -0,0 +1,44 @@
// 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 Game;
class IRenderHost {
public:
/**
* Initializes the render host, called by the game during the initial
* set up of the engine.
*
* @param game Game that requested the render host to initialize.
*/
virtual void init(const std::shared_ptr<Game> game) = 0;
/**
* Performs an update/tick of the render host. This would be the game
* asking the RenderHost to the rendering.
*/
virtual void update() = 0;
/**
* Overridable request from the game that asks if the RenderHost has any
* reason that it should need to close. For most libraries this would be
* whether or not the window was closed.
*
* @return True if the render host requests the game to gracefully exit.
*/
virtual bool_t isCloseRequested() = 0;
/**
* Destroys the render host.
*/
virtual ~IRenderHost() {
}
};
}

View File

@ -0,0 +1,103 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnlibs.hpp"
namespace Dawn {
enum MeshDrawMode {
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLE_FAN,
LINES,
POINTS
// LINE_STRIP,
};
class IMesh {
protected:
/** How many vertices are in the mesh */
int32_t verticeCount = -1;
/** How many indices are in the mesh */
int32_t indiceCount = -1;
public:
/**
* Create a new set of buffers for the mesh to use.
*
* @param verticeCount How many Vertices will this buffer support.
* @param indiceCount How many Indices will this buffer support.
*/
virtual void createBuffers(
const int32_t verticeCount,
const int32_t indiceCount
) = 0;
/**
* Cleanup the buffers on a given mesh. This is useful if you intend to
* expand the count of vertices your mesh supports.
*/
virtual void disposeBuffers() = 0;
/**
* Write vertice positions to the mesh.
*
* @param pos Position, within the buffer, to write to.
* @param vertices Array of positions to write.
* @param len How many positions are in the array.
*/
virtual void bufferPositions(
const int32_t pos,
const glm::vec3 positions[],
const int32_t len
) = 0;
/**
* Write vertice coordinates to the mesh.
*
* @param pos Position, within the buffer, to write to.
* @param coordinates Array of coordinates to write.
* @param len How many coordinates are in the array.
*/
virtual void bufferCoordinates(
const int32_t pos,
const glm::vec2 coordinates[],
const int32_t len
) = 0;
/**
* Write indices to the mesh.
*
* @param pos Position, within the buffer, to write to.
* @param indices Array of indices to write.
* @param len How many indices are in the array.
*/
virtual void bufferIndices(
const int32_t pos,
const int32_t indices[],
const int32_t len
) = 0;
/**
* Draw a primitive. Primitives are drawn by their indices.
*
* @param drawMode Which drawing mode to use to draw the primitive.
* @param start Start indice (index) to draw.
* @param count Count of indices to draw. Use -1 to draw all.
*/
virtual void draw(
const enum MeshDrawMode drawMode,
const int32_t start,
const int32_t count
) = 0;
/**
* Cleanup a previously initiated mesh.
*/
virtual ~IMesh() {
this->disposeBuffers();
}
};
}

View File

@ -3,7 +3,9 @@
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Game.hpp"
#include "game/Game.hpp"
#include "game/GameInit.hpp"
#include "scene/Scene.hpp"
using namespace Dawn;
@ -12,12 +14,21 @@ Game::Game() {
}
void Game::init() {
renderHost.init();
renderHost.init(shared_from_this());
inputManager.init(shared_from_this());
auto initialScene = GameInit::getInitialScene();
nextFrameScene = std::make_shared<Scene>(shared_from_this(), initialScene);
}
void Game::update() {
renderHost.update();
if(nextFrameScene) {
nextFrameScene->stage();
currentScene = nextFrameScene;
nextFrameScene = nullptr;
}
}
bool_t Game::isCloseRequested() {
@ -27,5 +38,5 @@ bool_t Game::isCloseRequested() {
}
Game::~Game() {
std::cout << "Game successfully destructed" << std::endl;
}

View File

@ -9,7 +9,13 @@
#include "input/InputManager.hpp"
namespace Dawn {
class Scene;
class Game : public std::enable_shared_from_this<Game> {
private:
std::shared_ptr<Scene> currentScene;
std::shared_ptr<Scene> nextFrameScene;
public:
RenderHost renderHost;
InputManager inputManager;

View File

@ -0,0 +1,15 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "game/Game.hpp"
#include "scene/Scene.hpp"
namespace Dawn {
class GameInit {
public:
static std::function<void(Scene&)> getInitialScene();
};
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Scene.cpp
SceneItem.cpp
SceneComponent.cpp
)
# Subdirs
add_subdirectory(item)

36
src/dawn/scene/Scene.cpp Normal file
View File

@ -0,0 +1,36 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Scene.hpp"
using namespace Dawn;
Scene::Scene(
const std::weak_ptr<Game> game,
const std::function<void(Scene&)> sceneInitializer
) :
game(game),
sceneInitializer(sceneInitializer)
{
}
void Scene::stage() {
Scene &selfReference = *this;
sceneInitializer(selfReference);
}
std::shared_ptr<Game> Scene::getGame() {
return game.lock();
}
std::shared_ptr<SceneItem> Scene::createSceneItem() {
auto item = std::make_shared<SceneItem>(shared_from_this());
sceneItems.push_back(item);
return item;
}
Scene::~Scene() {
}

52
src/dawn/scene/Scene.hpp Normal file
View File

@ -0,0 +1,52 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "game/Game.hpp"
#include "scene/SceneItem.hpp"
namespace Dawn {
class Scene final : public std::enable_shared_from_this<Scene> {
private:
std::weak_ptr<Game> game;
const std::function<void(Scene&)> sceneInitializer;
std::vector<std::shared_ptr<SceneItem>> sceneItems;
public:
/**
* Constructs a scene object.
*
* @param game Game that initialized this scene.
*/
Scene(
const std::weak_ptr<Game> game,
const std::function<void(Scene&)> sceneInitializer
);
/**
* Stages all of the scene items on the scene.
*/
void stage();
/**
* Returns a copy of the game instance that this scene belongs to.
*
* @return Shared pointer to the game instance.
*/
std::shared_ptr<Game> getGame();
/**
* Creates a scene item that belongs to this scene.
*
* @return Pointer to the new scene item.
*/
std::shared_ptr<SceneItem> createSceneItem();
/**
* Destroys the scene object and cleans up all of its children.
*/
virtual ~Scene();
};
}

View File

@ -0,0 +1,17 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "SceneComponent.hpp"
using namespace Dawn;
void SceneComponent::init(const std::shared_ptr<SceneItem> item) {
this->item = item;
this->onInit();
}
std::shared_ptr<SceneItem> SceneComponent::getItem() {
return this->item.lock();
}

View File

@ -0,0 +1,38 @@
// 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 SceneItem;
class SceneComponent : std::enable_shared_from_this<SceneComponent> {
private:
std::weak_ptr<SceneItem> item;
protected:
/**
* Custom component listener that is invoked when the component is meant
* to initialize.
*/
virtual void onInit() = 0;
public:
/**
* Initializes this scene component.
*
* @param item Scene item that this component belongs to.
*/
void init(const std::shared_ptr<SceneItem> item);
/**
* Returns the scene item that this scene component belongs to.
*
* @return Reference to the scene item that this component belongs to.
*/
std::shared_ptr<SceneItem> getItem();
};
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "scene/SceneItem.hpp"
#include "scene/Scene.hpp"
using namespace Dawn;
SceneItem::SceneItem(const std::weak_ptr<Scene> scene) :
scene(scene),
SceneItemTransform(),
SceneItemComponents()
{
}
std::shared_ptr<SceneItem> SceneItem::sceneItemComponentsSelf() {
return shared_from_this();
}
std::shared_ptr<Scene> SceneItem::getScene() {
return scene.lock();
}
SceneItem::~SceneItem() {
}

View File

@ -0,0 +1,46 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/item/SceneItemTransform.hpp"
#include "scene/item/SceneItemComponents.hpp"
namespace Dawn {
class Scene;
class SceneItem final :
public SceneItemTransform,
public SceneItemComponents,
public std::enable_shared_from_this<SceneItem>
{
private:
std::weak_ptr<Scene> scene;
protected:
std::shared_ptr<SceneItem> sceneItemComponentsSelf() override;
public:
/**
* Constructs a scene item.
*
* @param scene Scene that this item belongs to.
*/
SceneItem(const std::weak_ptr<Scene> scene);
/**
* Returns the scene that this scene item belongs to.
*
* @return Pointer to the scene that this item belongs to.
*/
std::shared_ptr<Scene> getScene();
/**
* Returns the scene that this item belongs to.
*
* @return Scene that this item belongs to.
*/
virtual ~SceneItem();
};
}

View File

@ -0,0 +1,10 @@
# Copyright (c) 2023 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
SceneItemComponents.cpp
SceneItemTransform.cpp
)

View File

@ -0,0 +1,24 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "SceneItemComponents.hpp"
using namespace Dawn;
SceneItemComponents::SceneItemComponents() {
}
void SceneItemComponents::removeComponent(
const std::shared_ptr<SceneComponent> component
) {
auto it = std::find(components.begin(), components.end(), component);
if(it == components.end()) return; //Not found?
components.erase(it);
}
SceneItemComponents::~SceneItemComponents() {
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "scene/SceneComponent.hpp"
namespace Dawn {
class SceneItem;
class SceneItemComponents {
protected:
std::vector<std::shared_ptr<SceneComponent>> components;
/**
* Shorthand way of allowing this class to retreive itself as a SceneItem.
*
* @return This as a shared pointer to a SceneItem.
*/
virtual std::shared_ptr<SceneItem> sceneItemComponentsSelf() = 0;
public:
SceneItemComponents();
/**
* Removes a component from this item.
*
* @param component Component to remove.
*/
void removeComponent(const std::shared_ptr<SceneComponent> component);
/**
* Adds a component to this item. You are given a shared pointer back but
* you are not intended to take responsibility for the component.
*
* @return Shared pointer to the created component.
*/
template<class T>
std::shared_ptr<T> addComponent() {
//Create the component and add it.
std::shared_ptr<T> component = std::make_shared<T>();
this->components.push_back(
static_pointer_cast<SceneComponent>(component)
);
// Init compoonent and return
component->init(sceneItemComponentsSelf());
return component;
}
virtual ~SceneItemComponents();
};
}

View File

@ -0,0 +1,122 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assert.hpp"
#include "scene/item/SceneItemTransform.hpp"
#include "scene/SceneItem.hpp"
using namespace Dawn;
SceneItemTransform::SceneItemTransform() :
transformLocal(1.0f),
transformWorld(1.0f)
{
this->updateLocalValuesFromLocalTransform();
}
void SceneItemTransform::updateLocalValuesFromLocalTransform() {
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(
this->transformLocal,
this->localScale,
this->localRotation,
this->localPosition,
skew,
perspective
);
}
void SceneItemTransform::updateLocalTransformFromWorldTransform() {
auto parent = this->getParent();
if(!parent) {
this->transformLocal = this->transformWorld;
} else {
this->transformLocal = (
glm::inverse(parent->transformWorld) * this->transformWorld
);
}
this->updateLocalValuesFromLocalTransform();
}
void SceneItemTransform::updateChildrenWorldTransforms() {
std::for_each(
this->children.begin(),
this->children.end(),
[](std::weak_ptr<SceneItem> &item) {
if(auto child = item.lock()) child->updateWorldTransformFromParent();
}
);
}
void SceneItemTransform::updateWorldTransformFromParent() {
auto parent = this->getParent();
if(!parent) {
this->transformWorld = this->transformLocal;
} else {
this->transformWorld = (
parent->transformWorld * this->transformLocal
);
}
this->updateLocalValuesFromLocalTransform();
this->updateChildrenWorldTransforms();
}
std::shared_ptr<SceneItem> SceneItemTransform::getParent() {
return parent.lock();
}
std::vector<std::shared_ptr<SceneItem>> SceneItemTransform::getChildren() {
std::vector<std::shared_ptr<SceneItem>> children;
std::for_each(
this->children.begin(),
this->children.end(),
[&children](std::weak_ptr<SceneItem> &item) {
if(auto child = item.lock()) children.push_back(child);
}
);
return children;
}
glm::mat4 SceneItemTransform::getLocalTransform() {
return this->transformLocal;
}
void SceneItemTransform::setWorldTransform(const glm::mat4 transform) {
this->transformWorld = transform;
this->updateLocalTransformFromWorldTransform();
this->updateChildrenWorldTransforms();
}
bool_t SceneItemTransform::isChildOf(std::shared_ptr<SceneItem> item) {
assertNotNull(item, "Cannot check if child of null item.");
auto parent = this->getParent();
while(parent) {
if(parent == item) return true;
parent = parent->getParent();
}
return false;
}
void SceneItemTransform::lookAt(
const glm::vec3 position,
const glm::vec3 target,
const glm::vec3 up
) {
this->setWorldTransform(glm::lookAt(position, target, up));
}
SceneItemTransform::~SceneItemTransform() {
std::for_each(
this->children.begin(),
this->children.end(),
[](std::weak_ptr<SceneItem> &item) {
if(auto child = item.lock()) {
child->parent.reset();
child->updateWorldTransformFromParent();
}
}
);
}

View File

@ -0,0 +1,103 @@
// 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 SceneItem;
class SceneItemTransform {
protected:
// Local (real) values
glm::vec3 localPosition;
glm::vec3 localScale;
glm::quat localRotation;
// Cached (non-real) values
glm::mat4 transformLocal;
glm::mat4 transformWorld;
// Heirarchy
std::weak_ptr<SceneItem> parent;
std::vector<std::weak_ptr<SceneItem>> children;
/**
* Unpacks the local transform into the local transform matrix values.
*/
void updateLocalValuesFromLocalTransform();
/**
* Sets the local transform (and all local real values) to match the world
* transform values.
*/
void updateLocalTransformFromWorldTransform();
/**
* Updates the world transform of this items children.
*/
void updateChildrenWorldTransforms();
/**
* Called by the parent of this item when it's transform changes.
*/
void updateWorldTransformFromParent();
public:
SceneItemTransform();
/**
* Returns the parent of this scene item.
*
* @return Pointer to the parent of this scene item.
*/
std::shared_ptr<SceneItem> getParent();
/**
* Returns the children of this scene item.
*
* @return Vector of pointers to the children of this scene item.
*/
std::vector<std::shared_ptr<SceneItem>> getChildren();
/**
* Returns the local transform of this item (relative to its parent).
*
* @return Local transform of this item.
*/
glm::mat4 getLocalTransform();
/**
* Sets the transform of this item within world space (relative to scene
* root)
*
* @param transform Transform of this item in world space.
*/
void setWorldTransform(const glm::mat4 transform);
/**
* Returns whether or not this item is a child of the given item. This
* will traverse up the entire heirarchy to confirm.
*
* @return True if this item is within the given item's heirarchy.
*/
bool_t isChildOf(std::shared_ptr<SceneItem> item);
/**
* 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.
* @param up Up vector of this transform.
*/
void lookAt(
const glm::vec3 position,
const glm::vec3 look,
const glm::vec3 up
);
virtual ~SceneItemTransform();
};
}