very WIP D3D11 support

This commit is contained in:
Noel Berry 2020-12-28 18:31:06 -08:00
parent 52e362e1b2
commit 41ae0ac6d5
15 changed files with 1795 additions and 357 deletions

View File

@ -103,12 +103,13 @@ add_library(blah
private/blah/third_party/stb_truetype.h
private/blah/internal/graphics_backend.h
private/blah/internal/graphics_backend_gl.cpp
private/blah/internal/graphics_backend_d3d11.cpp
private/blah/internal/input_backend.h
private/blah/internal/platform_backend.h
private/blah/internal/platform_backend_sdl2.cpp
)
target_include_directories(blah
target_include_directories(blah
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/public>
PRIVATE
@ -119,16 +120,27 @@ target_include_directories(blah
set(SDL2_ENABLED true CACHE BOOL "Use SDL2 as the System implementation")
set(SDL2_INCLUDE_DIRS "" CACHE FILEPATH "SDL2 Headers")
set(SDL2_LIBRARIES "" CACHE FILEPATH "SDL2 Headers")
set(OPENGL_ENABLED true CACHE BOOL "Include OpenGL graphics implementation")
set(OPENGL_ENABLED true CACHE BOOL "Use OpenGL graphics implementation")
set(D3D11_ENABLED false CACHE BOOL "Use D3D11 graphics implementation")
set(LIBS "")
# add OpenGL definition if we're using OpenGL
if (OPENGL_ENABLED)
add_compile_definitions(BLAH_USE_OPENGL)
endif()
# add D3D11 definition if we're using OpenGL
if (D3D11_ENABLED)
add_compile_definitions(BLAH_USE_D3D11)
set(LIBS ${LIBS} d3d11.lib dxguid.lib D3Dcompiler.lib)
endif()
# Link and create SDL2 Definition if we're using SDL2
if (SDL2_ENABLED)
add_compile_definitions(BLAH_USE_SDL2)
target_include_directories(blah PUBLIC "$<BUILD_INTERFACE:${SDL2_INCLUDE_DIRS}>")
target_link_libraries(blah PUBLIC ${SDL2_LIBRARIES})
endif()
set(LIBS ${LIBS} ${SDL2_LIBRARIES})
endif()
target_link_libraries(blah PUBLIC ${LIBS})

File diff suppressed because it is too large Load Diff

View File

@ -406,7 +406,7 @@ namespace Blah
}
// assign attributes
GLuint gl_mesh_assign_attributes(GLuint buffer, GLenum buffer_type, const VertexAttribute* vertex_attributes, int vertex_attribute_count, int stride, GLint divisor)
GLuint gl_mesh_assign_attributes(GLuint buffer, GLenum buffer_type, const VertexFormat& format, GLint divisor)
{
// bind
gl.BindBuffer(buffer_type, buffer);
@ -417,49 +417,83 @@ namespace Blah
// enable attributes
size_t ptr = 0;
for (int n = 0; n < vertex_attribute_count; n++)
for (int n = 0; n < format.attributes.size(); n++)
{
const VertexAttribute* attrib = (vertex_attributes + n);
auto& attribute = format.attributes[n];
GLenum type = GL_UNSIGNED_BYTE;
size_t component_size = 0;
int components = 1;
for (int i = 0, loc = 0; i < (int)attrib->components; i += 4, loc++)
if (attribute.type == VertexType::Float)
{
int components = attrib->components - i;
if (components > 4)
components = 4;
GLenum type = GL_UNSIGNED_BYTE;
size_t component_size = 0;
if (attrib->type == VertexAttributeType::Byte)
{
type = GL_UNSIGNED_BYTE;
component_size = 1;
}
else if (attrib->type == VertexAttributeType::Short)
{
type = GL_SHORT;
component_size = 2;
}
else if (attrib->type == VertexAttributeType::Int)
{
type = GL_INT;
component_size = 4;
}
else if (attrib->type == VertexAttributeType::Float)
{
type = GL_FLOAT;
component_size = 4;
}
uint32_t location = (uint32_t)(attrib->index + loc);
gl.EnableVertexAttribArray(location);
gl.VertexAttribPointer(location, components, type, attrib->normalized, stride, (void*)ptr);
gl.VertexAttribDivisor(location, divisor);
ptr += components * component_size;
type = GL_FLOAT;
component_size = 4;
components = 1;
}
else if (attribute.type == VertexType::Float2)
{
type = GL_FLOAT;
component_size = 4;
components = 2;
}
else if (attribute.type == VertexType::Float3)
{
type = GL_FLOAT;
component_size = 4;
components = 3;
}
else if (attribute.type == VertexType::Float4)
{
type = GL_FLOAT;
component_size = 4;
components = 4;
}
else if (attribute.type == VertexType::Byte4)
{
type = GL_BYTE;
component_size = 1;
components = 4;
}
else if (attribute.type == VertexType::UByte4)
{
type = GL_UNSIGNED_BYTE;
component_size = 1;
components = 4;
}
else if (attribute.type == VertexType::Short2)
{
type = GL_SHORT;
component_size = 2;
components = 2;
}
else if (attribute.type == VertexType::UShort2)
{
type = GL_UNSIGNED_SHORT;
component_size = 2;
components = 2;
}
else if (attribute.type == VertexType::Short4)
{
type = GL_SHORT;
component_size = 2;
components = 4;
}
else if (attribute.type == VertexType::UShort4)
{
type = GL_UNSIGNED_SHORT;
component_size = 2;
components = 4;
}
uint32_t location = (uint32_t)(attribute.index);
gl.EnableVertexAttribArray(location);
gl.VertexAttribPointer(location, components, type, attribute.normalized, format.stride, (void*)ptr);
gl.VertexAttribDivisor(location, divisor);
ptr += components * component_size;
}
return stride;
return format.stride;
}
// convert blend op enum
@ -554,12 +588,6 @@ namespace Blah
m_gl_format = GL_RG;
m_gl_type = GL_UNSIGNED_BYTE;
}
else if (format == TextureFormat::RGB)
{
m_gl_internal_format = GL_RGB;
m_gl_format = GL_RGB;
m_gl_type = GL_UNSIGNED_BYTE;
}
else if (format == TextureFormat::RGBA)
{
m_gl_internal_format = GL_RGBA;
@ -779,7 +807,6 @@ namespace Blah
{
m_id = 0;
// vertex shader
if (data->vertex == nullptr)
{
Log::error("Vertex Shader is required");
@ -819,33 +846,32 @@ namespace Blah
if (log_length > 0)
{
gl.DeleteShader(vertex_shader);
gl.DeleteShader(fragment_shader);
Log::error(log);
return;
}
}
// create actual shader program
GLuint id = gl.CreateProgram();
gl.AttachShader(id, vertex_shader);
gl.AttachShader(id, fragment_shader);
gl.LinkProgram(id);
gl.GetProgramInfoLog(id, 1024, &log_length, log);
gl.DetachShader(id, vertex_shader);
gl.DetachShader(id, fragment_shader);
gl.DeleteShader(vertex_shader);
gl.DeleteShader(fragment_shader);
if (log_length > 0)
{
gl.DetachShader(id, vertex_shader);
gl.DetachShader(id, fragment_shader);
gl.DeleteShader(vertex_shader);
gl.DeleteShader(fragment_shader);
Log::error(log);
return;
}
// ready to go
m_id = id;
// get uniforms
bool valid_uniforms = true;
{
const int max_name_length = 256;
@ -876,32 +902,48 @@ namespace Blah
UniformInfo uniform;
uniform.name = name;
uniform.type = UniformType::None;
uniform.buffer_index = 0;
uniform.array_length = size;
uniform_locations.push_back(gl.GetUniformLocation(id, name));
if (type == GL_FLOAT)
uniform.type = UniformType::Float;
else if (type == GL_FLOAT_VEC2)
uniform.type = UniformType::Float2;
else if (type == GL_FLOAT_VEC3)
uniform.type = UniformType::Float3;
else if (type == GL_FLOAT_VEC4)
uniform.type = UniformType::Float4;
else if (type == GL_FLOAT_MAT3x2)
uniform.type = UniformType::Mat3x2;
else if (type == GL_FLOAT_MAT4)
uniform.type = UniformType::Mat4x4;
else if (type == GL_SAMPLER_2D)
if (type == GL_SAMPLER_2D)
{
uniform.type = UniformType::Texture;
uniform.shader = ShaderType::Fragment;
}
else
{
Log::error("Unsupported Uniform Type. Must be either FLOAT, MAT3x2, MAT4, or SAMPLER_2D");
break;
uniform.shader = (ShaderType)((int)ShaderType::Vertex | (int)ShaderType::Fragment);
if (type == GL_FLOAT)
uniform.type = UniformType::Float;
else if (type == GL_FLOAT_VEC2)
uniform.type = UniformType::Float2;
else if (type == GL_FLOAT_VEC3)
uniform.type = UniformType::Float3;
else if (type == GL_FLOAT_VEC4)
uniform.type = UniformType::Float4;
else if (type == GL_FLOAT_MAT3x2)
uniform.type = UniformType::Mat3x2;
else if (type == GL_FLOAT_MAT4)
uniform.type = UniformType::Mat4x4;
else
{
valid_uniforms = false;
Log::error("Unsupported Uniform Type");
break;
}
}
m_uniforms.push_back(uniform);
}
}
// assign ID if the uniforms were valid
if (!valid_uniforms)
gl.DeleteProgram(id);
else
m_id = id;
}
~OpenGL_Shader()
@ -943,6 +985,8 @@ namespace Blah
uint8_t m_instance_attribs_enabled;
Vector<GLuint> m_vertex_attribs;
Vector<GLuint> m_instance_attribs;
GLenum m_index_format;
int m_index_size;
public:
@ -981,31 +1025,17 @@ namespace Blah
return m_id;
}
virtual void vertex_format_internal(const VertexAttribute* attributes, int attribute_count, int stride = -1) override
GLenum gl_index_format() const
{
gl.BindVertexArray(m_id);
{
if (m_vertex_buffer == 0)
gl.GenBuffers(1, &(m_vertex_buffer));
m_vertex_size = gl_mesh_assign_attributes(m_vertex_buffer, GL_ARRAY_BUFFER, attributes, attribute_count, stride, 0);
}
gl.BindVertexArray(0);
return m_index_format;
}
virtual void instance_format_internal(const VertexAttribute* attributes, int attribute_count, int stride = -1) override
int gl_index_size() const
{
gl.BindVertexArray(m_id);
{
if (m_instance_buffer == 0)
gl.GenBuffers(1, &(m_instance_buffer));
m_instance_size = gl_mesh_assign_attributes(m_instance_buffer, GL_ARRAY_BUFFER, attributes, attribute_count, stride, 1);
}
gl.BindVertexArray(0);
return m_index_size;
}
virtual void index_data(const void* indices, int64_t count) override
virtual void index_data(IndexFormat format, const void* indices, int64_t count) override
{
m_index_count = count;
@ -1014,48 +1044,64 @@ namespace Blah
if (m_index_buffer == 0)
gl.GenBuffers(1, &(m_index_buffer));
switch (format)
{
case IndexFormat::UInt16:
m_index_format = GL_UNSIGNED_SHORT;
m_index_size = 2;
break;
case IndexFormat::UInt32:
m_index_format = GL_UNSIGNED_INT;
m_index_size = 4;
break;
}
gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
gl.BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * count, indices, GL_DYNAMIC_DRAW);
gl.BufferData(GL_ELEMENT_ARRAY_BUFFER, m_index_size * count, indices, GL_DYNAMIC_DRAW);
}
gl.BindVertexArray(0);
}
virtual void vertex_data(const void* vertices, int64_t count) override
virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) override
{
if (m_vertex_buffer == 0 || m_vertex_size <= 0)
{
Log::error("You must assign a Vertex Format before setting Vertex Data");
}
else
{
m_vertex_count = count;
m_vertex_count = count;
gl.BindVertexArray(m_id);
{
gl.BindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
gl.BufferData(GL_ARRAY_BUFFER, m_vertex_size * count, vertices, GL_DYNAMIC_DRAW);
}
gl.BindVertexArray(0);
gl.BindVertexArray(m_id);
{
// Create Buffer if it doesn't exist yet
if (m_vertex_buffer == 0)
gl.GenBuffers(1, &(m_vertex_buffer));
// TODO:
// Cache this
m_vertex_size = gl_mesh_assign_attributes(m_vertex_buffer, GL_ARRAY_BUFFER, format, 0);
// Upload Buffer
gl.BindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
gl.BufferData(GL_ARRAY_BUFFER, m_vertex_size * count, vertices, GL_DYNAMIC_DRAW);
}
gl.BindVertexArray(0);
}
virtual void instance_data(const void* instances, int64_t count) override
virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) override
{
if (m_instance_buffer == 0 || m_instance_size <= 0)
{
Log::error("You must assign an Instance Format before setting Instance Data");
}
else
{
m_instance_count = count;
m_instance_count = count;
gl.BindVertexArray(m_id);
{
gl.BindBuffer(GL_ARRAY_BUFFER, m_instance_buffer);
gl.BufferData(GL_ARRAY_BUFFER, m_instance_size * count, instances, GL_DYNAMIC_DRAW);
}
gl.BindVertexArray(0);
gl.BindVertexArray(m_id);
{
// Create Buffer if it doesn't exist yet
if (m_instance_buffer == 0)
gl.GenBuffers(1, &(m_instance_buffer));
// TODO:
// Cache this
m_instance_size = gl_mesh_assign_attributes(m_instance_buffer, GL_ARRAY_BUFFER, format, 1);
// Upload Buffer
gl.BindBuffer(GL_ARRAY_BUFFER, m_instance_buffer);
gl.BufferData(GL_ARRAY_BUFFER, m_instance_size * count, instances, GL_DYNAMIC_DRAW);
}
gl.BindVertexArray(0);
}
virtual int64_t index_count() const override
@ -1222,6 +1268,7 @@ namespace Blah
// Use the Shader
// TODO: I don't love how material values are assigned or set here
// TODO: this should be cached?
{
gl.UseProgram(shader->gl_id());
@ -1230,6 +1277,8 @@ namespace Blah
GLint texture_ids[64];
auto& uniforms = shader->uniforms();
auto data = pass.material->data();
for (int i = 0; i < uniforms.size(); i++)
{
auto location = shader->uniform_locations[i];
@ -1258,36 +1307,44 @@ namespace Blah
}
gl.Uniform1iv(location, (GLint)uniform.array_length, &texture_ids[0]);
continue;
}
// Float
else if (uniform.type == UniformType::Float)
if (uniform.type == UniformType::Float)
{
gl.Uniform1fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i));
gl.Uniform1fv(location, (GLint)uniform.array_length, data);
data += uniform.array_length;
}
// Float2
else if (uniform.type == UniformType::Float2)
{
gl.Uniform2fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i));
gl.Uniform2fv(location, (GLint)uniform.array_length, data);
data += 2 * uniform.array_length;
}
// Float3
else if (uniform.type == UniformType::Float3)
{
gl.Uniform3fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i));
gl.Uniform3fv(location, (GLint)uniform.array_length, data);
data += 3 * uniform.array_length;
}
// Float4
else if (uniform.type == UniformType::Float4)
{
gl.Uniform4fv(location, (GLint)uniform.array_length, (const GLfloat*)pass.material->get_value(i));
gl.Uniform4fv(location, (GLint)uniform.array_length, data);
data += 4 * uniform.array_length;
}
// Matrix3x2
else if (uniform.type == UniformType::Mat3x2)
{
gl.UniformMatrix3x2fv(location, (GLint)uniform.array_length, 0, (const GLfloat*)pass.material->get_value(i));
gl.UniformMatrix3x2fv(location, (GLint)uniform.array_length, 0, data);
data += 6 * uniform.array_length;
}
// Matrix4x4
else if (uniform.type == UniformType::Mat4x4)
{
gl.UniformMatrix4fv(location, (GLint)uniform.array_length, 0, (const GLfloat*)pass.material->get_value(i));
gl.UniformMatrix4fv(location, (GLint)uniform.array_length, 0, data);
data += 16 * uniform.array_length;
}
}
}
@ -1416,13 +1473,16 @@ namespace Blah
{
gl.BindVertexArray(mesh->gl_id());
GLenum index_format = mesh->gl_index_format();
int index_size = mesh->gl_index_size();
if (pass.instance_count > 0)
{
gl.DrawElementsInstanced(
GL_TRIANGLES,
(GLint)(pass.index_count),
GL_UNSIGNED_INT,
(void*)(sizeof(int) * pass.index_start),
index_format,
(void*)(index_size* pass.index_start),
(GLint)pass.instance_count);
}
else
@ -1430,8 +1490,8 @@ namespace Blah
gl.DrawElements(
GL_TRIANGLES,
(GLint)(pass.index_count),
GL_UNSIGNED_INT,
(void*)(sizeof(int) * pass.index_start));
index_format,
(void*)(index_size * pass.index_start));
}
gl.BindVertexArray(0);

View File

@ -113,5 +113,8 @@ namespace Blah
void* gl_context_create();
void gl_context_make_current(void* context);
void gl_context_destroy(void* context);
// D3D11 Methods
void* d3d11_get_hwnd();
}
}

View File

@ -10,6 +10,7 @@
#include <SDL.h>
#include <SDL_vulkan.h>
#include <SDL_syswm.h>
#if _WIN32
// on Windows we're using the C++ <filesystem> API for now
@ -75,7 +76,7 @@ bool PlatformBackend::init(const Config* config)
int flags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
// GL Attributes
// enable OpenGL
if (App::renderer() == Renderer::OpenGL)
{
flags |= SDL_WINDOW_OPENGL;
@ -93,6 +94,11 @@ bool PlatformBackend::init(const Config* config)
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
}
// enable DirectX
else if (App::renderer() == Renderer::D3D11)
{
}
// create the window
window = SDL_CreateWindow(config->name, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, config->width, config->height, flags);
@ -643,4 +649,12 @@ void PlatformBackend::gl_context_destroy(void* context)
SDL_GL_DeleteContext(context);
}
void* PlatformBackend::d3d11_get_hwnd()
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(window, &info);
return info.info.win.window;
}
#endif // BLAH_USE_SDL2

View File

@ -15,8 +15,10 @@ namespace Blah
int m_count;
public:
static inline constexpr size_t MaxCapacity = Capacity;
StackVector();
StackVector(const std::initializer_list<T>& init);
StackVector(const StackVector& src);
StackVector(StackVector&& src) noexcept;
~StackVector();
@ -59,6 +61,14 @@ namespace Blah
m_count = 0;
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::StackVector(const std::initializer_list<T>& init)
{
m_count = 0;
for (auto& it : init)
push_back(it);
}
template<class T, size_t Capacity>
inline StackVector<T, Capacity>::StackVector(const StackVector& src)
{

View File

@ -8,52 +8,121 @@
#include <blah/app.h>
using namespace Blah;
namespace
{
// TODO:
// This shader needs to be graphics API agnostic
// TODO:
// This shader needs to be graphics API agnostic
const ShaderData data = {
// vertex shader
"#version 330\n"
"uniform mat4 u_matrix;\n"
"layout(location=0) in vec2 a_position;\n"
"layout(location=1) in vec2 a_tex;\n"
"layout(location=2) in vec4 a_color;\n"
"layout(location=3) in vec3 a_type;\n"
"out vec2 v_tex;\n"
"out vec4 v_col;\n"
"out vec3 v_type;\n"
"void main(void)\n"
"{\n"
" gl_Position = u_matrix * vec4(a_position.xy, 0, 1);\n"
" v_tex = a_tex;\n"
" v_col = a_color;\n"
" v_type = a_type;\n"
"}",
#ifdef BLAH_USE_OPENGL
// fragment shader
"#version 330\n"
"uniform sampler2D u_texture;\n"
"in vec2 v_tex;\n"
"in vec4 v_col;\n"
"in vec3 v_type;\n"
"out vec4 o_color;\n"
"void main(void)\n"
"{\n"
" vec4 color = texture(u_texture, v_tex);\n"
" o_color = \n"
" v_type.x * color * v_col + \n"
" v_type.y * color.a * v_col + \n"
" v_type.z * v_col;\n"
"}"
};
const ShaderData shader_data = {
// vertex shader
"#version 330\n"
"uniform mat4 u_matrix;\n"
"layout(location=0) in vec2 a_position;\n"
"layout(location=1) in vec2 a_tex;\n"
"layout(location=2) in vec4 a_color;\n"
"layout(location=3) in vec4 a_type;\n"
"out vec2 v_tex;\n"
"out vec4 v_col;\n"
"out vec4 v_type;\n"
"void main(void)\n"
"{\n"
" gl_Position = u_matrix * vec4(a_position.xy, 0, 1);\n"
" v_tex = a_tex;\n"
" v_col = a_color;\n"
" v_type = a_type;\n"
"}",
const VertexAttribute attributes[4] = {
{ 0, VertexSemantics::Position, VertexAttributeType::Float, 2, false },
{ 1, VertexSemantics::Texcoord0, VertexAttributeType::Float, 2, false },
{ 2, VertexSemantics::Color0, VertexAttributeType::Byte, 4, true },
{ 3, VertexSemantics::Texcoord1, VertexAttributeType::Byte, 3, true },
};
// fragment shader
"#version 330\n"
"uniform sampler2D u_texture;\n"
"in vec2 v_tex;\n"
"in vec4 v_col;\n"
"in vec4 v_type;\n"
"out vec4 o_color;\n"
"void main(void)\n"
"{\n"
" vec4 color = texture(u_texture, v_tex);\n"
" o_color = \n"
" v_type.x * color * v_col + \n"
" v_type.y * color.a * v_col + \n"
" v_type.z * v_col;\n"
"}"
};
#elif BLAH_USE_D3D11
const char* d3d11_shader = ""
"cbuffer constants : register(b0)\n"
"{\n"
" row_major float4x4 u_matrix;\n"
"}\n"
"struct vs_in\n"
"{\n"
" float2 position : POS;\n"
" float2 texcoord : TEX;\n"
" float4 color : COL;\n"
" float4 mask : MASK;\n"
"};\n"
"struct vs_out\n"
"{\n"
" float4 position : SV_POSITION;\n"
" float2 texcoord : TEX;\n"
" float4 color : COL;\n"
" float4 mask : MASK;\n"
"};\n"
"Texture2D u_texture : register(t0);\n"
"SamplerState u_sampler : register(s0);\n"
"vs_out vs_main(vs_in input)\n"
"{\n"
" vs_out output;\n"
" output.position = mul(float4(input.position, 0.0f, 1.0f), u_matrix);\n"
" output.texcoord = input.texcoord;\n"
" output.color = input.color;\n"
" output.mask = input.mask;\n"
" return output;\n"
"}\n"
"float4 ps_main(vs_out input) : SV_TARGET\n"
"{\n"
" float4 color = u_texture.Sample(u_sampler, input.texcoord);\n"
" return\n"
" input.mask.x * color * input.color + \n"
" input.mask.y * color.a * input.color + \n"
" input.mask.z * input.color;\n"
"}\n";
const ShaderData shader_data = {
d3d11_shader,
d3d11_shader,
{
{ "POS", 0 },
{ "TEX", 0 },
{ "COL", 0 },
{ "MASK", 0 },
}
};
#else
const ShaderData shader_data;
#endif
const VertexFormat format = VertexFormat(
{
{ 0, VertexType::Float2, false },
{ 1, VertexType::Float2, false },
{ 2, VertexType::UByte4, true },
{ 3, VertexType::UByte4, true },
});
}
namespace
{
@ -84,13 +153,13 @@ namespace
#define PUSH_QUAD(px0, py0, px1, py1, px2, py2, px3, py3, tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3, col0, col1, col2, col3, mult, fill, wash) \
{ \
m_batch.elements += 2; \
int* _i = m_indices.expand(6); \
*_i++ = (int)m_vertices.size() + 0; \
*_i++ = (int)m_vertices.size() + 1; \
*_i++ = (int)m_vertices.size() + 2; \
*_i++ = (int)m_vertices.size() + 0; \
*_i++ = (int)m_vertices.size() + 2; \
*_i++ = (int)m_vertices.size() + 3; \
auto _i = m_indices.expand(6); \
*_i++ = (uint32_t)m_vertices.size() + 0; \
*_i++ = (uint32_t)m_vertices.size() + 1; \
*_i++ = (uint32_t)m_vertices.size() + 2; \
*_i++ = (uint32_t)m_vertices.size() + 0; \
*_i++ = (uint32_t)m_vertices.size() + 2; \
*_i++ = (uint32_t)m_vertices.size() + 3; \
Vertex* _v = m_vertices.expand(4); \
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
@ -101,10 +170,10 @@ namespace
#define PUSH_TRIANGLE(px0, py0, px1, py1, px2, py2, tx0, ty0, tx1, ty1, tx2, ty2, col0, col1, col2, mult, fill, wash) \
{ \
m_batch.elements += 1; \
int* _i = m_indices.expand(3); \
*_i++ = (int)m_vertices.size() + 0; \
*_i++ = (int)m_vertices.size() + 1; \
*_i++ = (int)m_vertices.size() + 2; \
auto* _i = m_indices.expand(3); \
*_i++ = (uint32_t)m_vertices.size() + 0; \
*_i++ = (uint32_t)m_vertices.size() + 1; \
*_i++ = (uint32_t)m_vertices.size() + 2; \
Vertex* _v = m_vertices.expand(3); \
MAKE_VERTEX(_v, m_matrix, px0, py0, tx0, ty0, col0, mult, fill, wash); _v++; \
MAKE_VERTEX(_v, m_matrix, px1, py1, tx1, ty1, col1, mult, fill, wash); _v++; \
@ -126,8 +195,6 @@ ShaderRef Batch::m_default_shader;
Batch::Batch()
{
matrix_uniform = "u_matrix";
texture_uniform = "u_texture";
clear();
}
@ -292,21 +359,18 @@ void Batch::render(const FrameBufferRef& target, const Mat4x4& matrix)
// define defaults
{
if (!m_mesh)
{
m_mesh = Mesh::create();
m_mesh->vertex_format(attributes, 4, sizeof(Vertex));
}
if (!m_default_shader)
m_default_shader = Shader::create(&data);
m_default_shader = Shader::create(&shader_data);
if (!m_default_material)
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());
m_mesh->index_data(IndexFormat::UInt32, m_indices.data(), m_indices.size());
m_mesh->vertex_data(format, m_vertices.data(), m_vertices.size());
RenderPass pass;
pass.target = target;
@ -330,7 +394,7 @@ void Batch::render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4
if (!pass.material)
pass.material = m_default_material;
pass.material->set_texture(texture_uniform, b.texture, 0);
pass.material->set_texture(0, b.texture, 0);
pass.material->set_value(matrix_uniform, &matrix.m11, 16);
pass.blend = b.blend;

View File

@ -45,9 +45,6 @@ namespace Blah
// The name of the Matrix Uniform in the Shader
const char* matrix_uniform;
// The name of the Texture Uniform in the Shader
const char* texture_uniform;
Batch();
Batch(const Batch& other) = delete;
Batch& operator=(const Batch& other) = delete;
@ -186,6 +183,7 @@ namespace Blah
uint8_t mult;
uint8_t wash;
uint8_t fill;
uint8_t pad;
};
struct DrawBatch
@ -217,7 +215,7 @@ namespace Blah
uint8_t m_tex_wash;
DrawBatch m_batch;
Vector<Vertex> m_vertices;
Vector<int> m_indices;
Vector<uint32_t> m_indices;
Vector<Mat3x2> m_matrix_stack;
Vector<Rect> m_scissor_stack;
Vector<BlendMode> m_blend_stack;

View File

@ -42,7 +42,6 @@ Material::Material(const ShaderRef& shader)
m_shader = shader;
auto& uniforms = shader->uniforms();
Vector<int> float_offsets;
int float_size = 0;
for (auto& uniform : uniforms)
@ -57,13 +56,10 @@ Material::Material(const ShaderRef& shader)
continue;
}
float_offsets.push_back(float_size);
float_size += calc_uniform_size(uniform);
}
m_data.expand(float_size);
for (auto& it : float_offsets)
m_floats.push_back(m_data.begin() + it);
}
const ShaderRef Material::shader() const
@ -75,29 +71,50 @@ void Material::set_texture(const char* name, const TextureRef& texture, int inde
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
if (m_textures.size() > 0)
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
int offset = 0;
for (auto& uniform : m_shader->uniforms())
if (uniform.type != UniformType::Texture)
continue;
if (strcmp(uniform.name, name) == 0)
{
if (uniform.type != UniformType::Texture)
continue;
if (strcmp(uniform.name, name) == 0)
{
m_textures[offset + index] = texture;
return;
}
offset += uniform.array_length;
if (offset + index >= m_textures.size())
break;
m_textures[offset + index] = texture;
return;
}
offset += uniform.array_length;
if (offset + index >= m_textures.size())
break;
}
Log::warn("No Texture Uniform '%s' at index [%i] exists", name, index);
}
void Material::set_texture(int slot, const TextureRef& texture, int index)
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
int s = 0;
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type == UniformType::Texture)
{
if (s == slot)
{
if (index > uniform.array_length)
break;
m_textures[offset + index] = texture;
break;
}
offset += uniform.array_length;
s++;
}
}
}
TextureRef Material::get_texture(const char* name, int index) const
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
@ -124,14 +141,19 @@ TextureRef Material::get_texture(int slot, int index) const
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
int offset = 0;
int s = 0;
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type == UniformType::Texture)
{
if (s == slot)
{
if (index > uniform.array_length)
break;
return m_textures[offset + index];
}
offset += uniform.array_length;
if (offset + index >= m_textures.size())
@ -151,6 +173,7 @@ void Material::set_value(const char* name, const float* value, int64_t length)
BLAH_ASSERT(length >= 0, "Length must be >= 0");
int index = 0;
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type == UniformType::Texture || uniform.type == UniformType::None)
@ -165,10 +188,11 @@ void Material::set_value(const char* name, const float* value, int64_t length)
length = max;
}
memcpy(m_floats[index], value, sizeof(float) * length);
memcpy(m_data.begin() + offset, value, sizeof(float) * length);
return;
}
offset += calc_uniform_size(uniform);
index++;
}
@ -180,6 +204,7 @@ const float* Material::get_value(const char* name, int64_t* length) const
BLAH_ASSERT(m_shader, "Material Shader is invalid");
int index = 0;
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type == UniformType::Texture || uniform.type == UniformType::None)
@ -189,10 +214,11 @@ const float* Material::get_value(const char* name, int64_t* length) const
{
if (length != nullptr)
*length = calc_uniform_size(uniform);
return m_floats[index];
return m_data.begin() + offset;
}
index++;
offset += calc_uniform_size(uniform);
}
*length = 0;
@ -200,29 +226,12 @@ const float* Material::get_value(const char* name, int64_t* length) const
Log::warn("No Uniform '%s' exists", name);
}
const float* Material::get_value(int slot, int64_t* length) const
const Vector<TextureRef>& Material::textures() const
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
return m_textures;
}
int index = 0;
int s = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type != UniformType::Texture && uniform.type != UniformType::None)
{
if (index == slot)
{
if (length != nullptr)
*length = calc_uniform_size(uniform);
return m_floats[index];
}
index++;
}
s++;
}
Log::warn("No Uniform [%i] exists", slot);
*length = 0;
return nullptr;
}
const float* Material::data() const
{
return m_data.begin();
}

View File

@ -31,38 +31,33 @@ namespace Blah
// Returns the Shader assigned to the Material.
const ShaderRef shader() const;
// Sets the texture. If the index is out of bounds, the Material is not valid, the Uniform
// is not a Texture Uniform, or the Uniform does not exist, this will do nothing.
void set_texture(const char* name, const TextureRef& texture, int index = 0);
// Sets the texture
void set_texture(const char* name, const TextureRef& texture, int array_index = 0);
// Gets the texture.
// If the Uniform does not exist, or the index is out of bounds, this will return
// an invalid Texture reference.
TextureRef get_texture(const char* name, int index = 0) const;
// Sets the texture
void set_texture(int slot, const TextureRef& texture, int array_index = 0);
// Gets the texture from the given slot.
// If the slot is not a Texture Uniform, or the index is out of bounds, this will return
// an invalid Texture reference.
TextureRef get_texture(int slot, int index = 0) const;
// Gets the texture, or an empty reference if invalid
TextureRef get_texture(const char* name, int array_index = 0) const;
// Sets the value. Length is the total amount of values to set. For example, if the Uniform type
// is a float2, and there are 4 elements, the maximum length should be 8.
// Gets the texture, or an empty reference if invalid
TextureRef get_texture(int slot, int array_index = 0) const;
// Sets the value. `length` is the total number of floats to set
void set_value(const char* name, const float* value, int64_t length);
// Gets a pointer to the values of the given Uniform, or nullptr if it doesn't exist.
// Length is the total amount of values. For example, if the Uniform type
// is a float2, and there are 4 elements, the length should be 8.
const float* get_value(const char* name, int64_t* length = nullptr) const;
// Gets a pointer to the values of the given Uniform, or nullptr if it doesn't exist.
// Length is the total amount of values. For example, if the Uniform type
// is a float2, and there are 4 elements, the length should be 8.
const float* get_value(int slot, int64_t* length = nullptr) const;
// Returns the internal Texture buffer
const Vector<TextureRef>& textures() const;
// Returns the interal float buffer of all the values
const float* data() const;
private:
ShaderRef m_shader;
Vector<TextureRef> m_textures;
Vector<float*> m_floats;
Vector<float> m_data;
};
}

View File

@ -3,55 +3,38 @@
using namespace Blah;
MeshRef Mesh::create()
{
return GraphicsBackend::create_mesh();
}
void Mesh::vertex_format(const VertexAttribute* attributes, int attribute_count, int stride)
VertexFormat::VertexFormat(std::initializer_list<VertexAttribute> attributes, int stride)
{
if (stride < 0)
for (auto& it : attributes)
this->attributes.push_back(it);
if (stride <= 0)
{
stride = 0;
for (int n = 0; n < attribute_count; n++)
for (auto& it : attributes)
{
const VertexAttribute* attrib = (attributes + n);
if (attrib->type == VertexAttributeType::Byte)
stride += attrib->components * 1;
else if (attrib->type == VertexAttributeType::Short)
stride += attrib->components * 2;
else if (attrib->type == VertexAttributeType::Int)
stride += attrib->components * 4;
else if (attrib->type == VertexAttributeType::Float)
stride += attrib->components * 4;
switch (it.type)
{
case VertexType::Float: stride += 4; break;
case VertexType::Float2: stride += 8; break;
case VertexType::Float3: stride += 12; break;
case VertexType::Float4: stride += 16; break;
case VertexType::Byte4: stride += 4; break;
case VertexType::UByte4: stride += 4; break;
case VertexType::Short2: stride += 4; break;
case VertexType::UShort2: stride += 4; break;
case VertexType::Short4: stride += 8; break;
case VertexType::UShort4: stride += 8; break;
}
}
}
vertex_format_internal(attributes, attribute_count, stride);
}
void Mesh::instance_format(const VertexAttribute* attributes, int attribute_count, int stride)
{
if (stride < 0)
{
stride = 0;
for (int n = 0; n < attribute_count; n++)
{
const VertexAttribute* attrib = (attributes + n);
if (attrib->type == VertexAttributeType::Byte)
stride += attrib->components * 1;
else if (attrib->type == VertexAttributeType::Short)
stride += attrib->components * 2;
else if (attrib->type == VertexAttributeType::Int)
stride += attrib->components * 4;
else if (attrib->type == VertexAttributeType::Float)
stride += attrib->components * 4;
}
}
instance_format_internal(attributes, attribute_count, stride);
}
this->stride = stride;
}

View File

@ -1,47 +1,53 @@
#pragma once
#include <inttypes.h>
#include <memory>
#include <blah/containers/stackvector.h>
namespace Blah
{
enum class VertexSemantics
enum class VertexType
{
None,
Position,
Normal,
Bitangent,
Color0,
Color1,
Color2,
Color3,
Indices,
Weight,
Texcoord0,
Texcoord1,
Texcoord2,
Texcoord3,
Texcoord4,
Texcoord5,
Texcoord6,
Texcoord7
};
enum class VertexAttributeType
{
None,
Byte,
Short,
Int,
Float
Float,
Float2,
Float3,
Float4,
Byte4,
UByte4,
Short2,
UShort2,
Short4,
UShort4
};
struct VertexAttribute
{
int index;
VertexSemantics semantics;
VertexAttributeType type;
int components;
bool normalized;
// Location / Attribute Index
int index = 0;
// Vertex Type
VertexType type = VertexType::None;
// Whether the Vertex should be normalized (doesn't apply to Floats)
bool normalized = false;
};
struct VertexFormat
{
// List of Attributes
StackVector<VertexAttribute, 16> attributes;
// Total size in bytes of each Vertex element
int stride = 0;
VertexFormat() = default;
VertexFormat(std::initializer_list<VertexAttribute> attributes, int stride = 0);
};
enum class IndexFormat
{
UInt16,
UInt32
};
class Mesh;
@ -66,22 +72,14 @@ namespace Blah
// If the Mesh creation fails, it will return an invalid Mesh.
static MeshRef create();
// Sets the Vertex Format of the Mesh
void vertex_format(const VertexAttribute* attributes, int attribute_count, int stride = -1);
// Sets the Instance Format of the Mesh
void instance_format(const VertexAttribute* attributes, int attribute_count, int stride = -1);
// Uploads the given index buffer to the Mesh
virtual void index_data(const void* indices, int64_t count) = 0;
virtual void index_data(IndexFormat format, const void* indices, int64_t count) = 0;
// Uploads the given vertex buffer to the Mesh
// Note you must call vertex_format at least once before uploading vertices.
virtual void vertex_data(const void* vertices, int64_t count) = 0;
virtual void vertex_data(const VertexFormat& format, const void* vertices, int64_t count) = 0;
// Uploads the given instance buffer to the Mesh
// Note you must call instance_format at least once before uploading instances.
virtual void instance_data(const void* instances, int64_t count) = 0;
virtual void instance_data(const VertexFormat& format, const void* instances, int64_t count) = 0;
// Gets the index count of the Mesh
virtual int64_t index_count() const = 0;
@ -91,9 +89,5 @@ namespace Blah
// Gets the instance count of the Mesh
virtual int64_t instance_count() const = 0;
protected:
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;
};
}

View File

@ -5,6 +5,7 @@
namespace Blah
{
// Supported Uniform Types
enum class UniformType
{
None,
@ -17,17 +18,54 @@ namespace Blah
Texture
};
// Supported Shader Types
enum class ShaderType
{
None = 0,
Vertex = 1 << 0,
Fragment = 1 << 1
};
// Uniform Info, provided by the Shader
struct UniformInfo
{
// Name of the Uniform
String name;
// The Value type of the Uniform
UniformType type;
// The Shader type the Uniform is a part of
ShaderType shader;
// Some rendering APIs have uniform buffers. The `buffer_index`
// specifies which buffer the uniform belongs to
int buffer_index;
// Array length of the Uniform (ex. a vec2[4] would be 4)
int array_length;
};
// Data to be passed to the shader to construct it
struct ShaderData
{
struct HLSL_Attribute
{
// Semantic Name
const char* semantic_name = nullptr;
// (optional) Semantic Index
int semantic_index = 0;
};
// Vertex Shader Program data
const char* vertex;
// Fragment Shader Program data
const char* fragment;
// HLSL Attributes - required for D3D11
StackVector<HLSL_Attribute, 16> hlsl_attributes;
};
class Shader;

View File

@ -9,14 +9,16 @@ 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);
if (tex)
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);
if (tex)
tex->set_data(rgba);
return tex;
}
@ -35,10 +37,11 @@ TextureRef Texture::create(Stream& stream)
{
Image img = Image(stream);
if (img.pixels != nullptr && img.width > 0 && img.height > 0)
if (img.pixels && img.width > 0 && img.height > 0)
{
auto tex = create(img.width, img.height, TextureFormat::RGBA);
tex->set_data((unsigned char*)img.pixels);
if (tex)
tex->set_data((unsigned char*)img.pixels);
return tex;
}
@ -49,10 +52,11 @@ TextureRef Texture::create(const char* file)
{
Image img = Image(file);
if (img.pixels != nullptr)
if (img.pixels)
{
auto tex = create(img.width, img.height, TextureFormat::RGBA);
tex->set_data((unsigned char*)img.pixels);
if (tex)
tex->set_data((unsigned char*)img.pixels);
return tex;
}

View File

@ -22,7 +22,6 @@ namespace Blah
None,
R,
RG,
RGB,
RGBA,
DepthStencil,
Count