From 15608d830970ae10410229349f7798dcd72f3bfe Mon Sep 17 00:00:00 2001 From: Noel Berry Date: Sat, 26 Dec 2020 14:44:48 -0800 Subject: [PATCH] graphics refactor & new organization --- CMakeLists.txt | 26 +- README.md | 16 +- private/blah/internal/graphics_backend.h | 19 +- private/blah/internal/graphics_backend_gl.cpp | 134 ++++----- .../blah/internal/platform_backend_sdl2.cpp | 8 +- public/blah.h | 3 +- public/blah/app.cpp | 69 ++++- public/blah/app.h | 26 ++ public/blah/drawing/batch.cpp | 52 ++-- public/blah/drawing/batch.h | 8 +- public/blah/drawing/spritefont.cpp | 3 +- public/blah/drawing/subtexture.cpp | 6 +- public/blah/graphics/blend.cpp | 25 ++ public/blah/graphics/blend.h | 96 +++++++ public/blah/graphics/framebuffer.cpp | 38 +++ public/blah/graphics/framebuffer.h | 17 +- public/blah/graphics/graphics.cpp | 255 ------------------ public/blah/graphics/graphics.h | 246 ----------------- public/blah/graphics/material.cpp | 14 +- public/blah/graphics/material.h | 12 +- public/blah/graphics/mesh.cpp | 6 + public/blah/graphics/mesh.h | 9 +- public/blah/graphics/renderpass.cpp | 111 ++++++++ public/blah/graphics/renderpass.h | 82 ++++++ public/blah/graphics/shader.cpp | 9 + public/blah/graphics/shader.h | 9 +- public/blah/graphics/texture.cpp | 60 +++++ public/blah/graphics/texture.h | 28 +- 28 files changed, 742 insertions(+), 645 deletions(-) create mode 100644 public/blah/graphics/blend.cpp create mode 100644 public/blah/graphics/blend.h create mode 100644 public/blah/graphics/framebuffer.cpp delete mode 100644 public/blah/graphics/graphics.cpp delete mode 100644 public/blah/graphics/graphics.h create mode 100644 public/blah/graphics/renderpass.cpp create mode 100644 public/blah/graphics/renderpass.h create mode 100644 public/blah/graphics/shader.cpp create mode 100644 public/blah/graphics/texture.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dd9900..2f0c221 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,17 +17,21 @@ add_library(blah public/blah/time.cpp public/blah/time.h - public/blah/graphics/graphics.h - public/blah/graphics/graphics.cpp - public/blah/graphics/texture.h + public/blah/graphics/blend.h + public/blah/graphics/blend.cpp public/blah/graphics/framebuffer.h - public/blah/graphics/shader.h - public/blah/graphics/mesh.h - public/blah/graphics/mesh.cpp + public/blah/graphics/framebuffer.cpp public/blah/graphics/material.h public/blah/graphics/material.cpp + public/blah/graphics/mesh.h + public/blah/graphics/mesh.cpp + public/blah/graphics/renderpass.h + public/blah/graphics/renderpass.cpp + public/blah/graphics/shader.h + public/blah/graphics/shader.cpp + public/blah/graphics/texture.h + public/blah/graphics/texture.cpp - public/blah/input/input.h public/blah/input/input.cpp public/blah/input/virtual_stick.cpp public/blah/input/virtual_stick.h @@ -94,15 +98,15 @@ add_library(blah public/blah/streams/stream.cpp public/blah/streams/stream.h + private/blah/third_party/stb_image.h + private/blah/third_party/stb_image_write.h + private/blah/third_party/stb_truetype.h private/blah/internal/graphics_backend.h private/blah/internal/graphics_backend_gl.cpp private/blah/internal/input_backend.h private/blah/internal/platform_backend.h private/blah/internal/platform_backend_sdl2.cpp - - private/blah/third_party/stb_image.h - private/blah/third_party/stb_image_write.h - private/blah/third_party/stb_truetype.h) +) target_include_directories(blah PUBLIC diff --git a/README.md b/README.md index 6759f05..f6fbce9 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ this will likely see breaking changes. #### building - Requires C++17 and CMake - - The [SDL2 platform backend](https://github.com/NoelFB/blah/blob/master/private/blah/internal/platform_backend_sdl2.cpp) can be enabled in CMake with `BLAH_USE_SDL2`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES` - - The [OpenGL graphics backend](https://github.com/NoelFB/blah/blob/master/private/blah/internal/graphics_backend_gl.cpp) can be enabled in CMake with `BLAH_USE_OPENGL`. + - The [SDL2 platform backend](https://github.com/NoelFB/blah/blob/master/private/blah/internal/platform_backend_sdl2.cpp) can be enabled in CMake with `SDL2_ENABLED`, and setting `SDL2_INCLUDE_DIRS` and `SDL2_LIBRARIES` + - The [OpenGL graphics backend](https://github.com/NoelFB/blah/blob/master/private/blah/internal/graphics_backend_gl.cpp) can be enabled in CMake with `OPENGL_ENABLED`. - Other backends can be added by implementing the [Platform Backend](https://github.com/NoelFB/blah/blob/master/private/blah/internal/platform_backend.h) or [Graphics Backend](https://github.com/NoelFB/blah/blob/master/private/blah/internal/graphics_backend.h). #### notes @@ -26,17 +26,17 @@ Batch batch; void render() { - Graphics::clear(Graphics::backbuffer, 0x00000000); + App::backbuffer->clear(Color::black); - Vec2 center = Vec2(App::draw_width(), App::draw_height()) / 2; - float rotation = Time::elapsed * Calc::TAU; - Mat3x2 transform = Mat3x2::create_transform(center, Vec2::zero, Vec2::one, rotation); + auto center = Vec2(App::backbuffer->width(), App::backbuffer->height()) / 2; + auto rotation = Time::elapsed * Calc::TAU; + auto transform = Mat3x2::create_transform(center, Vec2::zero, Vec2::one, rotation); batch.push_matrix(transform); - batch.rect(Rect(-32, -32, 64, 64), 0xff0000); + batch.rect(Rect(-32, -32, 64, 64), Color::red); batch.pop_matrix(); - batch.render(Graphics::backbuffer); + batch.render(); batch.clear(); } diff --git a/private/blah/internal/graphics_backend.h b/private/blah/internal/graphics_backend.h index 375048a..b8fa1d2 100644 --- a/private/blah/internal/graphics_backend.h +++ b/private/blah/internal/graphics_backend.h @@ -1,5 +1,12 @@ #pragma once -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Blah { @@ -14,10 +21,10 @@ namespace Blah void shutdown(); // Returns info about the renderer - const GraphicsInfo* info(); + const RendererFeatures& features(); // Returns the renderer type - GraphicsRenderer renderer(); + Renderer renderer(); // Called once per frame void frame(); @@ -29,10 +36,10 @@ namespace Blah void after_render(); // Performs a draw call - void render(const RenderCall& call); + void render(const RenderPass& pass); - // Clears a buffer - void clear(const FrameBufferRef& target, uint32_t rgba); + // Clears the backbuffer + void clear_backbuffer(Color color); // Creates a new Texture. // if the Texture is invalid, this should return an empty reference. diff --git a/private/blah/internal/graphics_backend_gl.cpp b/private/blah/internal/graphics_backend_gl.cpp index a20a954..5034c37 100644 --- a/private/blah/internal/graphics_backend_gl.cpp +++ b/private/blah/internal/graphics_backend_gl.cpp @@ -1,6 +1,5 @@ #ifdef BLAH_USE_OPENGL -#include #include #include #include @@ -360,7 +359,7 @@ namespace Blah int max_samples; int max_texture_image_units; int max_texture_size; - GraphicsInfo info; + RendererFeatures features; }; // static state @@ -691,7 +690,7 @@ namespace Blah for (int i = 0; i < attachmentCount; i++) { - auto tex = Graphics::create_texture(width, height, attachments[i]); + auto tex = Texture::create(width, height, attachments[i]); auto gltex = ((OpenGL_Texture*)tex.get()); gltex->framebuffer_parent = true; @@ -751,6 +750,20 @@ namespace Blah { return m_height; } + + virtual void clear(Color color) override + { + auto rgba = color.to_rgba(); + unsigned char r = rgba >> 24; + unsigned char g = rgba >> 16; + unsigned char b = rgba >> 8; + unsigned char a = rgba; + + gl.BindFramebuffer(GL_FRAMEBUFFER, m_id); + gl.Disable(GL_SCISSOR_TEST); + gl.ClearColor(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); + gl.Clear(GL_COLOR_BUFFER_BIT); + } }; class OpenGL_Shader : public Shader @@ -1106,16 +1119,16 @@ namespace Blah gl.PixelStorei(GL_UNPACK_ALIGNMENT, 1); // assign info - gl.info.instancing = true; - gl.info.origin_bottom_left = true; - gl.info.max_texture_size = gl.max_texture_size; + gl.features.instancing = true; + gl.features.origin_bottom_left = true; + gl.features.max_texture_size = gl.max_texture_size; return true; } - GraphicsRenderer GraphicsBackend::renderer() + Renderer GraphicsBackend::renderer() { - return GraphicsRenderer::OpenGL; + return Renderer::OpenGL; } void GraphicsBackend::shutdown() @@ -1124,9 +1137,9 @@ namespace Blah gl.context = nullptr; } - const GraphicsInfo* GraphicsBackend::info() + const RendererFeatures& GraphicsBackend::features() { - return &gl.info; + return gl.features; } void GraphicsBackend::frame() {} @@ -1185,27 +1198,27 @@ namespace Blah return MeshRef(resource); } - void GraphicsBackend::render(const RenderCall& call) + void GraphicsBackend::render(const RenderPass& pass) { // Bind the Target Point size; - if (!call.target) + if (pass.target == App::backbuffer) { gl.BindFramebuffer(GL_FRAMEBUFFER, 0); size.x = App::draw_width(); size.y = App::draw_height(); } - else + else if (pass.target) { - auto framebuffer = (OpenGL_FrameBuffer*)call.target.get(); + auto framebuffer = (OpenGL_FrameBuffer*)pass.target.get(); gl.BindFramebuffer(GL_FRAMEBUFFER, framebuffer->gl_id()); - size.x = call.target->width(); - size.y = call.target->height(); + size.x = pass.target->width(); + size.y = pass.target->height(); } - auto shader_ref = call.material->shader(); + auto shader_ref = pass.material->shader(); auto shader = (OpenGL_Shader*)shader_ref.get(); - auto mesh = (OpenGL_Mesh*)call.mesh.get(); + auto mesh = (OpenGL_Mesh*)pass.mesh.get(); // Use the Shader // TODO: I don't love how material values are assigned or set here @@ -1227,7 +1240,7 @@ namespace Blah { for (int n = 0; n < uniform.array_length; n++) { - auto tex = call.material->get_texture(i, n); + auto tex = pass.material->get_texture(i, n); gl.ActiveTexture(GL_TEXTURE0 + texture_slot); @@ -1249,59 +1262,59 @@ namespace Blah // Float else if (uniform.type == UniformType::Float) { - gl.Uniform1fv(location, (GLint)uniform.array_length, (const GLfloat*)call.material->get_value(i)); + gl.Uniform1fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i)); } // Float2 else if (uniform.type == UniformType::Float2) { - gl.Uniform2fv(location, (GLint)uniform.array_length, (const GLfloat*)call.material->get_value(i)); + gl.Uniform2fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i)); } // Float3 else if (uniform.type == UniformType::Float3) { - gl.Uniform3fv(location, (GLint)uniform.array_length, (const GLfloat*)call.material->get_value(i)); + gl.Uniform3fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i)); } // Float4 else if (uniform.type == UniformType::Float4) { - gl.Uniform4fv(location, (GLint)uniform.array_length, (const GLfloat*)call.material->get_value(i)); + gl.Uniform4fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i)); } // Matrix3x2 else if (uniform.type == UniformType::Mat3x2) { - gl.UniformMatrix3x2fv(location, (GLint)uniform.array_length, 0, (const GLfloat*)call.material->get_value(i)); + gl.UniformMatrix3x2fv(location, (GLint)uniform.array_length, 0, (const GLfloat*)pass.material->get_value(i)); } // Matrix4x4 else if (uniform.type == UniformType::Mat4x4) { - gl.UniformMatrix4fv(location, (GLint)uniform.array_length, 0, (const GLfloat*)call.material->get_value(i)); + gl.UniformMatrix4fv(location, (GLint)uniform.array_length, 0, (const GLfloat*)pass.material->get_value(i)); } } } // Blend Mode { - GLenum colorOp = gl_get_blend_func(call.blend.colorOp); - GLenum alphaOp = gl_get_blend_func(call.blend.alphaOp); - GLenum colorSrc = gl_get_blend_factor(call.blend.colorSrc); - GLenum colorDst = gl_get_blend_factor(call.blend.colorDst); - GLenum alphaSrc = gl_get_blend_factor(call.blend.alphaSrc); - GLenum alphaDst = gl_get_blend_factor(call.blend.alphaDst); + GLenum colorOp = gl_get_blend_func(pass.blend.colorOp); + GLenum alphaOp = gl_get_blend_func(pass.blend.alphaOp); + GLenum colorSrc = gl_get_blend_factor(pass.blend.colorSrc); + GLenum colorDst = gl_get_blend_factor(pass.blend.colorDst); + GLenum alphaSrc = gl_get_blend_factor(pass.blend.alphaSrc); + GLenum alphaDst = gl_get_blend_factor(pass.blend.alphaDst); gl.Enable(GL_BLEND); gl.BlendEquationSeparate(colorOp, alphaOp); gl.BlendFuncSeparate(colorSrc, colorDst, alphaSrc, alphaDst); gl.ColorMask( - ((int)call.blend.mask & (int)BlendMask::Red), - ((int)call.blend.mask & (int)BlendMask::Green), - ((int)call.blend.mask & (int)BlendMask::Blue), - ((int)call.blend.mask & (int)BlendMask::Alpha)); + ((int)pass.blend.mask & (int)BlendMask::Red), + ((int)pass.blend.mask & (int)BlendMask::Green), + ((int)pass.blend.mask & (int)BlendMask::Blue), + ((int)pass.blend.mask & (int)BlendMask::Alpha)); - unsigned char r = call.blend.rgba >> 24; - unsigned char g = call.blend.rgba >> 16; - unsigned char b = call.blend.rgba >> 8; - unsigned char a = call.blend.rgba; + unsigned char r = pass.blend.rgba >> 24; + unsigned char g = pass.blend.rgba >> 16; + unsigned char b = pass.blend.rgba >> 8; + unsigned char a = pass.blend.rgba; gl.BlendColor( r / 255.0f, @@ -1312,7 +1325,7 @@ namespace Blah // Depth Function { - if (call.depth == Compare::None) + if (pass.depth == Compare::None) { gl.Disable(GL_DEPTH_TEST); } @@ -1320,7 +1333,7 @@ namespace Blah { gl.Enable(GL_DEPTH_TEST); - switch (call.depth) + switch (pass.depth) { case Compare::None: break; case Compare::Always: @@ -1353,7 +1366,7 @@ namespace Blah // Cull Mode { - if (call.cull == Cull::None) + if (pass.cull == Cull::None) { gl.Disable(GL_CULL_FACE); } @@ -1361,9 +1374,9 @@ namespace Blah { gl.Enable(GL_CULL_FACE); - if (call.cull == Cull::Back) + if (pass.cull == Cull::Back) gl.CullFace(GL_BACK); - else if (call.cull == Cull::Front) + else if (pass.cull == Cull::Front) gl.CullFace(GL_FRONT); else gl.CullFace(GL_FRONT_AND_BACK); @@ -1372,7 +1385,7 @@ namespace Blah // Viewport { - Rect viewport = call.viewport; + Rect viewport = pass.viewport; viewport.y = size.y - viewport.y - viewport.h; gl.Viewport((GLint)viewport.x, (GLint)viewport.y, (GLint)viewport.w, (GLint)viewport.h); @@ -1380,13 +1393,13 @@ namespace Blah // Scissor { - if (!call.has_scissor) + if (!pass.has_scissor) { gl.Disable(GL_SCISSOR_TEST); } else { - Rect scissor = call.scissor; + Rect scissor = pass.scissor; scissor.y = size.y - scissor.y - scissor.h; if (scissor.w < 0) @@ -1403,46 +1416,37 @@ namespace Blah { gl.BindVertexArray(mesh->gl_id()); - if (call.instance_count > 0) + if (pass.instance_count > 0) { gl.DrawElementsInstanced( GL_TRIANGLES, - (GLint)(call.index_count), + (GLint)(pass.index_count), GL_UNSIGNED_INT, - (void*)(sizeof(int) * call.index_start), - (GLint)call.instance_count); + (void*)(sizeof(int) * pass.index_start), + (GLint)pass.instance_count); } else { gl.DrawElements( GL_TRIANGLES, - (GLint)(call.index_count), + (GLint)(pass.index_count), GL_UNSIGNED_INT, - (void*)(sizeof(int) * call.index_start)); + (void*)(sizeof(int) * pass.index_start)); } gl.BindVertexArray(0); } } - void GraphicsBackend::clear(const FrameBufferRef& target, uint32_t rgba) + void GraphicsBackend::clear_backbuffer(Color color) { - if (!target) - { - gl.BindFramebuffer(GL_FRAMEBUFFER, 0); - } - else - { - auto framebuffer = (OpenGL_FrameBuffer*)target.get(); - if (framebuffer != nullptr) - gl.BindFramebuffer(GL_FRAMEBUFFER, framebuffer->gl_id()); - } - + auto rgba = color.to_rgba(); unsigned char r = rgba >> 24; unsigned char g = rgba >> 16; unsigned char b = rgba >> 8; unsigned char a = rgba; + gl.BindFramebuffer(GL_FRAMEBUFFER, 0); gl.Disable(GL_SCISSOR_TEST); gl.ClearColor(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); gl.Clear(GL_COLOR_BUFFER_BIT); diff --git a/private/blah/internal/platform_backend_sdl2.cpp b/private/blah/internal/platform_backend_sdl2.cpp index 95d020e..1dd827c 100644 --- a/private/blah/internal/platform_backend_sdl2.cpp +++ b/private/blah/internal/platform_backend_sdl2.cpp @@ -76,7 +76,7 @@ bool PlatformBackend::init(const Config* config) int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; // GL Attributes - if (GraphicsBackend::renderer() == GraphicsRenderer::OpenGL) + if (App::renderer() == Renderer::OpenGL) { flags |= SDL_WINDOW_OPENGL; @@ -135,7 +135,7 @@ bool PlatformBackend::init(const Config* config) void PlatformBackend::ready() { // enable V-Sync - if (GraphicsBackend::renderer() == GraphicsRenderer::OpenGL) + if (App::renderer() == Renderer::OpenGL) SDL_GL_SetSwapInterval(1); } @@ -342,7 +342,7 @@ void PlatformBackend::sleep(int milliseconds) void PlatformBackend::present() { - if (GraphicsBackend::renderer() == GraphicsRenderer::OpenGL) + if (App::renderer() == Renderer::OpenGL) { SDL_GL_SwapWindow(window); } @@ -396,7 +396,7 @@ void PlatformBackend::set_size(int width, int height) void PlatformBackend::get_draw_size(int* width, int* height) { - if (GraphicsBackend::renderer() == GraphicsRenderer::OpenGL) + if (App::renderer() == Renderer::OpenGL) { SDL_GL_GetDrawableSize(window, width, height); } diff --git a/public/blah.h b/public/blah.h index b0a8dbc..796d204 100644 --- a/public/blah.h +++ b/public/blah.h @@ -14,10 +14,11 @@ #include #include +#include #include -#include #include #include +#include #include #include diff --git a/public/blah/app.cpp b/public/blah/app.cpp index 474b15a..9e25574 100644 --- a/public/blah/app.cpp +++ b/public/blah/app.cpp @@ -11,9 +11,9 @@ using namespace Blah; namespace { - static Config app_config; - static bool app_is_running = false; - static bool app_is_exiting = false; + Config app_config; + bool app_is_running = false; + bool app_is_exiting = false; } Config::Config() @@ -230,4 +230,65 @@ float App::content_scale() void App::fullscreen(bool enabled) { PlatformBackend::set_fullscreen(enabled); -} \ No newline at end of file +} + +Renderer App::renderer() +{ + return GraphicsBackend::renderer(); +} + +const RendererFeatures& Blah::App::renderer_features() +{ + return GraphicsBackend::features(); +} + +namespace +{ + class BackBuffer final : public FrameBuffer + { + Attachments empty_attachments; + TextureRef empty_texture; + + virtual Attachments& attachments() override + { + BLAH_ASSERT(false, "Backbuffer doesn't have any attachments"); + return empty_attachments; + } + + virtual const Attachments& attachments() const override + { + BLAH_ASSERT(false, "Backbuffer doesn't have any attachments"); + return empty_attachments; + } + + virtual TextureRef& attachment(int index) override + { + BLAH_ASSERT(false, "Backbuffer doesn't have any attachments"); + return empty_texture; + } + + virtual const TextureRef& attachment(int index) const override + { + BLAH_ASSERT(false, "Backbuffer doesn't have any attachments"); + return empty_texture; + } + + virtual int width() const override + { + return App::draw_width(); + } + + virtual int height() const override + { + return App::draw_height(); + } + + virtual void clear(Color color) override + { + GraphicsBackend::clear_backbuffer(color); + } + }; + +} + +extern const FrameBufferRef App::backbuffer = FrameBufferRef(new BackBuffer()); \ No newline at end of file diff --git a/public/blah/app.h b/public/blah/app.h index 77d370c..b0d5cdb 100644 --- a/public/blah/app.h +++ b/public/blah/app.h @@ -1,4 +1,5 @@ #pragma once +#include namespace Blah { @@ -23,6 +24,22 @@ namespace Blah Config(); }; + enum class Renderer + { + None = -1, + OpenGL, + D3D11, + Metal, + Count + }; + + struct RendererFeatures + { + bool instancing = false; + bool origin_bottom_left = false; + int max_texture_size = 0; + }; + namespace App { // Runs the application @@ -60,5 +77,14 @@ namespace Blah // Toggles fullscreen void fullscreen(bool enabled); + + // Returns the Rendering API in use + Renderer renderer(); + + // Retrieves the Renderer Features + const RendererFeatures& renderer_features(); + + // Reference to the window's back buffer + extern const FrameBufferRef backbuffer; } } \ No newline at end of file diff --git a/public/blah/drawing/batch.cpp b/public/blah/drawing/batch.cpp index baf041a..1314f75 100644 --- a/public/blah/drawing/batch.cpp +++ b/public/blah/drawing/batch.cpp @@ -268,7 +268,7 @@ void Batch::set_texture(const TextureRef& texture) if (m_batch.texture != texture) { m_batch.texture = texture; - m_batch.flip_vertically = Graphics::info()->origin_bottom_left && texture && texture->is_framebuffer(); + m_batch.flip_vertically = App::renderer_features().origin_bottom_left && texture && texture->is_framebuffer(); } } @@ -293,53 +293,53 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix) { if (!m_mesh) { - m_mesh = Graphics::create_mesh(); + m_mesh = Mesh::create(); m_mesh->vertex_format(attributes, 4, sizeof(Vertex)); } if (!m_default_shader) - m_default_shader = Graphics::create_shader(&data); + m_default_shader = Shader::create(&data); if (!m_default_material) - m_default_material = Graphics::create_material(m_default_shader); + m_default_material = Material::create(m_default_shader); } // upload data m_mesh->index_data(m_indices.data(), m_indices.size()); m_mesh->vertex_data(m_vertices.data(), m_vertices.size()); - RenderCall call; - call.target = target; - call.mesh = m_mesh; - call.has_viewport = false; - call.viewport = Rect(); - call.instance_count = 0; - call.depth = Compare::None; - call.cull = Cull::None; + RenderPass pass; + pass.target = target; + pass.mesh = m_mesh; + pass.has_viewport = false; + pass.viewport = Rect(); + pass.instance_count = 0; + pass.depth = Compare::None; + pass.cull = Cull::None; for (auto& b : m_batches) - render_single_batch(call, b, matrix); + render_single_batch(pass, b, matrix); if (m_batch.elements > 0) - render_single_batch(call, m_batch, matrix); + render_single_batch(pass, m_batch, matrix); } -void Batch::render_single_batch(RenderCall& call, const DrawBatch& b, const Mat4x4& matrix) +void Batch::render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4x4& matrix) { - call.material = b.material; - if (!call.material) - call.material = m_default_material; + pass.material = b.material; + if (!pass.material) + pass.material = m_default_material; - call.material->set_texture(texture_uniform, b.texture, 0); - call.material->set_value(matrix_uniform, &matrix.m11, 16); + pass.material->set_texture(texture_uniform, b.texture, 0); + pass.material->set_value(matrix_uniform, &matrix.m11, 16); - call.blend = b.blend; - call.has_scissor = b.scissor.w >= 0 && b.scissor.h >= 0; - call.scissor = b.scissor; - call.index_start = (int64_t)b.offset * 3; - call.index_count = (int64_t)b.elements * 3; + pass.blend = b.blend; + pass.has_scissor = b.scissor.w >= 0 && b.scissor.h >= 0; + pass.scissor = b.scissor; + pass.index_start = (int64_t)b.offset * 3; + pass.index_count = (int64_t)b.elements * 3; - Graphics::render(call); + pass.perform(); } void Batch::clear() diff --git a/public/blah/drawing/batch.h b/public/blah/drawing/batch.h index c168661..c65fab9 100644 --- a/public/blah/drawing/batch.h +++ b/public/blah/drawing/batch.h @@ -1,5 +1,4 @@ #pragma once -#include #include #include #include @@ -9,6 +8,9 @@ #include #include #include +#include +#include +#include namespace Blah { @@ -114,7 +116,7 @@ namespace Blah void set_texture(const TextureRef& texture); // Draws the batch to the given target - void render(const FrameBufferRef& target); + void render(const FrameBufferRef& target = App::backbuffer); // Draws the batch to the given target, with the provided matrix void render(const FrameBufferRef& target, const Mat4x4& matrix); @@ -224,6 +226,6 @@ namespace Blah Vector m_layer_stack; Vector m_batches; - void render_single_batch(RenderCall& call, const DrawBatch& b, const Mat4x4& matrix); + void render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4x4& matrix); }; } \ No newline at end of file diff --git a/public/blah/drawing/spritefont.cpp b/public/blah/drawing/spritefont.cpp index ad98d97..d533c8f 100644 --- a/public/blah/drawing/spritefont.cpp +++ b/public/blah/drawing/spritefont.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include using namespace Blah; @@ -199,7 +198,7 @@ void SpriteFont::build(const Font& font, float size, const uint32_t* charset) packer.pack(); for (auto& it : packer.pages) - m_atlas.push_back(Graphics::create_texture(it)); + m_atlas.push_back(Texture::create(it)); // add character subtextures for (auto& it : packer.entries) diff --git a/public/blah/drawing/subtexture.cpp b/public/blah/drawing/subtexture.cpp index 74bc999..f2e9ff8 100644 --- a/public/blah/drawing/subtexture.cpp +++ b/public/blah/drawing/subtexture.cpp @@ -6,7 +6,7 @@ using namespace Blah; Subtexture::Subtexture() {} Subtexture::Subtexture(const TextureRef& texture) - : Subtexture(texture, Rect(0, 0, texture->width(), texture->height())) {} + : Subtexture(texture, Rect(0, 0, (float)texture->width(), (float)texture->height())) {} Subtexture::Subtexture(const TextureRef& texture, Rect source) : Subtexture(texture, source, Rect(0, 0, source.w, source.h)) {} @@ -48,8 +48,8 @@ void Subtexture::crop_info(const Rect& clip, Rect* dest_source, Rect* dest_frame { *dest_source = (clip + source.top_left() + frame.top_left()).overlap_rect(source); - dest_frame->x = Calc::min(0, frame.x + clip.x); - dest_frame->y = Calc::min(0, frame.y + clip.y); + dest_frame->x = Calc::min(0.0f, frame.x + clip.x); + dest_frame->y = Calc::min(0.0f, frame.y + clip.y); dest_frame->w = clip.w; dest_frame->h = clip.h; } diff --git a/public/blah/graphics/blend.cpp b/public/blah/graphics/blend.cpp new file mode 100644 index 0000000..cdf6d5d --- /dev/null +++ b/public/blah/graphics/blend.cpp @@ -0,0 +1,25 @@ +#include + +using namespace Blah; + +const BlendMode BlendMode::Normal = BlendMode( + BlendOp::Add, + BlendFactor::One, + BlendFactor::OneMinusSrcAlpha, + BlendOp::Add, + BlendFactor::One, + BlendFactor::OneMinusSrcAlpha, + BlendMask::RGBA, + 0xffffffff +); + +const BlendMode BlendMode::Subtract = BlendMode( + BlendOp::ReverseSubtract, + BlendFactor::One, + BlendFactor::One, + BlendOp::Add, + BlendFactor::One, + BlendFactor::One, + BlendMask::RGBA, + 0xffffffff +); \ No newline at end of file diff --git a/public/blah/graphics/blend.h b/public/blah/graphics/blend.h new file mode 100644 index 0000000..41789f9 --- /dev/null +++ b/public/blah/graphics/blend.h @@ -0,0 +1,96 @@ +#pragma once +#include + +namespace Blah +{ + enum class BlendOp + { + Add, + Subtract, + ReverseSubtract, + Min, + Max + }; + + enum class BlendFactor + { + Zero, + One, + SrcColor, + OneMinusSrcColor, + DstColor, + OneMinusDstColor, + SrcAlpha, + OneMinusSrcAlpha, + DstAlpha, + OneMinusDstAlpha, + ConstantColor, + OneMinusConstantColor, + ConstantAlpha, + OneMinusConstantAlpha, + SrcAlphaSaturate, + Src1Color, + OneMinusSrc1Color, + Src1Alpha, + OneMinusSrc1Alpha + }; + + enum class BlendMask + { + None = 0, + Red = 1, + Green = 2, + Blue = 4, + Alpha = 8, + RGB = Red | Green | Blue, + RGBA = Red | Green | Blue | Alpha, + }; + + struct BlendMode + { + BlendOp colorOp; + BlendFactor colorSrc; + BlendFactor colorDst; + BlendOp alphaOp; + BlendFactor alphaSrc; + BlendFactor alphaDst; + BlendMask mask; + uint32_t rgba; + + BlendMode() = default; + + BlendMode(BlendOp op, BlendFactor src, BlendFactor dst) + { + colorOp = op; + colorSrc = src; + colorDst = dst; + alphaOp = op; + alphaSrc = src; + alphaDst = dst; + mask = BlendMask::RGBA; + rgba = 0xffffffff; + } + + BlendMode(BlendOp rgbOp, BlendFactor rgbSrc, BlendFactor rgbDst, BlendOp aOp, BlendFactor aSrc, BlendFactor aDst, BlendMask blendMask, uint32_t blendColor) + { + colorOp = rgbOp; + colorSrc = rgbSrc; + colorDst = rgbDst; + alphaOp = aOp; + alphaSrc = aSrc; + alphaDst = aDst; + mask = blendMask; + rgba = blendColor; + } + + inline bool operator==(const BlendMode& rhs) const { + return colorOp == rhs.colorOp && colorSrc == rhs.colorSrc && colorDst == rhs.colorDst && + alphaOp == rhs.alphaOp && alphaSrc == rhs.alphaSrc && alphaDst == rhs.alphaDst && + mask == rhs.mask && rgba == rhs.rgba; + } + inline bool operator!=(const BlendMode& rhs) const { return !(*this == rhs); } + + static const BlendMode Normal; + static const BlendMode Subtract; + }; +} \ No newline at end of file diff --git a/public/blah/graphics/framebuffer.cpp b/public/blah/graphics/framebuffer.cpp new file mode 100644 index 0000000..ff912df --- /dev/null +++ b/public/blah/graphics/framebuffer.cpp @@ -0,0 +1,38 @@ +#include +#include + +using namespace Blah; + +FrameBufferRef FrameBuffer::create(int width, int height) +{ + static const TextureFormat attachment = TextureFormat::RGBA; + return create(width, height, &attachment, 1); +} + +FrameBufferRef FrameBuffer::create(int width, int height, const TextureFormat* attachments, int attachment_count) +{ + BLAH_ASSERT(width > 0 && height > 0, "FrameBuffer width and height must be larger than 0"); + BLAH_ASSERT(attachment_count <= BLAH_ATTACHMENTS, "Exceeded maximum attachment count"); + BLAH_ASSERT(attachment_count > 0, "At least one attachment must be provided"); + + int color_count = 0; + int depth_count = 0; + + for (int i = 0; i < attachment_count; i++) + { + BLAH_ASSERT((int)attachments[i] > (int)TextureFormat::None && (int)attachments[i] < (int)TextureFormat::Count, "Invalid texture format"); + + if (attachments[i] == TextureFormat::DepthStencil) + depth_count++; + else + color_count++; + } + + BLAH_ASSERT(depth_count <= 1, "FrameBuffer can only have 1 Depth/Stencil Texture"); + BLAH_ASSERT(color_count <= BLAH_ATTACHMENTS - 1, "Exceeded maximum Color attachment count"); + + if (color_count <= BLAH_ATTACHMENTS - 1 && depth_count <= 1 && width > 0 && height > 0) + return GraphicsBackend::create_framebuffer(width, height, attachments, attachment_count); + + return FrameBufferRef(); +} diff --git a/public/blah/graphics/framebuffer.h b/public/blah/graphics/framebuffer.h index aa8b119..473d23e 100644 --- a/public/blah/graphics/framebuffer.h +++ b/public/blah/graphics/framebuffer.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include // 4 color attachments + 1 depth/stencil @@ -10,9 +11,21 @@ namespace Blah { typedef StackVector Attachments; + class FrameBuffer; + typedef std::shared_ptr FrameBufferRef; + class FrameBuffer { public: + + // Creates a new FrameBuffer with a single Color attachment + // If the FrameBuffer creation fails, it will return an invalid FrameBufferRef. + static FrameBufferRef create(int width, int height); + + // Creates a new FrameBuffer with the given Texture Attachments. You must provide at least one Attachment. + // If the FrameBuffer creation fails, it will return an invalid FrameBufferRef. + static FrameBufferRef create(int width, int height, const TextureFormat* attachments, int attachmentCount); + virtual ~FrameBuffer() = default; // Gets the list of Attachments from the FrameBuffer @@ -32,7 +45,9 @@ namespace Blah // Gets the height of the FrameBuffer virtual int height() const = 0; + + // Clears the FrameBuffer + virtual void clear(Color color) = 0; }; - typedef std::shared_ptr FrameBufferRef; } diff --git a/public/blah/graphics/graphics.cpp b/public/blah/graphics/graphics.cpp deleted file mode 100644 index 598a963..0000000 --- a/public/blah/graphics/graphics.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Blah; - -const BlendMode BlendMode::Normal = BlendMode( - BlendOp::Add, - BlendFactor::One, - BlendFactor::OneMinusSrcAlpha, - BlendOp::Add, - BlendFactor::One, - BlendFactor::OneMinusSrcAlpha, - BlendMask::RGBA, - 0xffffffff -); - -const BlendMode BlendMode::Subtract = BlendMode( - BlendOp::ReverseSubtract, - BlendFactor::One, - BlendFactor::One, - BlendOp::Add, - BlendFactor::One, - BlendFactor::One, - BlendMask::RGBA, - 0xffffffff -); - -const GraphicsInfo* Graphics::info() -{ - return GraphicsBackend::info(); -} - -GraphicsRenderer Graphics::renderer() -{ - return GraphicsBackend::renderer(); -} - -TextureRef Graphics::create_texture(const Image& image) -{ - auto tex = create_texture(image.width, image.height, TextureFormat::RGBA); - tex->set_data((unsigned char*)image.pixels); - return tex; -} - -TextureRef Graphics::create_texture(int width, int height, unsigned char* rgba) -{ - auto tex = create_texture(width, height, TextureFormat::RGBA); - tex->set_data(rgba); - return tex; -} - -TextureRef Graphics::create_texture(int width, int height, TextureFormat format) -{ - BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0"); - BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format"); - - if (width > 0 && height > 0) - return GraphicsBackend::create_texture(width, height, TextureFilter::Linear, TextureWrap::Repeat, TextureWrap::Repeat, format); - - return TextureRef(); -} - -TextureRef Graphics::create_texture(Stream& stream) -{ - Image img = Image(stream); - - if (img.pixels != nullptr && img.width > 0 && img.height > 0) - { - auto tex = create_texture(img.width, img.height, TextureFormat::RGBA); - tex->set_data((unsigned char*)img.pixels); - return tex; - } - - return TextureRef(); -} - -TextureRef Graphics::create_texture(const char* file) -{ - Image img = Image(file); - - if (img.pixels != nullptr) - { - auto tex = create_texture(img.width, img.height, TextureFormat::RGBA); - tex->set_data((unsigned char*)img.pixels); - return tex; - } - - return TextureRef(); -} - -FrameBufferRef Graphics::create_framebuffer(int width, int height) -{ - static const TextureFormat attachment = TextureFormat::RGBA; - return create_framebuffer(width, height, &attachment, 1); -} - -FrameBufferRef Graphics::create_framebuffer(int width, int height, const TextureFormat* attachments, int attachment_count) -{ - BLAH_ASSERT(width > 0 && height > 0, "FrameBuffer width and height must be larger than 0"); - BLAH_ASSERT(attachment_count <= BLAH_ATTACHMENTS, "Exceeded maximum attachment count"); - BLAH_ASSERT(attachment_count > 0, "At least one attachment must be provided"); - - int color_count = 0; - int depth_count = 0; - - for (int i = 0; i < attachment_count; i++) - { - BLAH_ASSERT((int)attachments[i] > (int)TextureFormat::None && (int)attachments[i] < (int)TextureFormat::Count, "Invalid texture format"); - - if (attachments[i] == TextureFormat::DepthStencil) - depth_count++; - else - color_count++; - } - - BLAH_ASSERT(depth_count <= 1, "FrameBuffer can only have 1 Depth/Stencil Texture"); - BLAH_ASSERT(color_count <= BLAH_ATTACHMENTS - 1, "Exceeded maximum Color attachment count"); - - if (color_count <= BLAH_ATTACHMENTS - 1 && depth_count <= 1 && width > 0 && height > 0) - return GraphicsBackend::create_framebuffer(width, height, attachments, attachment_count); - - return FrameBufferRef(); -} - -ShaderRef Graphics::create_shader(const ShaderData* data) -{ - return GraphicsBackend::create_shader(data); -} - -MaterialRef Graphics::create_material(const ShaderRef& shader) -{ - BLAH_ASSERT(shader, "The provided shader is invalid"); - - if (shader) - return MaterialRef(new Material(shader)); - - return MaterialRef(); -} - -MeshRef Graphics::create_mesh() -{ - return GraphicsBackend::create_mesh(); -} - -RenderCall::RenderCall() -{ - blend = BlendMode::Normal; - target = Graphics::backbuffer; - mesh = MeshRef(); - material = MaterialRef(); - has_viewport = false; - has_scissor = false; - viewport = Rect(); - scissor = Rect(); - index_start = 0; - index_count = 0; - instance_count = 0; - depth = Compare::None; - cull = Cull::None; -} - -void Graphics::render(const RenderCall& render_call) -{ - // Validate Material - if (!render_call.material) - { - Log::warn("Trying to draw with an invalid Material"); - return; - } - - // Validate Shader - if (!render_call.material->shader()) - { - Log::warn("Trying to draw with an invalid Shader"); - return; - } - - // Validate Mesh - if (!render_call.mesh) - { - Log::warn("Trying to draw with an invalid Mesh"); - return; - } - - // copy call - RenderCall call = render_call; - - // Validate Index Count - int64_t index_count = call.mesh->index_count(); - if (call.index_start + call.index_count > index_count) - { - Log::warn( - "Trying to draw more indices than exist in the index buffer (%i-%i / %i)", - call.index_start, - call.index_start + call.index_count, - index_count); - - if (call.index_start > call.index_count) - return; - - call.index_count = call.index_count - call.index_start; - } - - // Validate Instance Count - int64_t instance_count = call.mesh->instance_count(); - if (call.instance_count > instance_count) - { - Log::warn( - "Trying to draw more instances than exist in the index buffer (%i / %i)", - call.instance_count, - instance_count); - - call.instance_count = instance_count; - } - - // get the total drawable size - Point draw_size; - if (!call.target) - draw_size = Point(App::draw_width(), App::draw_height()); - else - draw_size = Point(call.target->width(), call.target->height()); - - // Validate Viewport - if (!call.has_viewport) - { - call.viewport.x = 0; - call.viewport.y = 0; - call.viewport.w = (float)draw_size.x; - call.viewport.h = (float)draw_size.y; - } - else - { - call.viewport = call.viewport.overlap_rect(Rect(0, 0, draw_size.x, draw_size.y)); - } - - // Validate Scissor - if (call.has_scissor) - call.scissor = call.scissor.overlap_rect(Rect(0, 0, draw_size.x, draw_size.y)); - - GraphicsBackend::render(call); -} - -void Graphics::clear(const FrameBufferRef& target, uint32_t rgba) -{ - GraphicsBackend::clear(target, rgba); -} \ No newline at end of file diff --git a/public/blah/graphics/graphics.h b/public/blah/graphics/graphics.h deleted file mode 100644 index df01165..0000000 --- a/public/blah/graphics/graphics.h +++ /dev/null @@ -1,246 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Blah -{ - class Stream; - class Image; - - enum class Compare - { - None, - Always, - Never, - Less, - Equal, - LessOrEqual, - Greater, - NotEqual, - GreatorOrEqual - }; - - enum class Cull - { - None = 0, - Front = 1, - Back = 2, - Both = 3 - }; - - enum class BlendOp - { - Add, - Subtract, - ReverseSubtract, - Min, - Max - }; - - enum class BlendFactor - { - Zero, - One, - SrcColor, - OneMinusSrcColor, - DstColor, - OneMinusDstColor, - SrcAlpha, - OneMinusSrcAlpha, - DstAlpha, - OneMinusDstAlpha, - ConstantColor, - OneMinusConstantColor, - ConstantAlpha, - OneMinusConstantAlpha, - SrcAlphaSaturate, - Src1Color, - OneMinusSrc1Color, - Src1Alpha, - OneMinusSrc1Alpha - }; - - enum class BlendMask - { - None = 0, - Red = 1, - Green = 2, - Blue = 4, - Alpha = 8, - RGB = Red | Green | Blue, - RGBA = Red | Green | Blue | Alpha, - }; - - struct BlendMode - { - BlendOp colorOp; - BlendFactor colorSrc; - BlendFactor colorDst; - BlendOp alphaOp; - BlendFactor alphaSrc; - BlendFactor alphaDst; - BlendMask mask; - uint32_t rgba; - - BlendMode() = default; - - BlendMode(BlendOp op, BlendFactor src, BlendFactor dst) - { - colorOp = op; - colorSrc = src; - colorDst = dst; - alphaOp = op; - alphaSrc = src; - alphaDst = dst; - mask = BlendMask::RGBA; - rgba = 0xffffffff; - } - - BlendMode(BlendOp rgbOp, BlendFactor rgbSrc, BlendFactor rgbDst, BlendOp aOp, BlendFactor aSrc, BlendFactor aDst, BlendMask blendMask, uint32_t blendColor) - { - colorOp = rgbOp; - colorSrc = rgbSrc; - colorDst = rgbDst; - alphaOp = aOp; - alphaSrc = aSrc; - alphaDst = aDst; - mask = blendMask; - rgba = blendColor; - } - - inline bool operator==(const BlendMode& rhs) const { - return colorOp == rhs.colorOp && colorSrc == rhs.colorSrc && colorDst == rhs.colorDst && - alphaOp == rhs.alphaOp && alphaSrc == rhs.alphaSrc && alphaDst == rhs.alphaDst && - mask == rhs.mask && rgba == rhs.rgba; - } - inline bool operator!=(const BlendMode& rhs) const { return !(*this == rhs); } - - static const BlendMode Normal; - static const BlendMode Subtract; - }; - - struct RenderCall - { - // Framebuffer to draw to - FrameBufferRef target; - - // Mesh to draw with - MeshRef mesh; - - // Material to draw with - MaterialRef material; - - // Whether the Render Call should use a specific viewport - bool has_viewport; - - // Whether the Render Call should use a scissor rectangle - bool has_scissor; - - // The viewport (only used if hasViewport is true) - Rect viewport; - - // The scissor rectangle (only used if hasScissor is true) - Rect scissor; - - // First index in the Mesh to draw from - int64_t index_start; - - // Total amount of indices to draw from the Mesh - int64_t index_count; - - // Total amount of instances to draw from the Mesh - int64_t instance_count; - - // Depth Compare Function - Compare depth; - - // Cull Mode - Cull cull; - - // Blend Mode - BlendMode blend; - - // Initializes a default Render Call - RenderCall(); - }; - - enum class GraphicsRenderer - { - None = -1, - OpenGL, - D3D11, - Metal, - Count - }; - - struct GraphicsInfo - { - bool instancing = false; - bool origin_bottom_left = false; - int max_texture_size = 0; - }; - - namespace Graphics - { - const FrameBufferRef backbuffer; - - // Gets graphics information from the graphics device - const GraphicsInfo* info(); - - // Gets the Renderer implementation type - GraphicsRenderer renderer(); - - // Creates a new Texture. - // If the Texture creation fails, it will return an invalid TextureRef. - TextureRef create_texture(const Image& image); - - // Creates a new Texture. - // If the Texture creation fails, it will return an invalid TextureRef. - TextureRef create_texture(int width, int height, unsigned char* rgba); - - // Creates a new Texture. - // If the Texture creation fails, it will return an invalid TextureRef. - TextureRef create_texture(int width, int height, TextureFormat format); - - // Creates a new Texture from a Stream. - // If the Texture creation fails, it will return an invalid TextureRef. - TextureRef create_texture(Stream& stream); - - // Creates a new Texture from a File. - // If the Texture creation fails, it will return an invalid TextureRef. - TextureRef create_texture(const char* file); - - // Creates a new FrameBuffer with a single Color attachment - // If the FrameBuffer creation fails, it will return an invalid FrameBufferRef. - FrameBufferRef create_framebuffer(int width, int height); - - // Creates a new FrameBuffer with the given Texture Attachments. You must provide at least one Attachment. - // If the FrameBuffer creation fails, it will return an invalid FrameBufferRef. - FrameBufferRef create_framebuffer(int width, int height, const TextureFormat* attachments, int attachmentCount); - - // Creates a Shader with the given Shader Data. - // If the Shader creation fails, it will return an invalid ShaderRef. - ShaderRef create_shader(const ShaderData* data); - - // Creates a new Material from the given Shader. - // If the Shader is invalid, it will return an invalid MaterialRef. - MaterialRef create_material(const ShaderRef& shader); - - // Creates a new Mesh. - // If the Mesh creation fails, it will return an invalid Mesh. - MeshRef create_mesh(); - - // Submits and Flushes the given render call to the graphics device. - void render(const RenderCall& render_call); - - // Clears the given FrameBuffer to the given color. - void clear(const FrameBufferRef& target, uint32_t rgba); - } -} \ No newline at end of file diff --git a/public/blah/graphics/material.cpp b/public/blah/graphics/material.cpp index 6dcf9ec..c419bc6 100644 --- a/public/blah/graphics/material.cpp +++ b/public/blah/graphics/material.cpp @@ -26,14 +26,24 @@ namespace } } +MaterialRef Material::create(const ShaderRef& shader) +{ + BLAH_ASSERT(shader, "The provided shader is invalid"); + + if (shader) + return MaterialRef(new Material(shader)); + + return MaterialRef(); +} + Material::Material(const ShaderRef& shader) { BLAH_ASSERT(shader, "Material is being created with an invalid shader"); m_shader = shader; auto& uniforms = shader->uniforms(); - Vector float_offsets; - size_t float_size = 0; + Vector float_offsets; + int float_size = 0; for (auto& uniform : uniforms) { diff --git a/public/blah/graphics/material.h b/public/blah/graphics/material.h index 4aa80f0..0497af2 100644 --- a/public/blah/graphics/material.h +++ b/public/blah/graphics/material.h @@ -6,15 +6,23 @@ namespace Blah { + class Material; + typedef std::shared_ptr MaterialRef; + class Material { - public: + private: Material(const ShaderRef& shader); Material(const Material& src) = delete; Material(Material&& src) = delete; Material& operator=(const Material& src) = delete; Material& operator=(Material&& src) = delete; + public: + // Creates a new Material from the given Shader. + // If the Shader is invalid, it will return an invalid MaterialRef. + static MaterialRef create(const ShaderRef& shader); + // Returns the Shader assigned to the Material. const ShaderRef shader() const; @@ -52,6 +60,4 @@ namespace Blah Vector m_floats; Vector m_data; }; - - typedef std::shared_ptr MaterialRef; } \ No newline at end of file diff --git a/public/blah/graphics/mesh.cpp b/public/blah/graphics/mesh.cpp index 54d2674..bc18525 100644 --- a/public/blah/graphics/mesh.cpp +++ b/public/blah/graphics/mesh.cpp @@ -1,7 +1,13 @@ #include "mesh.h" +#include using namespace Blah; +MeshRef Mesh::create() +{ + return GraphicsBackend::create_mesh(); +} + void Mesh::vertex_format(const VertexAttribute* attributes, int attribute_count, int stride) { if (stride < 0) diff --git a/public/blah/graphics/mesh.h b/public/blah/graphics/mesh.h index 3c10b8c..7871326 100644 --- a/public/blah/graphics/mesh.h +++ b/public/blah/graphics/mesh.h @@ -44,9 +44,16 @@ namespace Blah bool normalized; }; + class Mesh; + typedef std::shared_ptr MeshRef; + class Mesh { public: + // Creates a new Mesh. + // If the Mesh creation fails, it will return an invalid Mesh. + static MeshRef create(); + virtual ~Mesh() = default; // Sets the Vertex Format of the Mesh @@ -79,6 +86,4 @@ namespace Blah virtual void vertex_format_internal(const VertexAttribute* attributes, int count, int stride) = 0; virtual void instance_format_internal(const VertexAttribute* attributes, int count, int stride) = 0; }; - - typedef std::shared_ptr MeshRef; } \ No newline at end of file diff --git a/public/blah/graphics/renderpass.cpp b/public/blah/graphics/renderpass.cpp new file mode 100644 index 0000000..14f8fed --- /dev/null +++ b/public/blah/graphics/renderpass.cpp @@ -0,0 +1,111 @@ +#include +#include +#include + +using namespace Blah; + +RenderPass::RenderPass() +{ + blend = BlendMode::Normal; + target = App::backbuffer; + mesh = MeshRef(); + material = MaterialRef(); + has_viewport = false; + has_scissor = false; + viewport = Rect(); + scissor = Rect(); + index_start = 0; + index_count = 0; + instance_count = 0; + depth = Compare::None; + cull = Cull::None; +} + +void RenderPass::perform() +{ + // Validate Material + if (!material) + { + Log::warn("Trying to draw with an invalid Material"); + return; + } + + // Validate Shader + if (!material->shader()) + { + Log::warn("Trying to draw with an invalid Shader"); + return; + } + + // Validate Mesh + if (!mesh) + { + Log::warn("Trying to draw with an invalid Mesh"); + return; + } + + // copy call + RenderPass pass = *this; + + // Validate Backbuffer + if (!pass.target) + { + pass.target = App::backbuffer; + Log::warn("Trying to draw with an invalid Target; falling back to Back Buffer"); + } + + // Validate Index Count + int64_t index_count = pass.mesh->index_count(); + if (pass.index_start + pass.index_count > index_count) + { + Log::warn( + "Trying to draw more indices than exist in the index buffer (%i-%i / %i)", + pass.index_start, + pass.index_start + pass.index_count, + index_count); + + if (pass.index_start > pass.index_count) + return; + + pass.index_count = pass.index_count - pass.index_start; + } + + // Validate Instance Count + int64_t instance_count = pass.mesh->instance_count(); + if (pass.instance_count > instance_count) + { + Log::warn( + "Trying to draw more instances than exist in the index buffer (%i / %i)", + pass.instance_count, + instance_count); + + pass.instance_count = instance_count; + } + + // get the total drawable size + Vec2 draw_size; + if (!pass.target) + draw_size = Vec2(App::draw_width(), App::draw_height()); + else + draw_size = Vec2(pass.target->width(), pass.target->height()); + + // Validate Viewport + if (!pass.has_viewport) + { + pass.viewport.x = 0; + pass.viewport.y = 0; + pass.viewport.w = draw_size.x; + pass.viewport.h = draw_size.y; + } + else + { + pass.viewport = pass.viewport.overlap_rect(Rect(0, 0, draw_size.x, draw_size.y)); + } + + // Validate Scissor + if (pass.has_scissor) + pass.scissor = pass.scissor.overlap_rect(Rect(0, 0, draw_size.x, draw_size.y)); + + // perform render + GraphicsBackend::render(pass); +} \ No newline at end of file diff --git a/public/blah/graphics/renderpass.h b/public/blah/graphics/renderpass.h new file mode 100644 index 0000000..521141e --- /dev/null +++ b/public/blah/graphics/renderpass.h @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Blah +{ + enum class Compare + { + None, + Always, + Never, + Less, + Equal, + LessOrEqual, + Greater, + NotEqual, + GreatorOrEqual + }; + + enum class Cull + { + None = 0, + Front = 1, + Back = 2, + Both = 3 + }; + + struct RenderPass + { + // Framebuffer to draw to + FrameBufferRef target; + + // Mesh to draw with + MeshRef mesh; + + // Material to draw with + MaterialRef material; + + // Whether the RenderPass should use a specific viewport + bool has_viewport; + + // Whether the RenderPass should use a scissor rectangle + bool has_scissor; + + // The viewport (only used if hasViewport is true) + Rect viewport; + + // The scissor rectangle (only used if hasScissor is true) + Rect scissor; + + // First index in the Mesh to draw from + int64_t index_start; + + // Total amount of indices to draw from the Mesh + int64_t index_count; + + // Total amount of instances to draw from the Mesh + int64_t instance_count; + + // Depth Compare Function + Compare depth; + + // Cull Mode + Cull cull; + + // Blend Mode + BlendMode blend; + + // Initializes a default RenderPass + RenderPass(); + + // Performs the render + void perform(); + }; +} \ No newline at end of file diff --git a/public/blah/graphics/shader.cpp b/public/blah/graphics/shader.cpp new file mode 100644 index 0000000..e246536 --- /dev/null +++ b/public/blah/graphics/shader.cpp @@ -0,0 +1,9 @@ +#include +#include + +using namespace Blah; + +ShaderRef Shader::create(const ShaderData* data) +{ + return GraphicsBackend::create_shader(data); +} \ No newline at end of file diff --git a/public/blah/graphics/shader.h b/public/blah/graphics/shader.h index 165b42c..c079b94 100644 --- a/public/blah/graphics/shader.h +++ b/public/blah/graphics/shader.h @@ -30,9 +30,17 @@ namespace Blah const char* fragment; }; + class Shader; + typedef std::shared_ptr ShaderRef; + class Shader { public: + + // Creates a Shader with the given Shader Data. + // If the Shader creation fails, it will return an invalid ShaderRef. + static ShaderRef create(const ShaderData* data); + virtual ~Shader() = default; // Gets a list of Shader Uniforms from Shader @@ -42,5 +50,4 @@ namespace Blah virtual const Vector& uniforms() const = 0; }; - typedef std::shared_ptr ShaderRef; } \ No newline at end of file diff --git a/public/blah/graphics/texture.cpp b/public/blah/graphics/texture.cpp new file mode 100644 index 0000000..9b59430 --- /dev/null +++ b/public/blah/graphics/texture.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include + +using namespace Blah; + +TextureRef Texture::create(const Image& image) +{ + auto tex = create(image.width, image.height, TextureFormat::RGBA); + tex->set_data((unsigned char*)image.pixels); + return tex; +} + +TextureRef Texture::create(int width, int height, unsigned char* rgba) +{ + auto tex = create(width, height, TextureFormat::RGBA); + tex->set_data(rgba); + return tex; +} + +TextureRef Texture::create(int width, int height, TextureFormat format) +{ + BLAH_ASSERT(width > 0 && height > 0, "Texture width and height must be larger than 0"); + BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format"); + + if (width > 0 && height > 0) + return GraphicsBackend::create_texture(width, height, TextureFilter::Linear, TextureWrap::Repeat, TextureWrap::Repeat, format); + + return TextureRef(); +} + +TextureRef Texture::create(Stream& stream) +{ + Image img = Image(stream); + + if (img.pixels != nullptr && img.width > 0 && img.height > 0) + { + auto tex = create(img.width, img.height, TextureFormat::RGBA); + tex->set_data((unsigned char*)img.pixels); + return tex; + } + + return TextureRef(); +} + +TextureRef Texture::create(const char* file) +{ + Image img = Image(file); + + if (img.pixels != nullptr) + { + auto tex = create(img.width, img.height, TextureFormat::RGBA); + tex->set_data((unsigned char*)img.pixels); + return tex; + } + + return TextureRef(); +} \ No newline at end of file diff --git a/public/blah/graphics/texture.h b/public/blah/graphics/texture.h index 47d805a..f9b8a82 100644 --- a/public/blah/graphics/texture.h +++ b/public/blah/graphics/texture.h @@ -28,9 +28,35 @@ namespace Blah Count }; + class Image; + class Stream; + class Texture; + typedef std::shared_ptr TextureRef; + class Texture { public: + + // Creates a new Texture. + // If the Texture creation fails, it will return an invalid TextureRef. + static TextureRef create(const Image& image); + + // Creates a new Texture. + // If the Texture creation fails, it will return an invalid TextureRef. + static TextureRef create(int width, int height, unsigned char* rgba); + + // Creates a new Texture. + // If the Texture creation fails, it will return an invalid TextureRef. + static TextureRef create(int width, int height, TextureFormat format); + + // Creates a new Texture from a Stream. + // If the Texture creation fails, it will return an invalid TextureRef. + static TextureRef create(Stream& stream); + + // Creates a new Texture from a File. + // If the Texture creation fails, it will return an invalid TextureRef. + static TextureRef create(const char* file); + virtual ~Texture() = default; // gets the width of the texture @@ -70,6 +96,4 @@ namespace Blah // Returns true if the Texture is part of a FrameBuffer virtual bool is_framebuffer() const = 0; }; - - typedef std::shared_ptr TextureRef; } \ No newline at end of file