diff --git a/include/blah/graphics/framebuffer.h b/include/blah/graphics/framebuffer.h index a9c7f25..6cad044 100644 --- a/include/blah/graphics/framebuffer.h +++ b/include/blah/graphics/framebuffer.h @@ -14,6 +14,15 @@ namespace Blah class FrameBuffer; typedef std::shared_ptr FrameBufferRef; + enum class ClearMask + { + None = 0, + Color = 1, + Depth = 2, + Stencil = 4, + All = (int)Color | (int)Depth | (int)Stencil + }; + class FrameBuffer { protected: @@ -56,7 +65,7 @@ namespace Blah virtual int height() const = 0; // Clears the FrameBuffer - virtual void clear(Color color) = 0; + virtual void clear(Color color = Color::black, float depth = 1.0f, uint8_t stencil = 0, ClearMask mask = ClearMask::All) = 0; }; } diff --git a/include/blah/math/calc.h b/include/blah/math/calc.h index c897750..252ed39 100644 --- a/include/blah/math/calc.h +++ b/include/blah/math/calc.h @@ -61,6 +61,8 @@ namespace Blah float cos(float x); + float tan(float x); + float atan2(float y, float x); float pow(float x, float n); diff --git a/include/blah/math/mat4x4.h b/include/blah/math/mat4x4.h index eda1029..1cdd5f2 100644 --- a/include/blah/math/mat4x4.h +++ b/include/blah/math/mat4x4.h @@ -1,4 +1,5 @@ #pragma once +#include "vec3.h" namespace Blah { @@ -36,8 +37,11 @@ namespace Blah static Mat4x4 create_ortho(float width, float height, float z_near_plane, float z_far_plane); static Mat4x4 create_ortho_offcenter(float left, float right, float bottom, float top, float z_near_plane, float z_far_plane); + static Mat4x4 create_perspective(float field_of_view, float ratio, float z_near_plane, float z_far_plane); static Mat4x4 create_translation(float x, float y, float z); static Mat4x4 create_scale(float x, float y, float z); + static Mat4x4 create_lookat(Vec3 position, Vec3 target, Vec3 up); + Mat4x4 operator* (const Mat4x4& rhs); }; diff --git a/include/blah/math/vec3.h b/include/blah/math/vec3.h index 172aaaf..f64cd3c 100644 --- a/include/blah/math/vec3.h +++ b/include/blah/math/vec3.h @@ -1,4 +1,5 @@ #pragma once +#include "calc.h" namespace Blah { @@ -19,5 +20,37 @@ namespace Blah , y(y) , z(z) {} + + inline Vec3 operator +(const Vec3 rhs) const + { + return Vec3(x + rhs.x, y + rhs.y, z + rhs.z); + } + + inline Vec3 operator -(const Vec3 rhs) const + { + return Vec3(x + rhs.x, y + rhs.y, z + rhs.z); + } + + inline Vec3 normal() const + { + float ls = x * x + y * y + z * z; + float length = (float)Calc::sqrt(ls); + return Vec3(x / length, y / length, z / length); + } + + static inline float dot(Vec3 a, Vec3 b) + { + return a.x * b.x + + a.y * b.y + + a.z * b.z; + } + + static inline Vec3 cross(Vec3 a, Vec3 b) + { + return Vec3( + a.y * b.z - a.z * b.y, + a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.x); + } }; } \ No newline at end of file diff --git a/src/core/app.cpp b/src/core/app.cpp index aeb755d..5ea0bb3 100644 --- a/src/core/app.cpp +++ b/src/core/app.cpp @@ -300,9 +300,9 @@ namespace return App::draw_height(); } - virtual void clear(Color color) override + virtual void clear(Color color, float depth, uint8_t stencil, ClearMask mask) override { - GraphicsBackend::clear_backbuffer(color); + GraphicsBackend::clear_backbuffer(color, depth, stencil, mask); } }; diff --git a/src/internal/graphics_backend.h b/src/internal/graphics_backend.h index dd69a4e..b388fea 100644 --- a/src/internal/graphics_backend.h +++ b/src/internal/graphics_backend.h @@ -39,7 +39,7 @@ namespace Blah void render(const RenderPass& pass); // Clears the backbuffer - void clear_backbuffer(Color color); + void clear_backbuffer(Color color, float depth, uint8_t stencil, ClearMask mask); // Creates a new Texture. // if the Texture is invalid, this should return an empty reference. diff --git a/src/internal/graphics_backend_d3d11.cpp b/src/internal/graphics_backend_d3d11.cpp index 03bde47..e14a665 100644 --- a/src/internal/graphics_backend_d3d11.cpp +++ b/src/internal/graphics_backend_d3d11.cpp @@ -25,7 +25,8 @@ namespace Blah ID3D11Device* device = nullptr; ID3D11DeviceContext* context = nullptr; IDXGISwapChain* swap_chain = nullptr; - ID3D11RenderTargetView* backbuffer = nullptr; + ID3D11RenderTargetView* backbuffer_view = nullptr; + ID3D11DepthStencilView* backbuffer_depth_view = nullptr; // supported renderer features RendererFeatures features; @@ -120,12 +121,10 @@ namespace Blah desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; desc.MiscFlags = 0; - if (is_framebuffer) - desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + bool is_depth_stencil = false; switch (format) { @@ -144,9 +143,18 @@ namespace Blah case TextureFormat::DepthStencil: desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; m_size = width * height * 4; + is_depth_stencil = true; break; } + if (!is_depth_stencil) + desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE; + else + desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL; + + if (is_framebuffer && !is_depth_stencil) + desc.BindFlags |= D3D11_BIND_RENDER_TARGET; + m_dxgi_format = desc.Format; auto hr = state.device->CreateTexture2D(&desc, NULL, &texture); @@ -158,11 +166,14 @@ namespace Blah return; } - hr = state.device->CreateShaderResourceView(texture, NULL, &view); - if (!SUCCEEDED(hr)) + if (!is_depth_stencil) { - texture->Release(); - texture = nullptr; + hr = state.device->CreateShaderResourceView(texture, NULL, &view); + if (!SUCCEEDED(hr)) + { + texture->Release(); + texture = nullptr; + } } } @@ -347,12 +358,27 @@ namespace Blah return m_attachments[0]->height(); } - virtual void clear(Color color) override + virtual void clear(Color color, float depth, uint8_t stencil, ClearMask mask) override { float col[4] = { color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f }; - for (int i = 0; i < m_attachments.size(); i++) - state.context->ClearRenderTargetView(color_views[i], col); + if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color) + { + for (int i = 0; i < m_attachments.size() - 1; i++) + state.context->ClearRenderTargetView(color_views[i], col); + } + + if (depth_view) + { + UINT flags = 0; + if (((int)mask & (int)ClearMask::Depth) == (int)ClearMask::Depth) + flags |= D3D11_CLEAR_DEPTH; + if (((int)mask & (int)ClearMask::Stencil) == (int)ClearMask::Stencil) + flags |= D3D11_CLEAR_STENCIL; + + if (flags != 0) + state.context->ClearDepthStencilView(depth_view, flags, depth, stencil); + } } }; @@ -722,10 +748,13 @@ namespace Blah state.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&frame_buffer); if (frame_buffer) { - state.device->CreateRenderTargetView(frame_buffer, nullptr, &state.backbuffer); + state.device->CreateRenderTargetView(frame_buffer, nullptr, &state.backbuffer_view); frame_buffer->Release(); } + // TODO: + // create a depth backbuffer + // Store Features state.features.instancing = true; state.features.max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; @@ -802,8 +831,8 @@ namespace Blah if (state.last_size != next_size) { // release old buffer - if (state.backbuffer) - state.backbuffer->Release(); + if (state.backbuffer_view) + state.backbuffer_view->Release(); // perform resize hr = state.swap_chain->ResizeBuffers(0, next_size.x, next_size.y, DXGI_FORMAT_B8G8R8A8_UNORM, 0); @@ -815,7 +844,7 @@ namespace Blah hr = state.swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&frame_buffer); if (SUCCEEDED(hr) && frame_buffer) { - hr = state.device->CreateRenderTargetView(frame_buffer, nullptr, &state.backbuffer); + hr = state.device->CreateRenderTargetView(frame_buffer, nullptr, &state.backbuffer_view); BLAH_ASSERT(SUCCEEDED(hr), "Failed to update Backbuffer on Resize"); frame_buffer->Release(); } @@ -870,7 +899,7 @@ namespace Blah // Set the Target if (pass.target == App::backbuffer || !pass.target) { - ctx->OMSetRenderTargets(1, &state.backbuffer, nullptr); + ctx->OMSetRenderTargets(1, &state.backbuffer_view, state.backbuffer_depth_view); } else { @@ -1036,10 +1065,25 @@ namespace Blah } } - void GraphicsBackend::clear_backbuffer(Color color) + void GraphicsBackend::clear_backbuffer(Color color, float depth, uint8_t stencil, ClearMask mask) { - float clear[4] = { color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f }; - state.context->ClearRenderTargetView(state.backbuffer, clear); + if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color) + { + float clear[4] = { color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f }; + state.context->ClearRenderTargetView(state.backbuffer_view, clear); + } + + if (state.backbuffer_depth_view) + { + UINT flags = 0; + if (((int)mask & (int)ClearMask::Depth) == (int)ClearMask::Depth) + flags |= D3D11_CLEAR_DEPTH; + if (((int)mask & (int)ClearMask::Stencil) == (int)ClearMask::Stencil) + flags |= D3D11_CLEAR_STENCIL; + + if (flags != 0) + state.context->ClearDepthStencilView(state.backbuffer_depth_view, flags, depth, stencil); + } } // Utility Methods diff --git a/src/internal/graphics_backend_gl.cpp b/src/internal/graphics_backend_gl.cpp index 3439a06..329cb57 100644 --- a/src/internal/graphics_backend_gl.cpp +++ b/src/internal/graphics_backend_gl.cpp @@ -749,13 +749,24 @@ namespace Blah return m_height; } - virtual void clear(Color color) override + virtual void clear(Color color, float depth, uint8_t stencil, ClearMask mask) override { + int clear = 0; + + if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color) + clear |= GL_COLOR_BUFFER_BIT; + if (((int)mask & (int)ClearMask::Depth) == (int)ClearMask::Depth) + clear |= GL_DEPTH_BUFFER_BIT; + if (((int)mask & (int)ClearMask::Stencil) == (int)ClearMask::Stencil) + clear |= GL_STENCIL_BUFFER_BIT; + gl.BindFramebuffer(GL_FRAMEBUFFER, m_id); gl.Disable(GL_SCISSOR_TEST); gl.ColorMask(true, true, true, true); gl.ClearColor(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f); - gl.Clear(GL_COLOR_BUFFER_BIT); + gl.ClearDepth(depth); + gl.ClearStencil(stencil); + gl.Clear(clear); } }; @@ -1485,13 +1496,24 @@ namespace Blah } } - void GraphicsBackend::clear_backbuffer(Color color) + void GraphicsBackend::clear_backbuffer(Color color, float depth, uint8_t stencil, ClearMask mask) { + int clear = 0; + + if (((int)mask & (int)ClearMask::Color) == (int)ClearMask::Color) + clear |= GL_COLOR_BUFFER_BIT; + if (((int)mask & (int)ClearMask::Depth) == (int)ClearMask::Depth) + clear |= GL_DEPTH_BUFFER_BIT; + if (((int)mask & (int)ClearMask::Stencil) == (int)ClearMask::Stencil) + clear |= GL_STENCIL_BUFFER_BIT; + gl.BindFramebuffer(GL_FRAMEBUFFER, 0); gl.Disable(GL_SCISSOR_TEST); gl.ColorMask(true, true, true, true); gl.ClearColor(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f); - gl.Clear(GL_COLOR_BUFFER_BIT); + gl.ClearDepth(depth); + gl.ClearStencil(stencil); + gl.Clear(clear); } } diff --git a/src/math/calc.cpp b/src/math/calc.cpp index e6d734c..67a4b5b 100644 --- a/src/math/calc.cpp +++ b/src/math/calc.cpp @@ -113,6 +113,11 @@ float Calc::cos(float x) return cosf(x); } +float Calc::tan(float x) +{ + return tanf(x); +} + float Calc::atan2(float y, float x) { return atan2f(y, x); diff --git a/src/math/mat4x4.cpp b/src/math/mat4x4.cpp index 313d9f3..3ea3ca0 100644 --- a/src/math/mat4x4.cpp +++ b/src/math/mat4x4.cpp @@ -1,4 +1,5 @@ #include +#include using namespace Blah; @@ -59,6 +60,29 @@ Mat4x4 Mat4x4::create_ortho_offcenter(float left, float right, float bottom, flo return result; } +Mat4x4 Mat4x4::create_perspective(float field_of_view, float ratio, float z_near_plane, float z_far_plane) +{ + float yScale = 1.0f / (float)Calc::tan(field_of_view * 0.5f); + float xScale = yScale / ratio; + + Mat4x4 result; + + result.m11 = xScale; + result.m12 = result.m13 = result.m14 = 0.0f; + + result.m22 = yScale; + result.m21 = result.m23 = result.m24 = 0.0f; + + result.m31 = result.m32 = 0.0f; + result.m33 = z_far_plane / (z_near_plane - z_far_plane); + result.m34 = -1.0f; + + result.m41 = result.m42 = result.m44 = 0.0f; + result.m43 = z_near_plane * z_far_plane / (z_near_plane - z_far_plane); + + return result; +} + Mat4x4 Mat4x4::create_translation(float x, float y, float z) { Mat4x4 result = identity; @@ -81,6 +105,34 @@ Mat4x4 Mat4x4::create_scale(float x, float y, float z) return result; } +Mat4x4 Mat4x4::create_lookat(Vec3 position, Vec3 target, Vec3 up) +{ + Vec3 zaxis = (position - target).normal(); + Vec3 xaxis = Vec3::cross(up, zaxis).normal(); + Vec3 yaxis = Vec3::cross(zaxis, xaxis); + + Mat4x4 result; + + result.m11 = xaxis.x; + result.m12 = yaxis.x; + result.m13 = zaxis.x; + result.m14 = 0.0f; + result.m21 = xaxis.y; + result.m22 = yaxis.y; + result.m23 = zaxis.y; + result.m24 = 0.0f; + result.m31 = xaxis.z; + result.m32 = yaxis.z; + result.m33 = zaxis.z; + result.m34 = 0.0f; + result.m41 = -Vec3::dot(xaxis, position); + result.m42 = -Vec3::dot(yaxis, position); + result.m43 = -Vec3::dot(zaxis, position); + result.m44 = 1.0f; + + return result; +} + Mat4x4 Mat4x4::operator*(const Mat4x4& rhs) { Mat4x4 m;