uniform refactor - closes #725

This commit is contained in:
Mikulas Florek 2016-02-09 19:21:00 +01:00
parent 1cc7b5f97c
commit 165892c169
6 changed files with 264 additions and 127 deletions

View file

@ -197,25 +197,32 @@ struct MaterialPlugin : public AssetBrowser::IPlugin
}
for (int i = 0; i < material->getUniformCount(); ++i)
auto* shader = material->getShader();
if(shader && material->isReady())
{
auto& uniform = material->getUniform(i);
switch (uniform.m_type)
for(int i = 0; i < shader->getUniformCount(); ++i)
{
case Material::Uniform::FLOAT:
ImGui::DragFloat(uniform.m_name, &uniform.m_float);
break;
case Material::Uniform::VEC3:
ImGui::DragFloat3(uniform.m_name, uniform.m_vec3);
break;
case Material::Uniform::COLOR:
ImGui::ColorEdit3(uniform.m_name, uniform.m_vec3);
if (ImGui::BeginPopupContextItem(StringBuilder<50>(uniform.m_name, "pu")))
auto& uniform = material->getUniform(i);
auto& shader_uniform = shader->getUniform(i);
switch(shader_uniform.type)
{
ImGui::ColorPicker(uniform.m_vec3, false);
ImGui::EndPopup();
case Shader::Uniform::FLOAT:
ImGui::DragFloat(shader_uniform.name, &uniform.float_value);
break;
case Shader::Uniform::VEC3:
ImGui::DragFloat3(shader_uniform.name, uniform.vec3);
break;
case Shader::Uniform::COLOR:
ImGui::ColorEdit3(shader_uniform.name, uniform.vec3);
if(ImGui::BeginPopupContextItem(StringBuilder<50>(shader_uniform.name, "pu")))
{
ImGui::ColorPicker(uniform.vec3, false);
ImGui::EndPopup();
}
break;
case Shader::Uniform::TIME: break;
default: ASSERT(false); break;
}
break;
}
}
ImGui::Columns(1);
@ -577,7 +584,7 @@ struct ShaderPlugin : public AssetBrowser::IPlugin
PlatformInterface::shellExecuteOpen(path);
}
if (ImGui::CollapsingHeader("Texture slots", nullptr, true, true))
if (shader->getTextureSlotCount() > 0 && ImGui::CollapsingHeader("Texture slots", nullptr, true, true))
{
ImGui::Columns(2);
ImGui::Text("name");
@ -595,6 +602,35 @@ struct ShaderPlugin : public AssetBrowser::IPlugin
}
ImGui::Columns(1);
}
if(shader->getUniformCount() > 0 && ImGui::CollapsingHeader("Uniforms", nullptr, true, true))
{
ImGui::Columns(2);
ImGui::Text("name");
ImGui::NextColumn();
ImGui::Text("type");
ImGui::NextColumn();
ImGui::Separator();
for(int i = 0; i < shader->getUniformCount(); ++i)
{
auto& uniform = shader->getUniform(i);
ImGui::Text(uniform.name);
ImGui::NextColumn();
switch(uniform.type)
{
case Shader::Uniform::COLOR: ImGui::Text("color"); break;
case Shader::Uniform::FLOAT: ImGui::Text("float"); break;
case Shader::Uniform::INT: ImGui::Text("int"); break;
case Shader::Uniform::MATRIX4: ImGui::Text("Matrix 4x4"); break;
case Shader::Uniform::TIME: ImGui::Text("time"); break;
case Shader::Uniform::VEC3: ImGui::Text("Vector3"); break;
default: ASSERT(false); break;
}
ImGui::NextColumn();
}
ImGui::Columns(1);
}
return true;
}

View file

@ -89,7 +89,7 @@ void Material::setDefine(uint8 define_idx, bool enabled)
void Material::unload(void)
{
clearUniforms();
m_uniforms.clear();
setShader(nullptr);
ResourceManagerBase* texture_manager = m_resource_manager.get(ResourceManager::TEXTURE);
@ -107,6 +107,9 @@ void Material::unload(void)
bool Material::save(JsonSerializer& serializer)
{
if(!isReady()) return false;
if(!m_shader) return false;
auto* manager = getResourceManager().get(ResourceManager::MATERIAL);
auto& renderer = static_cast<MaterialManager*>(manager)->getRenderer();
@ -154,37 +157,39 @@ bool Material::save(JsonSerializer& serializer)
for (int i = 0; i < m_uniforms.size(); ++i)
{
serializer.beginObject();
serializer.serialize("name", m_uniforms[i].m_name);
switch (m_uniforms[i].m_type)
const auto& uniform = m_shader->getUniform(i);
serializer.serialize("name", uniform.name);
switch (uniform.type)
{
case Uniform::FLOAT:
serializer.serialize("float_value", m_uniforms[i].m_float);
case Shader::Uniform::FLOAT:
serializer.serialize("float_value", m_uniforms[i].float_value);
break;
case Uniform::COLOR:
case Shader::Uniform::COLOR:
serializer.beginArray("color");
serializer.serializeArrayItem(m_uniforms[i].m_vec3[0]);
serializer.serializeArrayItem(m_uniforms[i].m_vec3[1]);
serializer.serializeArrayItem(m_uniforms[i].m_vec3[2]);
serializer.serializeArrayItem(m_uniforms[i].vec3[0]);
serializer.serializeArrayItem(m_uniforms[i].vec3[1]);
serializer.serializeArrayItem(m_uniforms[i].vec3[2]);
serializer.endArray();
break;
case Uniform::VEC3:
case Shader::Uniform::VEC3:
serializer.beginArray("vec3");
serializer.serializeArrayItem(m_uniforms[i].m_vec3[0]);
serializer.serializeArrayItem(m_uniforms[i].m_vec3[1]);
serializer.serializeArrayItem(m_uniforms[i].m_vec3[2]);
serializer.serializeArrayItem(m_uniforms[i].vec3[0]);
serializer.serializeArrayItem(m_uniforms[i].vec3[1]);
serializer.serializeArrayItem(m_uniforms[i].vec3[2]);
serializer.endArray();
break;
case Uniform::TIME:
serializer.serialize("time", m_uniforms[i].m_float);
case Shader::Uniform::TIME:
serializer.serialize("time", 0);
break;
case Uniform::INT:
serializer.serialize("int_value", m_uniforms[i].m_int);
case Shader::Uniform::INT:
serializer.serialize("int_value", m_uniforms[i].int_value);
break;
case Uniform::MATRIX:
case Shader::Uniform::MATRIX4:
serializer.beginArray("matrix_value");
for (int j = 0; j < 16; ++j)
{
serializer.serializeArrayItem(m_uniforms[i].m_matrix[j]);
serializer.serializeArrayItem(m_uniforms[i].matrix[j]);
}
serializer.endArray();
break;
@ -208,16 +213,6 @@ bool Material::save(JsonSerializer& serializer)
}
void Material::clearUniforms()
{
for (auto& uniform : m_uniforms)
{
bgfx::destroyUniform(uniform.m_handle);
}
m_uniforms.clear();
}
void Material::deserializeDefines(JsonSerializer& serializer)
{
auto* manager = getResourceManager().get(ResourceManager::MATERIAL);
@ -237,7 +232,7 @@ void Material::deserializeDefines(JsonSerializer& serializer)
void Material::deserializeUniforms(JsonSerializer& serializer)
{
serializer.deserializeArrayBegin();
clearUniforms();
m_uniforms.clear();
while (!serializer.isArrayEnd())
{
Uniform& uniform = m_uniforms.emplace();
@ -250,53 +245,45 @@ void Material::deserializeUniforms(JsonSerializer& serializer)
serializer.deserializeLabel(label, 255);
if (compareString(label, "name") == 0)
{
serializer.deserialize(uniform.m_name, Uniform::MAX_NAME_LENGTH, "");
uniform.m_name_hash = crc32(uniform.m_name);
char name[32];
serializer.deserialize(name, lengthOf(name), "");
uniform.name_hash = crc32(name);
}
else if (compareString(label, "int_value") == 0)
{
uniform_type = bgfx::UniformType::Int1;
uniform.m_type = Uniform::INT;
serializer.deserialize(uniform.m_int, 0);
serializer.deserialize(uniform.int_value, 0);
}
else if (compareString(label, "float_value") == 0)
{
uniform.m_type = Uniform::FLOAT;
serializer.deserialize(uniform.m_float, 0);
serializer.deserialize(uniform.float_value, 0);
}
else if (compareString(label, "matrix_value") == 0)
{
uniform_type = bgfx::UniformType::Mat4;
uniform.m_type = Uniform::MATRIX;
serializer.deserializeArrayBegin();
for (int i = 0; i < 16; ++i)
{
serializer.deserializeArrayItem(uniform.m_matrix[i], 0);
ASSERT(i == 15 || !serializer.isArrayEnd());
serializer.deserializeArrayItem(uniform.matrix[i], 0);
}
serializer.deserializeArrayEnd();
}
else if (compareString(label, "time") == 0)
{
uniform.m_type = Uniform::TIME;
serializer.deserialize(uniform.m_float, 0);
serializer.deserialize(uniform.float_value, 0);
}
else if (compareString(label, "color") == 0)
{
uniform.m_type = Uniform::COLOR;
serializer.deserializeArrayBegin();
serializer.deserializeArrayItem(uniform.m_vec3[0], 0);
serializer.deserializeArrayItem(uniform.m_vec3[1], 0);
serializer.deserializeArrayItem(uniform.m_vec3[2], 0);
serializer.deserializeArrayItem(uniform.vec3[0], 0);
serializer.deserializeArrayItem(uniform.vec3[1], 0);
serializer.deserializeArrayItem(uniform.vec3[2], 0);
serializer.deserializeArrayEnd();
}
else if (compareString(label, "vec3") == 0)
{
uniform.m_type = Uniform::VEC3;
serializer.deserializeArrayBegin();
serializer.deserializeArrayItem(uniform.m_vec3[0], 0);
serializer.deserializeArrayItem(uniform.m_vec3[1], 0);
serializer.deserializeArrayItem(uniform.m_vec3[2], 0);
serializer.deserializeArrayItem(uniform.vec3[0], 0);
serializer.deserializeArrayItem(uniform.vec3[1], 0);
serializer.deserializeArrayItem(uniform.vec3[2], 0);
serializer.deserializeArrayEnd();
}
else
@ -304,8 +291,6 @@ void Material::deserializeUniforms(JsonSerializer& serializer)
g_log_warning.log("material") << "Unknown label \"" << label << "\"";
}
}
uniform.m_handle = bgfx::createUniform(uniform.m_name, uniform_type);
serializer.deserializeObjectEnd();
}
serializer.deserializeArrayEnd();
@ -368,6 +353,34 @@ void Material::setShader(const Path& path)
void Material::onBeforeReady()
{
if (!m_shader) return;
for(int i = 0; i < m_shader->getUniformCount(); ++i)
{
auto& shader_uniform = m_shader->getUniform(i);
bool found = false;
for(int j = i; j < m_uniforms.size(); ++j)
{
if(m_uniforms[j].name_hash == shader_uniform.name_hash)
{
auto tmp = m_uniforms[i];
m_uniforms[i] = m_uniforms[j];
m_uniforms[j] = tmp;
found = true;
break;
}
}
if(found) continue;
if(i < m_uniforms.size())
{
m_uniforms.emplace(m_uniforms[i]);
}
else
{
m_uniforms.emplace();
}
m_uniforms[i].name_hash = shader_uniform.name_hash;
}
m_shader_instance = &m_shader->getInstance(m_define_mask);
}

View file

@ -31,33 +31,16 @@ public:
LEQUAL,
LESS
};
struct Uniform
{
Uniform() {}
enum Type
{
INT,
FLOAT,
MATRIX,
TIME,
COLOR,
VEC3
};
static const int MAX_NAME_LENGTH = 32;
char m_name[MAX_NAME_LENGTH + 1];
uint32 m_name_hash;
Type m_type;
bgfx::UniformHandle m_handle;
uint32 name_hash;
union
{
int32 m_int;
float m_float;
float m_vec3[3];
float m_matrix[16];
int32 int_value;
float float_value;
float vec3[3];
float matrix[16];
};
};
@ -101,7 +84,6 @@ private:
void unload(void) override;
bool load(FS::IFile& file) override;
void clearUniforms();
bool deserializeTexture(JsonSerializer& serializer, const char* material_dir);
void deserializeUniforms(JsonSerializer& serializer);
void deserializeDefines(JsonSerializer& serializer);

View file

@ -1428,36 +1428,37 @@ struct PipelineImpl : public Pipeline
vertex[5].u = 0;
vertex[5].v = 1;
for (int i = 0; i < material->getUniformCount(); ++i)
Shader* shader = material->getShader();
for (int i = 0; i < shader->getUniformCount(); ++i)
{
const Material::Uniform& uniform = material->getUniform(i);
const Shader::Uniform& shader_uniform = shader->getUniform(i);
switch (uniform.m_type)
switch (shader_uniform.type)
{
case Material::Uniform::FLOAT:
case Shader::Uniform::FLOAT:
{
Vec4 v(uniform.m_float, 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
Vec4 v(uniform.float_value, 0, 0, 0);
bgfx::setUniform(shader_uniform.handle, &v);
}
break;
case Material::Uniform::COLOR:
case Material::Uniform::VEC3:
case Shader::Uniform::COLOR:
case Shader::Uniform::VEC3:
{
Vec4 v(*(Vec3*)uniform.m_vec3, 0);
bgfx::setUniform(uniform.m_handle, &v);
Vec4 v(*(Vec3*)uniform.vec3, 0);
bgfx::setUniform(shader_uniform.handle, &v);
}
break;
case Material::Uniform::TIME:
case Shader::Uniform::TIME:
{
Vec4 v(m_scene->getTime(), 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
bgfx::setUniform(shader_uniform.handle, &v);
}
break;
default: ASSERT(false); break;
}
}
Shader* shader = material->getShader();
for (int i = 0; i < material->getTextureCount(); ++i)
{
Texture* texture = material->getTexture(i);
@ -1739,29 +1740,37 @@ struct PipelineImpl : public Pipeline
setPointLightUniforms(material, m_current_light);
}
for (int i = 0; i < material->getUniformCount(); ++i)
Shader* shader = material->getShader();
for (int i = 0; i < shader->getUniformCount(); ++i)
{
const Material::Uniform& uniform = material->getUniform(i);
const Shader::Uniform& shader_uniform = shader->getUniform(i);
switch (uniform.m_type)
switch (shader_uniform.type)
{
case Material::Uniform::FLOAT:
case Shader::Uniform::FLOAT:
{
Vec4 v(uniform.m_float, 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
Vec4 v(uniform.float_value, 0, 0, 0);
bgfx::setUniform(shader_uniform.handle, &v);
}
break;
case Material::Uniform::TIME:
case Shader::Uniform::VEC3:
case Shader::Uniform::COLOR:
{
Vec4 v(*(Vec3*)uniform.vec3, 0);
bgfx::setUniform(shader_uniform.handle, &v);
}
break;
case Shader::Uniform::TIME:
{
Vec4 v(m_scene->getTime(), 0, 0, 0);
bgfx::setUniform(uniform.m_handle, &v);
bgfx::setUniform(shader_uniform.handle, &v);
}
break;
default: ASSERT(false); break;
}
}
Shader* shader = material->getShader();
for (int i = 0; i < material->getTextureCount(); ++i)
{
Texture* texture = material->getTexture(i);

View file

@ -22,6 +22,7 @@ Shader::Shader(const Path& path, ResourceManager& resource_manager, IAllocator&
, m_allocator(allocator)
, m_instances(m_allocator)
, m_texture_slot_count(0)
, m_uniforms(m_allocator)
{
}
@ -84,6 +85,85 @@ void ShaderCombinations::parsePasses(lua_State* L)
}
void Shader::clearUniforms()
{
for(auto& uniform : m_uniforms)
{
bgfx::destroyUniform(uniform.handle);
}
m_uniforms.clear();
}
void Shader::parseUniforms(lua_State* L)
{
clearUniforms();
if(lua_getglobal(L, "uniforms") == LUA_TTABLE)
{
int len = (int)lua_rawlen(L, -1);
for(int i = 0; i < len; ++i)
{
auto& uniform = m_uniforms.emplace();
bgfx::UniformType::Enum bgfx_type;
if(lua_rawgeti(L, -1, 1 + i) == LUA_TTABLE)
{
if(lua_getfield(L, -1, "name") == LUA_TSTRING)
{
copyString(uniform.name, lua_tostring(L, -1));
uniform.name_hash = crc32(uniform.name);
}
lua_pop(L, 1);
if(lua_getfield(L, -1, "type") == LUA_TSTRING)
{
const char* type_str = lua_tostring(L, -1);
if(compareString(type_str, "float") == 0)
{
uniform.type = Shader::Uniform::FLOAT;
bgfx_type = bgfx::UniformType::Vec4;
}
else if(compareString(type_str, "int") == 0)
{
uniform.type = Shader::Uniform::INT;
bgfx_type = bgfx::UniformType::Int1;
}
else if(compareString(type_str, "color") == 0)
{
uniform.type = Shader::Uniform::COLOR;
bgfx_type = bgfx::UniformType::Vec4;
}
else if(compareString(type_str, "time") == 0)
{
uniform.type = Shader::Uniform::TIME;
bgfx_type = bgfx::UniformType::Vec4;
}
else if(compareString(type_str, "matrix4") == 0)
{
uniform.type = Shader::Uniform::MATRIX4;
bgfx_type = bgfx::UniformType::Mat4;
}
else if(compareString(type_str, "vec3") == 0)
{
uniform.type = Shader::Uniform::VEC3;
bgfx_type = bgfx::UniformType::Vec4;
}
else
{
g_log_error.log("shader") << "Unknown uniform type " << type_str << " in shader " << getPath().c_str();
uniform.type = Shader::Uniform::FLOAT;
bgfx_type = bgfx::UniformType::Vec4;
}
}
lua_pop(L, 1);
uniform.handle = bgfx::createUniform(uniform.name, bgfx_type);
}
lua_pop(L, 1);
}
}
lua_pop(L, 1);
}
void Shader::parseTextureSlots(lua_State* L)
{
for (int i = 0; i < m_texture_slot_count; ++i)
@ -99,9 +179,7 @@ void Shader::parseTextureSlots(lua_State* L)
{
if (lua_getfield(L, -1, "name") == LUA_TSTRING)
{
copyString(m_texture_slots[i].m_name,
sizeof(m_texture_slots[i].m_name),
lua_tostring(L, -1));
copyString(m_texture_slots[i].m_name, lua_tostring(L, -1));
}
lua_pop(L, 1);
if (lua_getfield(L, -1, "is_atlas") == LUA_TBOOLEAN)
@ -238,6 +316,7 @@ bool Shader::load(FS::IFile& file)
}
parseTextureSlots(L);
parseUniforms(L);
m_combintions.parse(getRenderer(), L);
if (!generateInstances())
{

View file

@ -90,9 +90,8 @@ class LUMIX_RENDERER_API Shader : public Resource
friend class ShaderInstance;
public:
class TextureSlot
struct TextureSlot
{
public:
TextureSlot() { reset(); }
void reset() { m_name[0] = m_uniform[0] = '\0'; m_define_idx = -1; m_is_atlas = false; }
@ -106,31 +105,49 @@ public:
};
struct Uniform
{
enum Type
{
INT,
FLOAT,
MATRIX4,
TIME,
COLOR,
VEC3
};
char name[32];
uint32 name_hash;
Type type;
bgfx::UniformHandle handle;
};
public:
static const int MAX_TEXTURE_SLOT_COUNT = 16;
public:
Shader(const Path& path,
ResourceManager& resource_manager,
IAllocator& allocator);
Shader(const Path& path, ResourceManager& resource_manager, IAllocator& allocator);
~Shader();
bool hasDefine(uint8 define_idx) const;
ShaderInstance& getInstance(uint32 mask);
ShaderInstance* getFirstInstance();
const TextureSlot& getTextureSlot(int index) const
{
return m_texture_slots[index];
}
const TextureSlot& getTextureSlot(int index) const { return m_texture_slots[index]; }
int getTextureSlotCount() const { return m_texture_slot_count; }
Renderer& getRenderer();
Uniform& getUniform(int index) { return m_uniforms[index]; }
int getUniformCount() const { return m_uniforms.size(); }
static bool getShaderCombinations(Renderer& renderer,
const char* shader_content,
ShaderCombinations* output);
const char* shader_content,
ShaderCombinations* output);
private:
void parseTextureSlots(lua_State* state);
void parseUniforms(lua_State* state);
void clearUniforms();
bool generateInstances();
uint32 getDefineMaskFromDense(uint32 dense) const;
@ -143,6 +160,7 @@ private:
TextureSlot m_texture_slots[MAX_TEXTURE_SLOT_COUNT];
int m_texture_slot_count;
Array<ShaderInstance*> m_instances;
Array<Uniform> m_uniforms;
ShaderCombinations m_combintions;
};