mirror of
https://github.com/NoelFB/blah.git
synced 2024-11-25 16:18:57 +08:00
graphics refactor & new organization
This commit is contained in:
parent
2c96f0813e
commit
15608d8309
|
@ -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
|
||||
|
|
16
README.md
16
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#pragma once
|
||||
#include <blah/graphics/graphics.h>
|
||||
#include <blah/app.h>
|
||||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <blah/math/color.h>
|
||||
|
||||
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.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifdef BLAH_USE_OPENGL
|
||||
|
||||
#include <blah/graphics/graphics.h>
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
#include <blah/internal/platform_backend.h>
|
||||
#include <blah/log.h>
|
||||
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
#include <blah/drawing/spritefont.h>
|
||||
#include <blah/drawing/subtexture.h>
|
||||
|
||||
#include <blah/graphics/blend.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/graphics/graphics.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include <blah/graphics/graphics.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/math/vec2.h>
|
||||
#include <blah/math/rect.h>
|
||||
|
@ -9,6 +8,9 @@
|
|||
#include <blah/drawing/subtexture.h>
|
||||
#include <blah/drawing/spritefont.h>
|
||||
#include <blah/containers/vector.h>
|
||||
#include <blah/graphics/blend.h>
|
||||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/app.h>
|
||||
|
||||
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<int> m_layer_stack;
|
||||
Vector<DrawBatch> 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);
|
||||
};
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
#include <blah/drawing/spritefont.h>
|
||||
#include <blah/images/font.h>
|
||||
#include <blah/images/packer.h>
|
||||
#include <blah/graphics/graphics.h>
|
||||
#include <blah/log.h>
|
||||
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
25
public/blah/graphics/blend.cpp
Normal file
25
public/blah/graphics/blend.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include <blah/graphics/blend.h>
|
||||
|
||||
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
|
||||
);
|
96
public/blah/graphics/blend.h
Normal file
96
public/blah/graphics/blend.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
38
public/blah/graphics/framebuffer.cpp
Normal file
38
public/blah/graphics/framebuffer.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
|
||||
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();
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/containers/stackvector.h>
|
||||
#include <blah/math/color.h>
|
||||
#include <memory>
|
||||
|
||||
// 4 color attachments + 1 depth/stencil
|
||||
|
@ -10,9 +11,21 @@ namespace Blah
|
|||
{
|
||||
typedef StackVector<TextureRef, BLAH_ATTACHMENTS> Attachments;
|
||||
|
||||
class FrameBuffer;
|
||||
typedef std::shared_ptr<FrameBuffer> 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<FrameBuffer> FrameBufferRef;
|
||||
}
|
||||
|
|
|
@ -1,255 +0,0 @@
|
|||
#include <blah/graphics/graphics.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/log.h>
|
||||
#include <blah/app.h>
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
#include <blah/images/image.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/math/rect.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <memory>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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<size_t> float_offsets;
|
||||
size_t float_size = 0;
|
||||
Vector<int> float_offsets;
|
||||
int float_size = 0;
|
||||
|
||||
for (auto& uniform : uniforms)
|
||||
{
|
||||
|
|
|
@ -6,15 +6,23 @@
|
|||
|
||||
namespace Blah
|
||||
{
|
||||
class Material;
|
||||
typedef std::shared_ptr<Material> 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<float*> m_floats;
|
||||
Vector<float> m_data;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Material> MaterialRef;
|
||||
}
|
|
@ -1,7 +1,13 @@
|
|||
#include "mesh.h"
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
|
||||
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)
|
||||
|
|
|
@ -44,9 +44,16 @@ namespace Blah
|
|||
bool normalized;
|
||||
};
|
||||
|
||||
class Mesh;
|
||||
typedef std::shared_ptr<Mesh> 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<Mesh> MeshRef;
|
||||
}
|
111
public/blah/graphics/renderpass.cpp
Normal file
111
public/blah/graphics/renderpass.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include <blah/graphics/renderpass.h>
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
#include <blah/log.h>
|
||||
|
||||
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);
|
||||
}
|
82
public/blah/graphics/renderpass.h
Normal file
82
public/blah/graphics/renderpass.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
#include <inttypes.h>
|
||||
#include <blah/math/rect.h>
|
||||
#include <blah/containers/str.h>
|
||||
#include <blah/graphics/texture.h>
|
||||
#include <blah/graphics/framebuffer.h>
|
||||
#include <blah/graphics/mesh.h>
|
||||
#include <blah/graphics/shader.h>
|
||||
#include <blah/graphics/material.h>
|
||||
#include <blah/graphics/blend.h>
|
||||
|
||||
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();
|
||||
};
|
||||
}
|
9
public/blah/graphics/shader.cpp
Normal file
9
public/blah/graphics/shader.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <blah/graphics/shader.h>
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
|
||||
using namespace Blah;
|
||||
|
||||
ShaderRef Shader::create(const ShaderData* data)
|
||||
{
|
||||
return GraphicsBackend::create_shader(data);
|
||||
}
|
|
@ -30,9 +30,17 @@ namespace Blah
|
|||
const char* fragment;
|
||||
};
|
||||
|
||||
class Shader;
|
||||
typedef std::shared_ptr<Shader> 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<UniformInfo>& uniforms() const = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Shader> ShaderRef;
|
||||
}
|
60
public/blah/graphics/texture.cpp
Normal file
60
public/blah/graphics/texture.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <blah/graphics/texture.h>
|
||||
#include <blah/images/image.h>
|
||||
#include <blah/streams/stream.h>
|
||||
#include <blah/internal/graphics_backend.h>
|
||||
#include <blah/log.h>
|
||||
|
||||
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();
|
||||
}
|
|
@ -28,9 +28,35 @@ namespace Blah
|
|||
Count
|
||||
};
|
||||
|
||||
class Image;
|
||||
class Stream;
|
||||
class Texture;
|
||||
typedef std::shared_ptr<Texture> 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<Texture> TextureRef;
|
||||
}
|
Loading…
Reference in New Issue
Block a user