separated Textures from Samplers, to accommodate HLSL etc

This commit is contained in:
Noel Berry 2020-12-30 14:03:50 -08:00
parent e88030101b
commit d4ff3f66ca
14 changed files with 343 additions and 206 deletions

View File

@ -27,6 +27,7 @@ add_library(blah
public/blah/graphics/mesh.cpp public/blah/graphics/mesh.cpp
public/blah/graphics/renderpass.h public/blah/graphics/renderpass.h
public/blah/graphics/renderpass.cpp public/blah/graphics/renderpass.cpp
public/blah/graphics/sampler.h
public/blah/graphics/shader.h public/blah/graphics/shader.h
public/blah/graphics/shader.cpp public/blah/graphics/shader.cpp
public/blah/graphics/texture.h public/blah/graphics/texture.h

View File

@ -43,11 +43,11 @@ namespace Blah
// Creates a new Texture. // Creates a new Texture.
// if the Texture is invalid, this should return an empty reference. // if the Texture is invalid, this should return an empty reference.
TextureRef create_texture(int width, int height, TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y, TextureFormat format); TextureRef create_texture(int width, int height, TextureFormat format);
// Creates a new FrameBuffer. // Creates a new FrameBuffer.
// if the FrameBuffer is invalid, this should return an empty reference. // if the FrameBuffer is invalid, this should return an empty reference.
FrameBufferRef create_framebuffer(int width, int height, const TextureFormat* attachments, int attachmentCount); FrameBufferRef create_framebuffer(int width, int height, const TextureFormat* attachments, int attachment_count);
// Creates a new Shader. // Creates a new Shader.
// if the Shader is invalid, this should return an empty reference. // if the Shader is invalid, this should return an empty reference.

View File

@ -58,9 +58,7 @@ namespace Blah
struct StoredSampler struct StoredSampler
{ {
TextureFilter filter; TextureSampler sampler;
TextureWrap wrap_x;
TextureWrap wrap_y;
ID3D11SamplerState* state; ID3D11SamplerState* state;
}; };
@ -79,7 +77,7 @@ namespace Blah
ID3D11InputLayout* get_layout(D3D11_Shader* shader, const VertexFormat& format); ID3D11InputLayout* get_layout(D3D11_Shader* shader, const VertexFormat& format);
ID3D11BlendState* get_blend(const BlendMode& blend); ID3D11BlendState* get_blend(const BlendMode& blend);
ID3D11RasterizerState* get_rasterizer(const RenderPass& pass); ID3D11RasterizerState* get_rasterizer(const RenderPass& pass);
ID3D11SamplerState* get_sampler(const TextureRef& texture); ID3D11SamplerState* get_sampler(const TextureSampler& sampler);
ID3D11DepthStencilState* get_depthstencil(const RenderPass& pass); ID3D11DepthStencilState* get_depthstencil(const RenderPass& pass);
}; };
@ -140,15 +138,23 @@ namespace Blah
D3D11_SHADER_INPUT_BIND_DESC desc; D3D11_SHADER_INPUT_BIND_DESC desc;
reflector->GetResourceBindingDesc(i, &desc); reflector->GetResourceBindingDesc(i, &desc);
if (desc.Type == D3D_SIT_TEXTURE && if (desc.Type == D3D_SIT_TEXTURE && desc.Dimension == D3D_SRV_DIMENSION_TEXTURE2D)
desc.Dimension == D3D_SRV_DIMENSION_TEXTURE2D)
{ {
auto uniform = append_to.expand(); auto uniform = append_to.expand();
uniform->name = desc.Name; uniform->name = desc.Name;
uniform->shader = shader_type; uniform->shader = shader_type;
uniform->buffer_index = 0; uniform->buffer_index = 0;
uniform->array_length = max(1, desc.BindCount); uniform->array_length = max(1, desc.BindCount);
uniform->type = UniformType::Texture; uniform->type = UniformType::Texture2D;
}
else if (desc.Type == D3D_SIT_SAMPLER)
{
auto uniform = append_to.expand();
uniform->name = desc.Name;
uniform->shader = shader_type;
uniform->buffer_index = 0;
uniform->array_length = max(1, desc.BindCount);
uniform->type = UniformType::Sampler2D;
} }
} }
@ -224,10 +230,7 @@ namespace Blah
private: private:
int m_width; int m_width;
int m_height; int m_height;
TextureFilter m_filter;
TextureFormat m_format; TextureFormat m_format;
TextureWrap m_wrap_x;
TextureWrap m_wrap_y;
bool m_is_framebuffer; bool m_is_framebuffer;
int m_size; int m_size;
@ -235,14 +238,11 @@ namespace Blah
ID3D11Texture2D* texture = nullptr; ID3D11Texture2D* texture = nullptr;
ID3D11ShaderResourceView* view = nullptr; ID3D11ShaderResourceView* view = nullptr;
D3D11_Texture(int width, int height, TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y, TextureFormat format, bool is_framebuffer) D3D11_Texture(int width, int height, TextureFormat format, bool is_framebuffer)
{ {
m_width = width; m_width = width;
m_height = height; m_height = height;
m_filter = filter;
m_format = format; m_format = format;
m_wrap_x = wrap_x;
m_wrap_y = wrap_y;
m_is_framebuffer = is_framebuffer; m_is_framebuffer = is_framebuffer;
m_size = 0; m_size = 0;
@ -320,32 +320,6 @@ namespace Blah
return m_format; return m_format;
} }
virtual void set_filter(TextureFilter filter) override
{
m_filter = filter;
}
virtual TextureFilter get_filter() const override
{
return m_filter;
}
virtual void set_wrap(TextureWrap x, TextureWrap y) override
{
m_wrap_x = x;
m_wrap_y = y;
}
virtual TextureWrap get_wrap_x() const override
{
return m_wrap_x;
}
virtual TextureWrap get_wrap_y() const override
{
return m_wrap_y;
}
virtual void set_data(unsigned char* data) override virtual void set_data(unsigned char* data) override
{ {
D3D11_BOX box; D3D11_BOX box;
@ -386,17 +360,12 @@ namespace Blah
StackVector<ID3D11RenderTargetView*, Attachments::MaxCapacity - 1> color_views; StackVector<ID3D11RenderTargetView*, Attachments::MaxCapacity - 1> color_views;
ID3D11DepthStencilView* depth_view = nullptr; ID3D11DepthStencilView* depth_view = nullptr;
D3D11_FrameBuffer(int width, int height, const TextureFormat* attachments, int attachmentCount) D3D11_FrameBuffer(int width, int height, const TextureFormat* attachments, int attachment_count)
{ {
for (int i = 0; i < attachmentCount; i++) for (int i = 0; i < attachment_count; i++)
{ {
auto tex = new D3D11_Texture( auto tex = new D3D11_Texture(width, height, attachments[i], true);
width, height,
TextureFilter::Linear,
TextureWrap::Repeat,
TextureWrap::Repeat,
attachments[i],
true);
m_attachments.push_back(TextureRef(tex)); m_attachments.push_back(TextureRef(tex));
if (attachments[i] == TextureFormat::DepthStencil) if (attachments[i] == TextureFormat::DepthStencil)
@ -891,9 +860,9 @@ namespace Blah
state.swap_chain->Present(1, 0); state.swap_chain->Present(1, 0);
} }
TextureRef GraphicsBackend::create_texture(int width, int height, TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y, TextureFormat format) TextureRef GraphicsBackend::create_texture(int width, int height, TextureFormat format)
{ {
auto result = new D3D11_Texture(width, height, filter, wrap_x, wrap_y, format, false); auto result = new D3D11_Texture(width, height, format, false);
if (result->texture) if (result->texture)
return TextureRef(result); return TextureRef(result);
@ -901,9 +870,9 @@ namespace Blah
return TextureRef(); return TextureRef();
} }
FrameBufferRef GraphicsBackend::create_framebuffer(int width, int height, const TextureFormat* attachments, int attachmentCount) FrameBufferRef GraphicsBackend::create_framebuffer(int width, int height, const TextureFormat* attachments, int attachment_count)
{ {
return FrameBufferRef(new D3D11_FrameBuffer(width, height, attachments, attachmentCount)); return FrameBufferRef(new D3D11_FrameBuffer(width, height, attachments, attachment_count));
} }
ShaderRef GraphicsBackend::create_shader(const ShaderData* data) ShaderRef GraphicsBackend::create_shader(const ShaderData* data)
@ -936,7 +905,9 @@ namespace Blah
const float* data = material->data(); const float* data = material->data();
for (auto& it : shader->uniforms()) for (auto& it : shader->uniforms())
{ {
if (it.type == UniformType::Texture) if (it.type == UniformType::None ||
it.type == UniformType::Texture2D ||
it.type == UniformType::Sampler2D)
continue; continue;
int size = 0; int size = 0;
@ -1071,7 +1042,7 @@ namespace Blah
ctx->PSSetShader(shader->fragment, nullptr, 0); ctx->PSSetShader(shader->fragment, nullptr, 0);
ctx->PSSetConstantBuffers(0, shader->fcb.size(), shader->fcb.begin()); ctx->PSSetConstantBuffers(0, shader->fcb.size(), shader->fcb.begin());
// Fragment Shader Textures & Samplers // Fragment Shader Textures
auto& textures = pass.material->textures(); auto& textures = pass.material->textures();
for (int i = 0; i < textures.size(); i++) for (int i = 0; i < textures.size(); i++)
{ {
@ -1080,23 +1051,17 @@ namespace Blah
// Assign the Texture // Assign the Texture
auto view = ((D3D11_Texture*)textures[i].get())->view; auto view = ((D3D11_Texture*)textures[i].get())->view;
ctx->PSSetShaderResources(i, 1, &view); ctx->PSSetShaderResources(i, 1, &view);
// Assign the Sampler
// TODO:
// This is incorrect! Textures and Samplers are separate in HLSL.
// For now, assuming there's 1 Sampler Per Texture, and we set it to
// the properties of the texture at the same index.
// I think most modern APIs separate these, where as OpenGL makes
// them the same (afaik). Either we need to separate these in our
// API, or find some work around here.
auto sampler = state.get_sampler(textures[i]);
if (sampler)
ctx->PSSetSamplers(i, 1, &sampler);
} }
} }
// Fragment Shader Samplers
auto& samplers = pass.material->samplers();
for (int i = 0; i < samplers.size(); i++)
{
auto sampler = state.get_sampler(samplers[i]);
if (sampler)
ctx->PSSetSamplers(i, 1, &sampler);
}
} }
// RS // RS
@ -1294,14 +1259,10 @@ namespace Blah
return nullptr; return nullptr;
} }
ID3D11SamplerState* D3D11::get_sampler(const TextureRef& texture) ID3D11SamplerState* D3D11::get_sampler(const TextureSampler& sampler)
{ {
auto filter = texture->get_filter();
auto wrap_x = texture->get_wrap_x();
auto wrap_y = texture->get_wrap_y();
for (auto& it : sampler_cache) for (auto& it : sampler_cache)
if (it.filter == filter && it.wrap_x == wrap_x && it.wrap_y == wrap_y) if (it.sampler == sampler)
return it.state; return it.state;
D3D11_SAMPLER_DESC desc = {}; D3D11_SAMPLER_DESC desc = {};
@ -1311,19 +1272,19 @@ namespace Blah
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
desc.ComparisonFunc = D3D11_COMPARISON_NEVER; desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
switch (filter) switch (sampler.filter)
{ {
case TextureFilter::Nearest: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; break; case TextureFilter::Nearest: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; break;
case TextureFilter::Linear: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; break; case TextureFilter::Linear: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; break;
} }
switch (wrap_x) switch (sampler.wrap_x)
{ {
case TextureWrap::Clamp: desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; break; case TextureWrap::Clamp: desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; break;
case TextureWrap::Repeat: desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; break; case TextureWrap::Repeat: desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; break;
} }
switch (wrap_y) switch (sampler.wrap_y)
{ {
case TextureWrap::Clamp: desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; break; case TextureWrap::Clamp: desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; break;
case TextureWrap::Repeat: desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; break; case TextureWrap::Repeat: desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; break;
@ -1335,9 +1296,7 @@ namespace Blah
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
auto entry = sampler_cache.expand(); auto entry = sampler_cache.expand();
entry->filter = filter; entry->sampler = sampler;
entry->wrap_x = wrap_x;
entry->wrap_y = wrap_y;
entry->state = result; entry->state = result;
return result; return result;
} }

View File

@ -545,9 +545,7 @@ namespace Blah
GLuint m_id; GLuint m_id;
int m_width; int m_width;
int m_height; int m_height;
TextureWrap m_wrap_x; TextureSampler m_sampler;
TextureWrap m_wrap_y;
TextureFilter m_filter;
TextureFormat m_format; TextureFormat m_format;
GLenum m_gl_internal_format; GLenum m_gl_internal_format;
GLenum m_gl_format; GLenum m_gl_format;
@ -556,14 +554,12 @@ namespace Blah
public: public:
bool framebuffer_parent; bool framebuffer_parent;
OpenGL_Texture(int width, int height, TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y, TextureFormat format) OpenGL_Texture(int width, int height, TextureFormat format)
{ {
m_id = 0; m_id = 0;
m_width = width; m_width = width;
m_height = height; m_height = height;
m_wrap_x = wrap_x; m_sampler = TextureSampler(TextureFilter::None, TextureWrap::None, TextureWrap::None);
m_wrap_y = wrap_y;
m_filter = filter;
m_format = format; m_format = format;
framebuffer_parent = false; framebuffer_parent = false;
m_gl_internal_format = GL_RED; m_gl_internal_format = GL_RED;
@ -609,12 +605,7 @@ namespace Blah
gl.GenTextures(1, &m_id); gl.GenTextures(1, &m_id);
gl.ActiveTexture(GL_TEXTURE0); gl.ActiveTexture(GL_TEXTURE0);
gl.BindTexture(GL_TEXTURE_2D, m_id); gl.BindTexture(GL_TEXTURE_2D, m_id);
gl.TexImage2D(GL_TEXTURE_2D, 0, m_gl_internal_format, width, height, 0, m_gl_format, m_gl_type, nullptr); gl.TexImage2D(GL_TEXTURE_2D, 0, m_gl_internal_format, width, height, 0, m_gl_format, m_gl_type, nullptr);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (m_filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (m_filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (m_wrap_x == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (m_wrap_y == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
} }
~OpenGL_Texture() ~OpenGL_Texture()
@ -643,38 +634,18 @@ namespace Blah
return m_format; return m_format;
} }
virtual void set_filter(TextureFilter filter) override void update_sampler(const TextureSampler& sampler)
{ {
m_filter = filter; if (m_sampler != sampler)
{
m_sampler = sampler;
gl.BindTexture(GL_TEXTURE_2D, m_id); gl.BindTexture(GL_TEXTURE_2D, m_id);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR)); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (m_sampler.filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR)); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (m_sampler.filter == TextureFilter::Nearest ? GL_NEAREST : GL_LINEAR));
} gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (m_sampler.wrap_x == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (m_sampler.wrap_y == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
virtual TextureFilter get_filter() const override }
{
return m_filter;
}
virtual void set_wrap(TextureWrap x, TextureWrap y) override
{
m_wrap_x = x;
m_wrap_y = y;
gl.BindTexture(GL_TEXTURE_2D, m_id);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (x == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (y == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
}
virtual TextureWrap get_wrap_x() const override
{
return m_wrap_x;
}
virtual TextureWrap get_wrap_y() const override
{
return m_wrap_y;
} }
virtual void set_data(unsigned char* data) override virtual void set_data(unsigned char* data) override
@ -899,20 +870,34 @@ 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_SAMPLER_2D) if (type == GL_SAMPLER_2D)
{ {
uniform.type = UniformType::Texture; UniformInfo tex_uniform;
uniform.shader = ShaderType::Fragment; tex_uniform.name = name;
tex_uniform.buffer_index = 0;
tex_uniform.array_length = size;
tex_uniform.type = UniformType::Texture2D;
tex_uniform.shader = ShaderType::Fragment;
uniform_locations.push_back(gl.GetUniformLocation(id, name));
m_uniforms.push_back(tex_uniform);
UniformInfo sampler_uniform;
sampler_uniform.name = String(name).append("_sampler");
sampler_uniform.buffer_index = 0;
sampler_uniform.array_length = size;
sampler_uniform.type = UniformType::Sampler2D;
sampler_uniform.shader = ShaderType::Fragment;
uniform_locations.push_back(gl.GetUniformLocation(id, name));
m_uniforms.push_back(sampler_uniform);
} }
else else
{ {
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));
uniform.shader = (ShaderType)((int)ShaderType::Vertex | (int)ShaderType::Fragment); uniform.shader = (ShaderType)((int)ShaderType::Vertex | (int)ShaderType::Fragment);
if (type == GL_FLOAT) if (type == GL_FLOAT)
@ -933,9 +918,10 @@ namespace Blah
Log::error("Unsupported Uniform Type"); Log::error("Unsupported Uniform Type");
break; break;
} }
m_uniforms.push_back(uniform);
} }
m_uniforms.push_back(uniform);
} }
} }
@ -1192,9 +1178,9 @@ namespace Blah
void GraphicsBackend::before_render() {} void GraphicsBackend::before_render() {}
void GraphicsBackend::after_render() {} void GraphicsBackend::after_render() {}
TextureRef GraphicsBackend::create_texture(int width, int height, TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y, TextureFormat format) TextureRef GraphicsBackend::create_texture(int width, int height, TextureFormat format)
{ {
auto resource = new OpenGL_Texture(width, height, filter, wrap_x, wrap_y, format); auto resource = new OpenGL_Texture(width, height, format);
if (resource->gl_id() <= 0) if (resource->gl_id() <= 0)
{ {
@ -1272,10 +1258,9 @@ namespace Blah
{ {
gl.UseProgram(shader->gl_id()); gl.UseProgram(shader->gl_id());
// upload uniform values
int texture_slot = 0; int texture_slot = 0;
int gl_texture_slot = 0;
GLint texture_ids[64]; GLint texture_ids[64];
auto& uniforms = shader->uniforms(); auto& uniforms = shader->uniforms();
auto data = pass.material->data(); auto data = pass.material->data();
@ -1284,14 +1269,19 @@ namespace Blah
auto location = shader->uniform_locations[i]; auto location = shader->uniform_locations[i];
auto& uniform = uniforms[i]; auto& uniform = uniforms[i];
// Sampler 2D // Sampler 2D's are assigned by updating texture values
if (uniform.type == UniformType::Texture) if (uniform.type == UniformType::Sampler2D)
continue;
// Texture2D
if (uniform.type == UniformType::Texture2D)
{ {
for (int n = 0; n < uniform.array_length; n++) for (int n = 0; n < uniform.array_length; n++)
{ {
auto tex = pass.material->get_texture(i, n); auto tex = pass.material->get_texture(texture_slot, n);
auto sampler = pass.material->get_sampler(texture_slot, n);
gl.ActiveTexture(GL_TEXTURE0 + texture_slot); gl.ActiveTexture(GL_TEXTURE0 + gl_texture_slot);
if (!tex) if (!tex)
{ {
@ -1299,14 +1289,17 @@ namespace Blah
} }
else else
{ {
gl.BindTexture(GL_TEXTURE_2D, ((OpenGL_Texture*)tex.get())->gl_id()); auto gl_tex = ((OpenGL_Texture*)tex.get());
gl_tex->update_sampler(sampler);
gl.BindTexture(GL_TEXTURE_2D, gl_tex->gl_id());
} }
texture_ids[n] = texture_slot; texture_ids[n] = gl_texture_slot;
texture_slot++; gl_texture_slot++;
} }
gl.Uniform1iv(location, (GLint)uniform.array_length, &texture_ids[0]); gl.Uniform1iv(location, (GLint)uniform.array_length, &texture_ids[0]);
texture_slot++;
continue; continue;
} }

View File

@ -19,6 +19,7 @@
#include <blah/graphics/material.h> #include <blah/graphics/material.h>
#include <blah/graphics/mesh.h> #include <blah/graphics/mesh.h>
#include <blah/graphics/renderpass.h> #include <blah/graphics/renderpass.h>
#include <blah/graphics/sampler.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>

View File

@ -339,6 +339,18 @@ void Batch::set_texture(const TextureRef& texture)
} }
} }
void Batch::set_sampler(const TextureSampler& sampler)
{
if (m_batch.elements > 0 && sampler != m_batch.sampler)
{
m_batches.push_back(m_batch);
m_batch.offset += m_batch.elements;
m_batch.elements = 0;
}
m_batch.sampler = sampler;
}
void Batch::render(const FrameBufferRef& target) void Batch::render(const FrameBufferRef& target)
{ {
Point size; Point size;
@ -394,7 +406,8 @@ void Batch::render_single_batch(RenderPass& pass, const DrawBatch& b, const Mat4
if (!pass.material) if (!pass.material)
pass.material = m_default_material; pass.material = m_default_material;
pass.material->set_texture(0, b.texture, 0); pass.material->set_texture(0, b.texture);
pass.material->set_sampler(0, b.sampler);
pass.material->set_value(matrix_uniform, &matrix.m11, 16); pass.material->set_value(matrix_uniform, &matrix.m11, 16);
pass.blend = b.blend; pass.blend = b.blend;
@ -422,6 +435,7 @@ void Batch::clear()
m_batch.blend = BlendMode::Normal; m_batch.blend = BlendMode::Normal;
m_batch.material.reset(); m_batch.material.reset();
m_batch.texture.reset(); m_batch.texture.reset();
m_batch.sampler = default_sampler;
m_batch.scissor.w = m_batch.scissor.h = -1; m_batch.scissor.w = m_batch.scissor.h = -1;
m_batch.flip_vertically = false; m_batch.flip_vertically = false;

View File

@ -9,6 +9,7 @@
#include <blah/drawing/spritefont.h> #include <blah/drawing/spritefont.h>
#include <blah/containers/vector.h> #include <blah/containers/vector.h>
#include <blah/graphics/blend.h> #include <blah/graphics/blend.h>
#include <blah/graphics/sampler.h>
#include <blah/graphics/renderpass.h> #include <blah/graphics/renderpass.h>
#include <blah/app.h> #include <blah/app.h>
@ -45,6 +46,9 @@ namespace Blah
// The name of the Matrix Uniform in the Shader // The name of the Matrix Uniform in the Shader
const char* matrix_uniform; const char* matrix_uniform;
// Default Sampler, set on clear
TextureSampler default_sampler;
Batch(); Batch();
Batch(const Batch& other) = delete; Batch(const Batch& other) = delete;
Batch& operator=(const Batch& other) = delete; Batch& operator=(const Batch& other) = delete;
@ -112,6 +116,9 @@ namespace Blah
// this (ex the `str` and `tex` methods) // this (ex the `str` and `tex` methods)
void set_texture(const TextureRef& texture); void set_texture(const TextureRef& texture);
// Sets the current texture sampler for drawing.
void set_sampler(const TextureSampler& sampler);
// Draws the batch to the given target // Draws the batch to the given target
void render(const FrameBufferRef& target = App::backbuffer); void render(const FrameBufferRef& target = App::backbuffer);
@ -194,6 +201,7 @@ namespace Blah
MaterialRef material; MaterialRef material;
BlendMode blend; BlendMode blend;
TextureRef texture; TextureRef texture;
TextureSampler sampler;
bool flip_vertically; bool flip_vertically;
Rect scissor; Rect scissor;

View File

@ -89,7 +89,7 @@ namespace Blah
rgba = blendColor; rgba = blendColor;
} }
inline bool operator==(const BlendMode& rhs) const bool operator==(const BlendMode& rhs) const
{ {
return return
color_op == rhs.color_op && color_src == rhs.color_src && color_dst == rhs.color_dst && color_op == rhs.color_op && color_src == rhs.color_src && color_dst == rhs.color_dst &&
@ -97,7 +97,7 @@ namespace Blah
mask == rhs.mask && rgba == rhs.rgba; mask == rhs.mask && rgba == rhs.rgba;
} }
inline bool operator!=(const BlendMode& rhs) const bool operator!=(const BlendMode& rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }

View File

@ -49,13 +49,20 @@ Material::Material(const ShaderRef& shader)
if (uniform.type == UniformType::None) if (uniform.type == UniformType::None)
continue; continue;
if (uniform.type == UniformType::Texture) if (uniform.type == UniformType::Texture2D)
{ {
for (int i = 0; i < uniform.array_length; i ++) for (int i = 0; i < uniform.array_length; i ++)
m_textures.push_back(TextureRef()); m_textures.push_back(TextureRef());
continue; continue;
} }
if (uniform.type == UniformType::Sampler2D)
{
for (int i = 0; i < uniform.array_length; i++)
m_samplers.push_back(TextureSampler());
continue;
}
float_size += calc_uniform_size(uniform); float_size += calc_uniform_size(uniform);
} }
@ -74,7 +81,7 @@ void Material::set_texture(const char* name, const TextureRef& texture, int inde
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
{ {
if (uniform.type != UniformType::Texture) if (uniform.type != UniformType::Texture2D)
continue; continue;
if (strcmp(uniform.name, name) == 0) if (strcmp(uniform.name, name) == 0)
@ -99,19 +106,20 @@ void Material::set_texture(int slot, const TextureRef& texture, int index)
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
{ {
if (uniform.type == UniformType::Texture) if (uniform.type != UniformType::Texture2D)
{ continue;
if (s == slot)
{
if (index > uniform.array_length)
break;
m_textures[offset + index] = texture; if (s == slot)
{
if (index > uniform.array_length)
break; break;
}
offset += uniform.array_length; m_textures[offset + index] = texture;
s++; break;
} }
offset += uniform.array_length;
s++;
} }
} }
@ -122,7 +130,7 @@ TextureRef Material::get_texture(const char* name, int index) const
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
{ {
if (uniform.type != UniformType::Texture) if (uniform.type != UniformType::Texture2D)
continue; continue;
if (strcmp(uniform.name, name) == 0) if (strcmp(uniform.name, name) == 0)
@ -145,21 +153,21 @@ TextureRef Material::get_texture(int slot, int index) const
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
{ {
if (uniform.type == UniformType::Texture) if (uniform.type != UniformType::Texture2D)
continue;
if (s == slot)
{ {
if (s == slot) if (index > uniform.array_length)
{
if (index > uniform.array_length)
break;
return m_textures[offset + index];
}
offset += uniform.array_length;
if (offset + index >= m_textures.size())
break; break;
return m_textures[offset + index];
} }
offset += uniform.array_length;
if (offset + index >= m_textures.size())
break;
s++; s++;
} }
@ -167,6 +175,107 @@ TextureRef Material::get_texture(int slot, int index) const
return TextureRef(); return TextureRef();
} }
void Material::set_sampler(const char* name, const TextureSampler& sampler, int index)
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type != UniformType::Sampler2D)
continue;
if (strcmp(uniform.name, name) == 0)
{
m_samplers[offset + index] = sampler;
return;
}
offset += uniform.array_length;
if (offset + index >= m_samplers.size())
break;
}
Log::warn("No Sampler Uniform '%s' at index [%i] exists", name, index);
}
void Material::set_sampler(int slot, const TextureSampler& sampler, 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::Sampler2D)
continue;
if (s == slot)
{
if (index > uniform.array_length)
break;
m_samplers[offset + index] = sampler;
break;
}
offset += uniform.array_length;
s++;
}
}
TextureSampler Material::get_sampler(const char* name, int index) const
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type != UniformType::Sampler2D)
continue;
if (strcmp(uniform.name, name) == 0)
return m_samplers[offset + index];
offset += uniform.array_length;
if (offset + index >= m_samplers.size())
break;
}
Log::warn("No Sampler Uniform '%s' at index [%i] exists", name, index);
return TextureSampler();
}
TextureSampler Material::get_sampler(int slot, int index) const
{
BLAH_ASSERT(m_shader, "Material Shader is invalid");
int s = 0;
int offset = 0;
for (auto& uniform : m_shader->uniforms())
{
if (uniform.type != UniformType::Sampler2D)
continue;
if (s == slot)
{
if (index > uniform.array_length)
break;
return m_samplers[offset + index];
}
offset += uniform.array_length;
if (offset + index >= m_samplers.size())
break;
s++;
}
Log::warn("No Sampler Uniform ['%i'] at index [%i] exists", slot, index);
return TextureSampler();
}
void Material::set_value(const char* name, const float* value, int64_t length) void Material::set_value(const char* name, const float* value, int64_t length)
{ {
BLAH_ASSERT(m_shader, "Material Shader is invalid"); BLAH_ASSERT(m_shader, "Material Shader is invalid");
@ -176,7 +285,9 @@ void Material::set_value(const char* name, const float* value, int64_t length)
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
{ {
if (uniform.type == UniformType::Texture || uniform.type == UniformType::None) if (uniform.type == UniformType::Texture2D ||
uniform.type == UniformType::Sampler2D ||
uniform.type == UniformType::None)
continue; continue;
if (strcmp(uniform.name, name) == 0) if (strcmp(uniform.name, name) == 0)
@ -207,7 +318,9 @@ const float* Material::get_value(const char* name, int64_t* length) const
int offset = 0; int offset = 0;
for (auto& uniform : m_shader->uniforms()) for (auto& uniform : m_shader->uniforms())
{ {
if (uniform.type == UniformType::Texture || uniform.type == UniformType::None) if (uniform.type == UniformType::Texture2D ||
uniform.type == UniformType::Sampler2D ||
uniform.type == UniformType::None)
continue; continue;
if (strcmp(uniform.name, name) == 0) if (strcmp(uniform.name, name) == 0)
@ -231,6 +344,11 @@ const Vector<TextureRef>& Material::textures() const
return m_textures; return m_textures;
} }
const Vector<TextureSampler>& Material::samplers() const
{
return m_samplers;
}
const float* Material::data() const const float* Material::data() const
{ {
return m_data.begin(); return m_data.begin();

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <blah/graphics/texture.h> #include <blah/graphics/texture.h>
#include <blah/graphics/shader.h> #include <blah/graphics/shader.h>
#include <blah/graphics/sampler.h>
#include <blah/containers/vector.h> #include <blah/containers/vector.h>
#include <memory> #include <memory>
@ -43,6 +44,18 @@ namespace Blah
// Gets the texture, or an empty reference if invalid // Gets the texture, or an empty reference if invalid
TextureRef get_texture(int slot, int array_index = 0) const; TextureRef get_texture(int slot, int array_index = 0) const;
// Sets the sampler
void set_sampler(const char* name, const TextureSampler& sampler, int array_index = 0);
// Sets the sampler
void set_sampler(int slot, const TextureSampler& sampler, int array_index = 0);
// Gets the sampler
TextureSampler get_sampler(const char* name, int array_index = 0) const;
// Gets the sampler
TextureSampler get_sampler(int slot, int array_index = 0) const;
// Sets the value. `length` is the total number of floats to set // Sets the value. `length` is the total number of floats to set
void set_value(const char* name, const float* value, int64_t length); void set_value(const char* name, const float* value, int64_t length);
@ -52,12 +65,16 @@ namespace Blah
// Returns the internal Texture buffer // Returns the internal Texture buffer
const Vector<TextureRef>& textures() const; const Vector<TextureRef>& textures() const;
// Returns the internal Sampler buffer
const Vector<TextureSampler>& samplers() const;
// Returns the interal float buffer of all the values // Returns the interal float buffer of all the values
const float* data() const; const float* data() const;
private: private:
ShaderRef m_shader; ShaderRef m_shader;
Vector<TextureRef> m_textures; Vector<TextureRef> m_textures;
Vector<TextureSampler> m_samplers;
Vector<float> m_data; Vector<float> m_data;
}; };
} }

View File

@ -0,0 +1,53 @@
#pragma once
namespace Blah
{
enum class TextureFilter
{
None,
Linear,
Nearest
};
enum class TextureWrap
{
None,
Clamp,
Repeat
};
struct TextureSampler
{
TextureFilter filter;
TextureWrap wrap_x;
TextureWrap wrap_y;
TextureSampler() :
filter(TextureFilter::Linear),
wrap_x(TextureWrap::Repeat),
wrap_y(TextureWrap::Repeat) {}
TextureSampler(TextureFilter filter) :
filter(filter),
wrap_x(TextureWrap::Repeat),
wrap_y(TextureWrap::Repeat) {}
TextureSampler(TextureFilter filter, TextureWrap wrap_x, TextureWrap wrap_y) :
filter(filter),
wrap_x(wrap_x),
wrap_y(wrap_y) {}
bool operator==(const TextureSampler& rhs) const
{
return
filter == rhs.filter &&
wrap_x == rhs.wrap_x &&
wrap_y == rhs.wrap_y;
}
bool operator!=(const TextureSampler& rhs) const
{
return !(*this == rhs);
}
};
}

View File

@ -15,7 +15,8 @@ namespace Blah
Float4, Float4,
Mat3x2, Mat3x2,
Mat4x4, Mat4x4,
Texture Texture2D,
Sampler2D
}; };
// Supported Shader Types // Supported Shader Types

View File

@ -28,7 +28,7 @@ TextureRef Texture::create(int width, int height, TextureFormat format)
BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format"); BLAH_ASSERT((int)format > (int)TextureFormat::None && (int)format < (int)TextureFormat::Count, "Invalid texture format");
if (width > 0 && height > 0) if (width > 0 && height > 0)
return GraphicsBackend::create_texture(width, height, TextureFilter::Linear, TextureWrap::Repeat, TextureWrap::Repeat, format); return GraphicsBackend::create_texture(width, height, format);
return TextureRef(); return TextureRef();
} }

View File

@ -3,19 +3,6 @@
namespace Blah namespace Blah
{ {
enum class TextureFilter
{
None,
Linear,
Nearest
};
enum class TextureWrap
{
None,
Clamp,
Repeat
};
enum class TextureFormat enum class TextureFormat
{ {
@ -76,21 +63,6 @@ namespace Blah
// Gets the format of the Texture // Gets the format of the Texture
virtual TextureFormat format() const = 0; virtual TextureFormat format() const = 0;
// Sets the filter of the Texture
virtual void set_filter(TextureFilter filter) = 0;
// Gets the filter of the Texture
virtual TextureFilter get_filter() const = 0;
// Sets the wrap of the Texture
virtual void set_wrap(TextureWrap x, TextureWrap y) = 0;
// Gets the wrap of the Texture
virtual TextureWrap get_wrap_x() const = 0;
// Gets the wrap of the Texture
virtual TextureWrap get_wrap_y() const = 0;
// Sets the data of the Texture. // Sets the data of the Texture.
// Note that the pixel buffer should be in the same format as the Texture. There is no row padding. // Note that the pixel buffer should be in the same format as the Texture. There is no row padding.
// If the pixel buffer isn't the same size as the texture, it will set the minimum available amount of data. // If the pixel buffer isn't the same size as the texture, it will set the minimum available amount of data.