mirror of
https://github.com/NoelFB/blah.git
synced 2025-02-23 14:28:28 +08:00
252 lines
5.4 KiB
C++
252 lines
5.4 KiB
C++
|
#include <blah/graphics/material.h>
|
||
|
|
||
|
using namespace Blah;
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
size_t calc_uniform_size(const ShaderUniform& uniform)
|
||
|
{
|
||
|
size_t components = 0;
|
||
|
|
||
|
switch (uniform.type)
|
||
|
{
|
||
|
case UniformType::Float: components = 1; break;
|
||
|
case UniformType::Float2: components = 2; break;
|
||
|
case UniformType::Float3: components = 3; break;
|
||
|
case UniformType::Float4: components = 4; break;
|
||
|
case UniformType::Mat3x2: components = 6; break;
|
||
|
case UniformType::Mat4x4: components = 16; break;
|
||
|
default:
|
||
|
BLAH_ERROR("Unespected Uniform Type");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return components * uniform.array_length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Material::Material(const ShaderRef& shader)
|
||
|
{
|
||
|
m_shader = shader;
|
||
|
m_data = nullptr;
|
||
|
m_disposed = false;
|
||
|
|
||
|
// invalid shader
|
||
|
if (!m_shader || !m_shader->is_valid())
|
||
|
{
|
||
|
m_disposed = true;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Uniforms uniforms = shader->uniforms();
|
||
|
StackList<size_t, BLAH_UNIFORMS> float_offsets;
|
||
|
size_t float_size = 0;
|
||
|
|
||
|
for (auto& uniform : uniforms)
|
||
|
{
|
||
|
if (uniform.type == UniformType::None)
|
||
|
continue;
|
||
|
|
||
|
if (uniform.type == UniformType::Texture)
|
||
|
{
|
||
|
for (int i = 0; i < uniform.array_length; i ++)
|
||
|
m_textures.add(TextureRef());
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
float_offsets.add(float_size);
|
||
|
float_size += calc_uniform_size(uniform);
|
||
|
}
|
||
|
|
||
|
m_data = new float[float_size];
|
||
|
memset(m_data, 0, sizeof(float) * float_size);
|
||
|
|
||
|
for (auto& it : float_offsets)
|
||
|
m_floats.add(m_data + it);
|
||
|
}
|
||
|
|
||
|
Material::~Material()
|
||
|
{
|
||
|
dispose();
|
||
|
}
|
||
|
|
||
|
const ShaderRef Material::shader() const
|
||
|
{
|
||
|
return m_shader;
|
||
|
}
|
||
|
|
||
|
void Material::set_texture(const char* name, const TextureRef& texture, int index)
|
||
|
{
|
||
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||
|
|
||
|
if (m_textures.count() > 0)
|
||
|
{
|
||
|
int offset = 0;
|
||
|
for (auto& uniform : m_shader->uniforms())
|
||
|
{
|
||
|
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.count())
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Log::warn("No Texture Uniform '%s' at index [%i] exists", name, index);
|
||
|
}
|
||
|
|
||
|
TextureRef Material::get_texture(const char* name, int index) const
|
||
|
{
|
||
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||
|
|
||
|
int offset = 0;
|
||
|
for (auto& uniform : m_shader->uniforms())
|
||
|
{
|
||
|
if (uniform.type != UniformType::Texture)
|
||
|
continue;
|
||
|
|
||
|
if (strcmp(uniform.name, name) == 0)
|
||
|
return m_textures[offset + index];
|
||
|
|
||
|
offset += uniform.array_length;
|
||
|
if (offset + index >= m_textures.count())
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Log::warn("No Texture Uniform '%s' at index [%i] exists", name, index);
|
||
|
return TextureRef();
|
||
|
}
|
||
|
|
||
|
TextureRef Material::get_texture(int slot, int index) const
|
||
|
{
|
||
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||
|
|
||
|
int offset = 0;
|
||
|
int s = 0;
|
||
|
for (auto& uniform : m_shader->uniforms())
|
||
|
{
|
||
|
if (uniform.type == UniformType::Texture)
|
||
|
{
|
||
|
if (s == slot)
|
||
|
return m_textures[offset + index];
|
||
|
|
||
|
offset += uniform.array_length;
|
||
|
if (offset + index >= m_textures.count())
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
s++;
|
||
|
}
|
||
|
|
||
|
Log::warn("No Texture Uniform ['%i'] at index [%i] exists", slot, index);
|
||
|
return TextureRef();
|
||
|
}
|
||
|
|
||
|
void Material::set_value(const char* name, const float* value, int64_t length)
|
||
|
{
|
||
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||
|
BLAH_ASSERT(length >= 0, "Length must be >= 0");
|
||
|
|
||
|
int index = 0;
|
||
|
for (auto& uniform : m_shader->uniforms())
|
||
|
{
|
||
|
if (uniform.type == UniformType::Texture || uniform.type == UniformType::None)
|
||
|
continue;
|
||
|
|
||
|
if (strcmp(uniform.name, name) == 0)
|
||
|
{
|
||
|
size_t max = calc_uniform_size(uniform);
|
||
|
if (length > max)
|
||
|
{
|
||
|
Log::warn("Exceeding length of Uniform '%s' (%i / %i)", name, length, max);
|
||
|
length = max;
|
||
|
}
|
||
|
|
||
|
memcpy(m_floats[index], value, sizeof(float) * length);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
index++;
|
||
|
}
|
||
|
|
||
|
Log::warn("No Uniform '%s' exists", name);
|
||
|
}
|
||
|
|
||
|
const float* Material::get_value(const char* name, int64_t* length) const
|
||
|
{
|
||
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||
|
|
||
|
int index = 0;
|
||
|
for (auto& uniform : m_shader->uniforms())
|
||
|
{
|
||
|
if (uniform.type == UniformType::Texture || uniform.type == UniformType::None)
|
||
|
continue;
|
||
|
|
||
|
if (strcmp(uniform.name, name) == 0)
|
||
|
{
|
||
|
if (length != nullptr)
|
||
|
*length = calc_uniform_size(uniform);
|
||
|
return m_floats[index];
|
||
|
}
|
||
|
|
||
|
index++;
|
||
|
}
|
||
|
|
||
|
*length = 0;
|
||
|
return nullptr;
|
||
|
Log::warn("No Uniform '%s' exists", name);
|
||
|
}
|
||
|
|
||
|
const float* Material::get_value(int slot, int64_t* length) const
|
||
|
{
|
||
|
BLAH_ASSERT(!m_disposed, "Material has been disposed");
|
||
|
BLAH_ASSERT(m_shader && m_shader->is_valid(), "Material Shader is invalid");
|
||
|
|
||
|
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++;
|
||
|
}
|
||
|
|
||
|
*length = 0;
|
||
|
return nullptr;
|
||
|
Log::warn("No Uniform [%i] exists", slot);
|
||
|
}
|
||
|
|
||
|
bool Material::is_valid() const
|
||
|
{
|
||
|
return !m_disposed && m_shader && m_shader->is_valid();
|
||
|
}
|
||
|
|
||
|
void Material::dispose()
|
||
|
{
|
||
|
delete[] m_data;
|
||
|
m_data = nullptr;
|
||
|
m_shader.reset();
|
||
|
m_textures.clear();
|
||
|
m_floats.clear();
|
||
|
}
|