First render.

This commit is contained in:
2023-11-17 00:02:04 -06:00
parent 55f629c7b5
commit 490da9d0c1
43 changed files with 1039 additions and 67 deletions

View File

@ -21,7 +21,7 @@ add_subdirectory(assert)
# add_subdirectory(asset)
# add_subdirectory(audio)
add_subdirectory(component)
# add_subdirectory(display)
add_subdirectory(display)
add_subdirectory(game)
# add_subdirectory(games)
# add_subdirectory(input)
@ -32,7 +32,7 @@ add_subdirectory(game)
add_subdirectory(scene)
# add_subdirectory(state)
# add_subdirectory(time)
# add_subdirectory(util)
add_subdirectory(util)
# Definitions
# target_compile_definitions(${DAWN_TARGET_NAME}

View File

@ -6,6 +6,8 @@
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Camera.cpp
Material.cpp
MeshRenderer.cpp
)
)
# Subdirs
add_subdirectory(material)

View File

@ -51,7 +51,9 @@ glm::mat4 Camera::getProjection() {
}
float_t Camera::getAspect() {
return 1.0f;
auto rt = this->getRenderTarget();
if(rt == nullptr) rt = getGame()->renderHost.getBackBufferRenderTarget();
return rt->getWidth() / rt->getHeight();
}
void Camera::setRenderTarget(std::shared_ptr<RenderTarget> renderTarget) {

View File

@ -0,0 +1,159 @@
// 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"
#include "display/mesh/Mesh.hpp"
#include "display/shader/Shader.hpp"
#include "component/display/Camera.hpp"
#include "component/display/MeshRenderer.hpp"
namespace Dawn {
struct IRenderPass {
public:
std::shared_ptr<Mesh> mesh;
/**
* Binds the shader for this render pass.
*/
virtual void bind() = 0;
/**
* Sets the data for this render pass to the shader.
*/
virtual void setData() = 0;
/**
* Uploads the data to the GPU.
*/
virtual void upload() = 0;
/**
* Draws the mesh for this render pass.
*/
virtual void draw() = 0;
/**
* Cleans up the render pass.
*/
virtual ~IRenderPass() { }
};
template<class S, typename D>
struct RenderPass : public IRenderPass {
private:
std::shared_ptr<S> shader;
const D data;
std::shared_ptr<Mesh> mesh;
const enum MeshDrawMode drawMode;
const int32_t indiceStart;
const int32_t indiceCount;
public:
/**
* Constructs a new RenderPass.
*
* @param self Self component instance that is creating this render pass.
* @param d The data to use for this render pass.
* @param mesh The mesh to use for this render pass.
* @param drawMode The draw mode to use for this render pass.
* @param indiceStart The indice to start drawing from.
* @param indiceCount The number of indices to draw.
*/
RenderPass(
SceneComponent &self,
const D d,
const std::shared_ptr<Mesh> mesh,
const enum MeshDrawMode drawMode,
const int32_t indiceStart,
const int32_t indiceCount
) :
data(d),
mesh(mesh),
drawMode(drawMode),
indiceStart(indiceStart),
indiceCount(indiceCount)
{
//Get the shader
shader = (
self.getGame()->renderHost.shaderManager.getShader<S>()
);
assertNotNull(shader, "Shader cannot be null!");
// Need mesh?
if(!this->mesh) {
auto meshRenderer = self.getItem()->getComponent<MeshRenderer>();
if(meshRenderer) this->mesh = meshRenderer->mesh;
}
}
void bind() override {
shader->bind();
}
void setData() override {
shader->setData(data);
}
void upload() override {
shader->upload();
}
void draw() override {
if(mesh) {
mesh->draw(drawMode, indiceStart, indiceCount);
}
}
};
struct RenderPassContext {
std::shared_ptr<Game> game;
std::shared_ptr<Scene> scene;
std::shared_ptr<Camera> camera;
std::shared_ptr<RenderTarget> renderTarget;
};
class IRenderableComponent {
public:
/**
* Retreive the list of render passes for this component.
*
* @param ctx Context for the render pass.
* @return List of render passes.
*/
virtual std::vector<std::shared_ptr<IRenderPass>> getPasses(
struct RenderPassContext &ctx
) = 0;
};
/**
* Short-hand function to create a render pass.
*
* @tparam S Shader type.
* @tparam D Shader's data type
* @param self Instance of the IRenderableComponent that is creating the pass.
* @param data Data to use for the render pass.
* @return Created render pass.
*/
template<class S, typename D>
std::shared_ptr<struct IRenderPass> createRenderPass(
SceneComponent &self,
const D data,
const std::shared_ptr<Mesh> mesh = nullptr,
const enum MeshDrawMode drawMode = MeshDrawMode::TRIANGLES,
int32_t indiceStart = 0,
int32_t indiceCount = -1
) {
return std::make_shared<struct RenderPass<S,D>>(
self,
data,
mesh,
drawMode,
indiceStart,
indiceCount
);
}
}

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
Material.cpp
SimpleTexturedMaterial.cpp
)

View File

@ -5,9 +5,15 @@
#pragma once
#include "scene/SceneComponent.hpp"
#include "component/display/IRenderableComponent.hpp"
namespace Dawn {
class Material : public SceneComponent {
class Material :
public SceneComponent,
public IRenderableComponent
{
protected:
public:
void onInit() override;
void onDispose() override;

View File

@ -0,0 +1,32 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "SimpleTexturedMaterial.hpp"
using namespace Dawn;
struct Color SimpleTexturedMaterial::getColor() {
return this->data.color;
}
void SimpleTexturedMaterial::setColor(struct Color color) {
this->data.color = color;
}
std::vector<std::shared_ptr<IRenderPass>> SimpleTexturedMaterial::getPasses(
struct RenderPassContext &ctx
) {
this->data.model = this->getItem()->getWorldTransform();
this->data.projection = ctx.camera->getProjection();
this->data.view = ctx.camera->getItem()->getWorldTransform();
this->data.color = COLOR_RED;
return {
createRenderPass<SimpleTexturedShader, struct SimpleTexturedShaderData>(
*this,
data
)
};
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "component/display/material/Material.hpp"
#include "display/shader/SimpleTexturedShader.hpp"
namespace Dawn {
class SimpleTexturedMaterial : public Material {
private:
struct SimpleTexturedShaderData data;
public:
/**
* Returns the color of this material.
*/
struct Color getColor();
/**
* Sets the color of this material.
*
* @param color The color to set.
*/
void setColor(struct Color color);
std::vector<std::shared_ptr<IRenderPass>> getPasses(
struct RenderPassContext &ctx
) override;
};
}

View File

@ -7,6 +7,8 @@
target_sources(${DAWN_TARGET_NAME}
PRIVATE
Color.cpp
RenderPipeline.cpp
IRenderHost.cpp
)
# Subdirs

View File

@ -4,35 +4,37 @@
// https://opensource.org/licenses/MIT
#include "Color.hpp"
#include "util/String.hpp"
#include "assert/assert.hpp"
using namespace Dawn;
struct Color Color::fromString(const std::string str) {
// Convert to lowercase
auto lower = stringToLowercase(str);
auto lower = String::toLowercase(str);
if(stringIncludes(lower, "cornflower")) {
if(String::includes(lower, "cornflower")) {
return COLOR_CORNFLOWER_BLUE;
} else if(stringIncludes(lower, "magenta")) {
} else if(String::includes(lower, "magenta")) {
return COLOR_MAGENTA;
} else if(stringIncludes(lower, "white")) {
} else if(String::includes(lower, "white")) {
return COLOR_WHITE;
} else if(stringIncludes(lower, "black")) {
} else if(String::includes(lower, "black")) {
return COLOR_BLACK;
} else if(stringIncludes(lower, "red")) {
} else if(String::includes(lower, "red")) {
return COLOR_RED;
} else if(stringIncludes(lower, "green")) {
} else if(String::includes(lower, "green")) {
return COLOR_GREEN;
} else if(stringIncludes(lower, "blue")) {
} else if(String::includes(lower, "blue")) {
return COLOR_BLUE;
} else if(stringIncludes(lower, "transparent")) {
} else if(String::includes(lower, "transparent")) {
return COLOR_TRANSPARENT;
}
@ -57,7 +59,7 @@ struct Color Color::fromString(const std::string str) {
}
// Split by comma
auto splitByComma = stringSplit(str, ",");
auto splitByComma = String::split(str, ",");
if(splitByComma.size() == 3) {
// RGB
return {

View File

@ -0,0 +1,14 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "IRenderHost.hpp"
using namespace Dawn;
IRenderHost::IRenderHost() : renderPipeline(), shaderManager() {
}
IRenderHost::~IRenderHost() {
}

View File

@ -6,12 +6,22 @@
#pragma once
#include "dawnlibs.hpp"
#include "display/RenderTarget.hpp"
#include "display/RenderPipeline.hpp"
#include "display/shader/ShaderManager.hpp"
namespace Dawn {
class Game;
class IRenderHost {
public:
RenderPipeline renderPipeline;
ShaderManager shaderManager;
/**
* Creates a render host.
*/
IRenderHost();
/**
* Initializes the render host, called by the game during the initial
* set up of the engine.
@ -22,9 +32,9 @@ namespace Dawn {
/**
* Performs an update/tick of the render host. This would be the game
* asking the RenderHost to the rendering.
* asking the RenderHost to do the rendering.
*/
virtual void update() = 0;
virtual void update(const std::shared_ptr<Game> game) = 0;
/**
* Overridable request from the game that asks if the RenderHost has any
@ -46,8 +56,6 @@ namespace Dawn {
/**
* Destroys the render host.
*/
virtual ~IRenderHost() {
}
virtual ~IRenderHost();
};
}

View File

@ -0,0 +1,110 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assert.hpp"
#include "RenderPipeline.hpp"
#include "game/Game.hpp"
#include "scene/Scene.hpp"
#include "component/display/Camera.hpp"
#include "component/display/IRenderableComponent.hpp"
using namespace Dawn;
RenderPipeline::RenderPipeline() {
}
void RenderPipeline::render(
const std::shared_ptr<Game> game
) {
assertNotNull(game, "Game cannot be null");
auto scene = game->getCurrentScene();
if(!scene) return;
this->renderScene(game, scene);
}
void RenderPipeline::renderScene(
const std::shared_ptr<Game> game,
const std::shared_ptr<Scene> scene
) {
assertNotNull(game, "Game cannot be null");
assertNotNull(scene, "Scene cannot be null");
// TODO: Render Subscenes First
// Get a list of all cameras in the scene
auto cameras = scene->findComponents<Camera>();
auto backBuffer = scene->getGame()->renderHost.getBackBufferRenderTarget();
std::shared_ptr<Camera> backbufferCamera = nullptr;
for(auto camera : cameras) {
auto rt = camera->getRenderTarget();
// Is this camera the backbuffer camera?
if(rt == backBuffer || rt == nullptr) {
backbufferCamera = camera;
continue;
}
// Render scene with this camera
renderSceneCamera(game, scene, camera, camera->getRenderTarget());
}
if(backbufferCamera) {
// Render the backbuffer camera
renderSceneCamera(game, scene, backbufferCamera, backBuffer);
}
}
void RenderPipeline::renderSceneCamera(
const std::shared_ptr<Game> game,
const std::shared_ptr<Scene> scene,
const std::shared_ptr<Camera> camera,
const std::shared_ptr<RenderTarget> renderTarget
) {
assertNotNull(game, "Game cannot be null");
assertNotNull(scene, "Scene cannot be null");
assertNotNull(camera, "Camera cannot be null");
struct RenderPassContext ctx = {
game,
scene,
camera,
renderTarget
};
// Get list of renderables
std::vector<std::shared_ptr<struct IRenderPass>> renderPasses;
auto renderables = scene->findComponents<IRenderableComponent>();
for(auto renderable : renderables) {
auto rp = renderable->getPasses(ctx);
renderPasses.insert(renderPasses.end(), rp.begin(), rp.end());
}
// Sort the render passes
// TODO: Make clearing the buffers editable!
renderTarget->bind();
renderTarget->clear(
RENDER_TARGET_CLEAR_COLOR |
RENDER_TARGET_CLEAR_DEPTH
);
std::for_each(
renderPasses.begin(),
renderPasses.end(),
[&](std::shared_ptr<struct IRenderPass> pass) {
pass->bind();
pass->setData();
pass->upload();
pass->draw();
}
);
}
RenderPipeline::~RenderPipeline() {
}

View File

@ -0,0 +1,63 @@
// 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 Scene;
class Camera;
class RenderTarget;
class RenderPipeline {
public:
/**
* Creates a new RenderPipeline.
*/
RenderPipeline();
/**
* Renders the game. This will render the current scene.
*
* @param game Game to render.
*/
void render(
const std::shared_ptr<Game> game
);
/**
* Renders a specific scene. This will render all cameras within the
* scene.
*
* @param game Game to render.
* @param scene Scene to render.
*/
void renderScene(
const std::shared_ptr<Game> game,
const std::shared_ptr<Scene> scene
);
/**
* Renders a specific scene with a specific camera.
*
* @param game Game to render.
* @param scene Scene to render.
* @param camera Camera to render.
* @param renderTarget Render target to render to.
*/
void renderSceneCamera(
const std::shared_ptr<Game> game,
const std::shared_ptr<Scene> scene,
const std::shared_ptr<Camera> camera,
const std::shared_ptr<RenderTarget> renderTarget
);
/**
* Destroys the RenderPipeline.
*/
virtual ~RenderPipeline();
};
}

View File

@ -6,10 +6,8 @@
#pragma once
#include "dawnlibs.hpp"
enum RenderTargetClearFlag {
COLOR = 1 << 0,
DEPTH = 1 << 0
};
#define RENDER_TARGET_CLEAR_COLOR 1 << 0
#define RENDER_TARGET_CLEAR_DEPTH 1 << 1
namespace Dawn {
class RenderTarget {
@ -51,7 +49,7 @@ namespace Dawn {
*
* @param clearFlags Flags to request what is going to be cleared.
*/
virtual void clear(const enum RenderTargetClearFlag clearFlags) = 0;
virtual void clear(const int32_t clearFlags) = 0;
/**
* Bind the render target for rendering to. The proceeding render requests

View File

@ -7,7 +7,7 @@
using namespace Dawn;
void Dawn::CubeMesh::buffer(
void CubeMesh::buffer(
const std::shared_ptr<Mesh> mesh,
const glm::vec3 pos,
const glm::vec3 size,

View File

@ -7,9 +7,29 @@
#include "dawnlibs.hpp"
namespace Dawn {
template<struct T>
class IShader {
private:
enum ShaderParameterType {
VEC2,
VEC3,
VEC4,
MAT3,
MAT4,
COLOR,
FLOAT,
INT,
TEXTURE,
BOOLEAN
};
class IShaderBase {
public:
virtual ~IShaderBase() {
}
};
template<typename T>
class IShader : public IShaderBase {
protected:
T data;
public:

View File

@ -7,7 +7,7 @@
using namespace Dawn;
IShaderStage::IShaderStage(const enum ShaderType type) :
IShaderStage::IShaderStage(const enum ShaderStageType type) :
type(type)
{

View File

@ -7,20 +7,22 @@
#include "dawnlibs.hpp"
namespace Dawn {
enum ShaderType {
enum ShaderStageType {
VERTEX,
FRAGMENT,
COMPUTE
// COMPUTE
};
class IShaderStage {
public:
const enum ShaderStageType type;
/**
* Constructs a new Shader Stage.
*
* @param type Type of shader stage.
*/
IShaderStage(const enum ShaderType type);
IShaderStage(const enum ShaderStageType type);
/**
* Destroy the IShaderStage object

View File

@ -0,0 +1,45 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "display/shader/Shader.hpp"
namespace Dawn {
class ShaderManager {
private:
std::vector<std::shared_ptr<IShaderBase>> shaders;
public:
/**
* Retreives an instance of the shader from the shader manager. If the
* shader does not exist it will be created.
*
* @tparam T Type of shader to retreive.
* @return Shader instance.
*/
template<class T>
std::shared_ptr<T> getShader() {
auto itShaders = shaders.begin();
while(itShaders != shaders.end()) {
// auto shader = itShaders->lock();
// if(!shader) {
// itShaders = shaders.erase(itShaders);
// continue;
// }
// std::shared_ptr<T> casted = std::dynamic_pointer_cast<T>(shader);
auto shader = *itShaders;
std::shared_ptr<T> casted = std::dynamic_pointer_cast<T>(shader);
if(casted) return casted;
itShaders++;
}
auto newShader = std::make_shared<T>();
shaders.push_back(newShader);
newShader->init();
return newShader;
}
};
}

View File

@ -22,7 +22,7 @@ void Game::init() {
}
void Game::update() {
renderHost.update();
renderHost.update(shared_from_this());
if(nextFrameScene) {
nextFrameScene->stage();
@ -37,6 +37,10 @@ bool_t Game::isCloseRequested() {
);
}
std::shared_ptr<Scene> Game::getCurrentScene() {
return currentScene;
}
Game::~Game() {
std::cout << "Game successfully destructed" << std::endl;
}

View File

@ -44,6 +44,13 @@ namespace Dawn {
*/
bool_t isCloseRequested();
/**
* Returns the current scene that is active.
*
* @return The current scene.
*/
std::shared_ptr<Scene> getCurrentScene();
/**
* Deconstructs the game instance, does not deinitialize anything.
*/

View File

@ -44,6 +44,21 @@ namespace Dawn {
*/
std::shared_ptr<SceneItem> createSceneItem();
/**
* Returns a list of scene components that match the given type.
*
* @return List of scene components matching the type.
*/
template<class T>
std::vector<std::shared_ptr<T>> findComponents() {
std::vector<std::shared_ptr<T>> components;
for(auto item : sceneItems) {
auto component = item->getComponent<T>();
if(component) components.push_back(component);
}
return components;
}
/**
* Destroys the scene object and cleans up all of its children.
*/

View File

@ -5,8 +5,8 @@
#include "assert/assert.hpp"
#include "util/Flag.hpp"
#include "scene/Scene.hpp"
#include "game/Game.hpp"
#include "scene/Scene.hpp"
using namespace Dawn;

View File

@ -49,6 +49,20 @@ namespace Dawn {
return component;
}
/**
* Returns a list of components that match the given type.
*
* @return List of components matching the type.
*/
template<class T>
std::shared_ptr<T> getComponent() {
for(auto component : this->components) {
auto cast = std::dynamic_pointer_cast<T>(component);
if(cast) return cast;
}
return nullptr;
}
virtual ~SceneItemComponents();
};
}

View File

@ -84,6 +84,10 @@ glm::mat4 SceneItemTransform::getLocalTransform() {
return this->transformLocal;
}
glm::mat4 SceneItemTransform::getWorldTransform() {
return this->transformWorld;
}
void SceneItemTransform::setWorldTransform(const glm::mat4 transform) {
this->transformWorld = transform;
this->updateLocalTransformFromWorldTransform();

View File

@ -68,6 +68,13 @@ namespace Dawn {
* @return Local transform of this item.
*/
glm::mat4 getLocalTransform();
/**
* Returns the world transform of this item (relative to scene root).
*
* @return World transform of this item.
*/
glm::mat4 getWorldTransform();
/**
* Sets the transform of this item within world space (relative to scene

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
String.cpp
)

36
src/dawn/util/String.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 "String.hpp"
using namespace Dawn;
std::string String::toLowercase(const std::string &str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}
bool_t String::includes(const std::string &str, const std::string &needle) {
return str.find(needle) != std::string::npos;
}
std::vector<std::string> String::split(
const std::string &s,
const std::string &delim
) {
size_t posStart = 0, posEnd, delimLength = delim.length();
std::string token;
std::vector<std::string> res;
while((posEnd = s.find(delim, posStart)) != std::string::npos) {
token = s.substr(posStart, posEnd - posStart);
posStart = posEnd + delimLength;
res.push_back (token);
}
res.push_back(s.substr(posStart));
return res;
}

41
src/dawn/util/String.hpp Normal file
View File

@ -0,0 +1,41 @@
// 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 String {
public:
/**
* Converts the given string to lowercase.
*
* @param str String to convert.
* @return The lowercase string.
*/
static std::string toLowercase(const std::string &str);
/**
* Checks if the given string includes the given needle.
*
* @param str String to check.
* @param needle String to check for.
* @return True if the string includes the needle.
*/
static bool_t includes(const std::string &str, const std::string &needle);
/**
* Splits the given string by the given delimiter.
*
* @param str String to split.
* @param delim Delimiter to split by.
* @return The split string.
*/
static std::vector<std::string> split(
const std::string &str,
const std::string &delim
);
};
}