mirror of
https://github.com/NoelFB/blah.git
synced 2025-02-22 14:18:29 +08:00
357 lines
7.2 KiB
C++
357 lines
7.2 KiB
C++
#include <blah/graphics/material.h>
|
|
#include <blah/common.h>
|
|
#include <cstring>
|
|
|
|
using namespace Blah;
|
|
|
|
namespace
|
|
{
|
|
int calc_uniform_size(const UniformInfo& uniform)
|
|
{
|
|
int 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_ASSERT(false, "Unespected Uniform Type");
|
|
break;
|
|
}
|
|
|
|
return components * uniform.array_length;
|
|
}
|
|
}
|
|
|
|
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();
|
|
int float_size = 0;
|
|
|
|
for (auto& uniform : uniforms)
|
|
{
|
|
if (uniform.type == UniformType::None)
|
|
continue;
|
|
|
|
if (uniform.type == UniformType::Texture2D)
|
|
{
|
|
for (int i = 0; i < uniform.array_length; i ++)
|
|
m_textures.push_back(TextureRef());
|
|
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);
|
|
}
|
|
|
|
m_data.expand(float_size);
|
|
}
|
|
|
|
ShaderRef Material::shader() const
|
|
{
|
|
return m_shader;
|
|
}
|
|
|
|
void Material::set_texture(const char* name, const TextureRef& texture, int index)
|
|
{
|
|
BLAH_ASSERT(m_shader, "Material Shader is invalid");
|
|
|
|
int offset = 0;
|
|
for (auto& uniform : m_shader->uniforms())
|
|
{
|
|
if (uniform.type != UniformType::Texture2D)
|
|
continue;
|
|
|
|
if (strcmp(uniform.name, name) == 0)
|
|
{
|
|
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::Texture2D)
|
|
continue;
|
|
|
|
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");
|
|
|
|
int offset = 0;
|
|
for (auto& uniform : m_shader->uniforms())
|
|
{
|
|
if (uniform.type != UniformType::Texture2D)
|
|
continue;
|
|
|
|
if (strcmp(uniform.name, name) == 0)
|
|
return m_textures[offset + index];
|
|
|
|
offset += uniform.array_length;
|
|
if (offset + index >= m_textures.size())
|
|
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_shader, "Material Shader is invalid");
|
|
|
|
int s = 0;
|
|
int offset = 0;
|
|
for (auto& uniform : m_shader->uniforms())
|
|
{
|
|
if (uniform.type != UniformType::Texture2D)
|
|
continue;
|
|
|
|
if (s == slot)
|
|
{
|
|
if (index > uniform.array_length)
|
|
break;
|
|
|
|
return m_textures[offset + index];
|
|
}
|
|
|
|
offset += uniform.array_length;
|
|
if (offset + index >= m_textures.size())
|
|
break;
|
|
|
|
s++;
|
|
}
|
|
|
|
Log::warn("No Texture Uniform ['%i'] at index [%i] exists", slot, index);
|
|
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, i64 length)
|
|
{
|
|
BLAH_ASSERT(m_shader, "Material Shader is invalid");
|
|
BLAH_ASSERT(length >= 0, "Length must be >= 0");
|
|
|
|
int index = 0;
|
|
int offset = 0;
|
|
for (auto& uniform : m_shader->uniforms())
|
|
{
|
|
if (uniform.type == UniformType::Texture2D ||
|
|
uniform.type == UniformType::Sampler2D ||
|
|
uniform.type == UniformType::None)
|
|
continue;
|
|
|
|
if (strcmp(uniform.name, name) == 0)
|
|
{
|
|
auto max = calc_uniform_size(uniform);
|
|
if (length > max)
|
|
{
|
|
Log::warn("Exceeding length of Uniform '%s' (%i / %i)", name, length, max);
|
|
length = max;
|
|
}
|
|
|
|
memcpy(m_data.begin() + offset, value, sizeof(float) * length);
|
|
return;
|
|
}
|
|
|
|
offset += calc_uniform_size(uniform);
|
|
index++;
|
|
}
|
|
|
|
Log::warn("No Uniform '%s' exists", name);
|
|
}
|
|
|
|
const float* Material::get_value(const char* name, i64* 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::Texture2D ||
|
|
uniform.type == UniformType::Sampler2D ||
|
|
uniform.type == UniformType::None)
|
|
continue;
|
|
|
|
if (strcmp(uniform.name, name) == 0)
|
|
{
|
|
if (length != nullptr)
|
|
*length = calc_uniform_size(uniform);
|
|
return m_data.begin() + offset;
|
|
}
|
|
|
|
index++;
|
|
offset += calc_uniform_size(uniform);
|
|
}
|
|
|
|
Log::warn("No Uniform '%s' exists", name);
|
|
*length = 0;
|
|
return nullptr;
|
|
}
|
|
|
|
const Vector<TextureRef>& Material::textures() const
|
|
{
|
|
return m_textures;
|
|
}
|
|
|
|
const Vector<TextureSampler>& Material::samplers() const
|
|
{
|
|
return m_samplers;
|
|
}
|
|
|
|
const float* Material::data() const
|
|
{
|
|
return m_data.begin();
|
|
}
|