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

View File

@ -7,14 +7,15 @@
#include "assert/assertgl.hpp"
#include "assert/assert.hpp"
#include "game/Game.hpp"
#include "display/RenderPipeline.hpp"
using namespace Dawn;
RenderHost::RenderHost() {
RenderHost::RenderHost() : IRenderHost() {
}
void RenderHost::init(std::shared_ptr<Game> game) {
void RenderHost::init(const std::shared_ptr<Game> game) {
// Init GLFW
if(!glfwInit()) {
assertUnreachable("Failed to initialize GLFW!");
@ -80,10 +81,30 @@ void RenderHost::init(std::shared_ptr<Game> game) {
// });
}
void RenderHost::update() {
void RenderHost::update(const std::shared_ptr<Game> game) {
// Prepare the initial values
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
assertNoGLError();
glBlendFuncSeparate(
GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA,
GL_ONE,
GL_ONE_MINUS_SRC_ALPHA
);
assertNoGLError();
glDepthMask(GL_TRUE);
assertNoGLError();
glDepthFunc(GL_LESS);
assertNoGLError();
// Pipeline
renderPipeline.render(game);
// Tick the engine.
glfwSwapBuffers(window);
// Update events
glfwPollEvents();
}

View File

@ -25,8 +25,8 @@ namespace Dawn {
*/
RenderHost();
void init(std::shared_ptr<Game> game) override;
void update() override;
void init(const std::shared_ptr<Game> game) override;
void update(const std::shared_ptr<Game> game) override;
bool_t isCloseRequested() override;
std::shared_ptr<RenderTarget> getBackBufferRenderTarget() override;

View File

@ -6,6 +6,7 @@
#include "scene/SceneList.hpp"
#include "component/display/Camera.hpp"
#include "component/display/MeshRenderer.hpp"
#include "component/display/material/SimpleTexturedMaterial.hpp"
#include "display/mesh/CubeMesh.hpp"
using namespace Dawn;
@ -18,9 +19,11 @@ void Dawn::helloWorldScene(Scene &s) {
cameraItem->lookAt({ 3, 3, 3}, { 0, 0, 0 }, { 0, 1, 0 });
auto cubeMesh = std::make_shared<Mesh>();
cubeMesh->createBuffers(CUBE_VERTICE_COUNT, CUBE_INDICE_COUNT);
CubeMesh::buffer(cubeMesh, glm::vec3(-1, -1, -1), glm::vec3(1, 1, 1), 0, 0);
auto cubeItem = s.createSceneItem();
auto cubeMeshRenderer = cubeItem->addComponent<MeshRenderer>();
cubeMeshRenderer->mesh = cubeMesh;
auto cubeMaterial = cubeItem->addComponent<SimpleTexturedMaterial>();
}

View File

@ -43,17 +43,15 @@ void BackBufferRenderTarget::setClearColor(const struct Color color) {
this->clearColor = color;
}
void BackBufferRenderTarget::clear(
const enum RenderTargetClearFlag clearFlags
) {
void BackBufferRenderTarget::clear(const int32_t clearFlags) {
glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
assertNoGLError();
GLbitfield mask = 0;
if(Flag::isOn(clearFlags, RenderTargetClearFlag::COLOR)) {
if(Flag::isOn(clearFlags, RENDER_TARGET_CLEAR_COLOR)) {
mask |= GL_COLOR_BUFFER_BIT;
}
if(Flag::isOn(clearFlags, RenderTargetClearFlag::DEPTH)) {
if(Flag::isOn(clearFlags, RENDER_TARGET_CLEAR_DEPTH)) {
mask |= GL_DEPTH_BUFFER_BIT;
}

View File

@ -26,7 +26,7 @@ namespace Dawn {
float_t getWidth() override;
float_t getHeight() override;
void setClearColor(const struct Color color) override;
void clear(const enum RenderTargetClearFlag) override;
void clear(const int32_t) override;
void bind() override;
/**

View File

@ -8,4 +8,5 @@ target_sources(${DAWN_TARGET_NAME}
PRIVATE
Shader.cpp
ShaderStage.cpp
SimpleTexturedShader.cpp
)

View File

@ -3,4 +3,6 @@
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Shader.hpp"
#include "Shader.hpp"
using namespace Dawn;

View File

@ -4,13 +4,168 @@
// https://opensource.org/licenses/MIT
#pragma once
#include "display/ShaderStage.hpp"
#include "display/IShader.hpp"
#include "display/shader/ShaderStage.hpp"
#include "display/shader/IShader.hpp"
#include "assert/assert.hpp"
#include "assert/assertgl.hpp"
#include "display/Color.hpp"
namespace Dawn {
template<struct T>
enum ShaderOpenGLVariant {
GLSL_330_CORE
};
struct ShaderOpenGLParameter {
std::string name;
size_t offset;
enum ShaderParameterType type;
GLint location = -1;
ShaderOpenGLParameter(
const std::string &name,
const void *offset,
const enum ShaderParameterType type
) {
this->name = name;
this->offset = (size_t)offset;
this->type = type;
}
};
template<typename T>
class Shader : public IShader<T> {
private:
std::vector<std::shared_ptr<ShaderStage>> stages;
std::vector<struct ShaderOpenGLParameter> parameters;
enum ShaderOpenGLVariant variant;
GLuint shaderProgram = -1;
protected:
virtual void getStages(
const enum ShaderOpenGLVariant variant,
const T *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderOpenGLParameter> &parameters
) = 0;
public:
/**
* Initializes the shader, this needs to be called before the shader can
* be used.
*/
void init() override {
// Determine which kind of OpenGL shader to use.
variant = GLSL_330_CORE;
// Now get the stages
T dummy;
this->getStages(
variant,
&dummy,
stages,
parameters
);
// Create the shader program
shaderProgram = glCreateProgram();
assertNoGLError();
// Attach all the stages
for(auto stage : stages) {
glAttachShader(shaderProgram, stage->id);
assertNoGLError();
}
// Link and verify the program
glLinkProgram(shaderProgram);
assertNoGLError();
GLint status;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
assertNoGLError();
assertTrue(status == GL_TRUE, "Failed to link shader program.");
// Map parameters correctly.
std::for_each(
parameters.begin(),
parameters.end(),
[&](struct ShaderOpenGLParameter &param) {
// Correct offset
param.offset = param.offset - (size_t)(&dummy);
param.location = glGetUniformLocation(
shaderProgram,
param.name.c_str()
);
assertNoGLError();
assertTrue(
param.location != -1,
"Failed to get location for parameter %s.",
param.name.c_str()
);
}
);
this->bind();
}
/**
* Binds the shader as the current one, does not upload any data, somewhat
* relies on something else uploading the data.
*/
void bind() override {
glUseProgram(shaderProgram);
assertNoGLError();
}
/**
* Uploads the data to the GPU.
*/
void upload() override {
switch(this->variant) {
case ShaderOpenGLVariant::GLSL_330_CORE:
for(auto param : parameters) {
void *value = (void*)(
((size_t)&this->data) + param.offset
);
switch(param.type) {
case ShaderParameterType::MAT4: {
glm::mat4 *matrix = (glm::mat4 *)value;
glUniformMatrix4fv(
param.location, 1, GL_FALSE, glm::value_ptr(*matrix)
);
break;
}
case ShaderParameterType::COLOR: {
auto color = (Color *)value;
glUniform4f(
param.location,
color->r,
color->g,
color->b,
color->a
);
break;
}
default: {
assertUnreachable("Unsupported ShaderParameterType");
}
}
assertNoGLError();
}
break;
default:
assertUnreachable("Unsupported ShaderOpenGLVariant");
}
}
~Shader() {
}
};
}

View File

@ -3,15 +3,67 @@
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assertgl.hpp"
#include "assert/assert.hpp"
#include "ShaderStage.hpp"
using namespace Dawn;
ShaderStage::ShaderStage(const enum ShaderType type) : type(type) {
}
ShaderStage::ShaderStage(
const enum ShaderStageType type,
const std::string source
) : IShaderStage(type) {
// Get OpenGL Shader Type
GLenum shaderType;
switch(this->type) {
case ShaderStageType::VERTEX:
shaderType = GL_VERTEX_SHADER;
break;
void ShaderStage::compile(const std::string source) {
case ShaderStageType::FRAGMENT:
shaderType = GL_FRAGMENT_SHADER;
break;
// case ShaderStageType::COMPUTE:
// shaderType = GL_COMPUTE;
// break;
default:
assertUnreachable("Unknown ShaderStageType");
}
// Initialize the shader
this->id = glCreateShader(shaderType);
assertNoGLError();
// Compile the shader
auto cSource = source.c_str();
glShaderSource(this->id, 1, &cSource, NULL);
assertNoGLError();
glCompileShader(this->id);
assertNoGLError();
// Validate
GLint status;
glGetShaderiv(this->id, GL_COMPILE_STATUS, &status);
assertNoGLError();
if(!status) {
// Failed to compile
GLint logLength;
glGetShaderiv(this->id, GL_INFO_LOG_LENGTH, &logLength);
assertNoGLError();
GLchar *log = new GLchar[logLength];
glGetShaderInfoLog(this->id, logLength, NULL, log);
assertNoGLError();
assertUnreachable("Failed to compile shader stage:\n%s", log);
}
}
ShaderStage::~ShaderStage() {
if(this->id != -1) {
glDeleteShader(this->id);
assertNoGLError();
}
}

View File

@ -5,32 +5,24 @@
#pragma once
#include "dawnopengl.hpp"
#include "dawnlibs.hpp"
#include "display/shader/IShaderStage.hpp"
namespace Dawn {
class ShaderStage {
class ShaderStage : public IShaderStage {
public:
GLuint id = -1;
const enum ShaderType type;
/**
* Constructs a new ShaderStage.
*
* @param type The type of shader this is.
*/
ShaderStage(const enum ShaderType type);
/**
* Compiles the shader stage.
*
* @param source The source code to compile.
*/
void compile(const std::string source);
ShaderStage(const enum ShaderStageType type, const std::string source);
/**
* Disposes of the shader stage.
*/
virtual ~ShaderStage();
~ShaderStage();
};
}

View File

@ -0,0 +1,78 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "display/shader/SimpleTexturedShader.hpp"
using namespace Dawn;
void SimpleTexturedShader::getStages(
const enum ShaderOpenGLVariant variant,
const struct SimpleTexturedShaderData *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderOpenGLParameter> &parameters
) {
// Stages
std::shared_ptr<ShaderStage> vertex;
std::shared_ptr<ShaderStage> fragment;
switch(variant) {
case ShaderOpenGLVariant::GLSL_330_CORE:
vertex = std::make_shared<ShaderStage>(
ShaderStageType::VERTEX,
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"uniform mat4 u_Projection;\n"
"uniform mat4 u_View;\n"
"uniform mat4 u_Model;\n"
"void main() {\n"
"gl_Position = u_Projection * u_View * u_Model * vec4(aPos, 1.0);\n"
"}"
);
fragment = std::make_shared<ShaderStage>(
ShaderStageType::FRAGMENT,
"#version 330 core\n"
"in vec2 o_TextCoord;\n"
"out vec4 o_Color;\n"
"uniform vec4 u_Color;\n"
"void main() {\n"
"o_Color = u_Color;"
"}\n"
);
break;
default:
assertUnreachable("Unsupported ShaderOpenGLVariant");
}
// Add stages
stages.push_back(vertex);
stages.push_back(fragment);
// Parameters
parameters.push_back(ShaderOpenGLParameter(
"u_Projection",
&rel->projection,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderOpenGLParameter(
"u_View",
&rel->view,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderOpenGLParameter(
"u_Model",
&rel->model,
ShaderParameterType::MAT4
));
parameters.push_back(ShaderOpenGLParameter(
"u_Color",
&rel->color,
ShaderParameterType::COLOR
));
}

View File

@ -0,0 +1,26 @@
// 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 {
struct SimpleTexturedShaderData {
glm::mat4 projection;
glm::mat4 view;
glm::mat4 model;
struct Color color = COLOR_WHITE;
};
class SimpleTexturedShader : public Shader<SimpleTexturedShaderData> {
protected:
void getStages(
const enum ShaderOpenGLVariant variant,
const struct SimpleTexturedShaderData *rel,
std::vector<std::shared_ptr<ShaderStage>> &stages,
std::vector<struct ShaderOpenGLParameter> &parameters
) override;
};
}