LumixEngine/src/renderer/material.cpp

854 lines
21 KiB
C++
Raw Normal View History

2015-08-17 23:45:26 +02:00
#include "renderer/material.h"
2016-05-10 08:24:31 +02:00
#include "engine/crc32.h"
#include "engine/fs/file_system.h"
#include "engine/json_serializer.h"
#include "engine/log.h"
#include "engine/path_utils.h"
#include "engine/profiler.h"
#include "engine/resource_manager.h"
#include "engine/resource_manager_base.h"
#include "renderer/material_manager.h"
2016-02-14 16:49:37 +01:00
#include "renderer/pipeline.h"
2015-09-05 13:08:47 +02:00
#include "renderer/renderer.h"
2015-08-17 23:45:26 +02:00
#include "renderer/shader.h"
#include "renderer/texture.h"
2014-06-16 21:18:15 +02:00
namespace Lumix
{
2014-09-07 01:10:24 +02:00
static const uint32 SHADOWMAP_HASH = crc32("shadowmap");
2016-07-24 22:21:43 +02:00
static const ResourceType TEXTURE_TYPE("texture");
static const ResourceType SHADER_TYPE("shader");
static const ResourceType MATERIAL_TYPE("material");
static const float DEFAULT_ALPHA_REF_VALUE = 0.3f;
2016-05-17 07:10:20 +02:00
2016-03-14 00:59:28 +01:00
static struct CustomFlags
{
char flags[32][32];
int count;
} s_custom_flags = {};
2014-09-07 01:10:24 +02:00
static uint8 DEFAULT_COMMAND_BUFFER = 0;
2016-07-25 01:02:36 +02:00
Material::Material(const Path& path, ResourceManagerBase& resource_manager, IAllocator& allocator)
2015-09-04 14:00:28 +02:00
: Resource(path, resource_manager, allocator)
, m_shader(nullptr)
, m_uniforms(allocator)
, m_allocator(allocator)
, m_texture_count(0)
, m_render_states(BGFX_STATE_CULL_CW)
, m_color(1, 1, 1)
2015-09-04 14:00:28 +02:00
, m_shininess(4)
, m_shader_instance(nullptr)
2016-02-08 00:18:19 +01:00
, m_define_mask(0)
, m_command_buffer(&DEFAULT_COMMAND_BUFFER)
2016-03-14 00:59:28 +01:00
, m_custom_flags(0)
2015-09-04 14:00:28 +02:00
{
for (auto& l : m_layer_count) l = 1;
setAlphaRef(DEFAULT_ALPHA_REF_VALUE);
2015-09-04 14:00:28 +02:00
for (int i = 0; i < MAX_TEXTURE_COUNT; ++i)
{
m_textures[i] = nullptr;
}
setShader(nullptr);
2015-09-04 14:00:28 +02:00
}
2014-06-16 21:18:15 +02:00
Material::~Material()
{
ASSERT(isEmpty());
}
2015-06-18 01:33:49 +02:00
2016-03-14 00:59:28 +01:00
const char* Material::getCustomFlagName(int index)
{
return s_custom_flags.flags[index];
}
int Material::getCustomFlagCount()
{
return s_custom_flags.count;
}
2016-03-14 00:59:28 +01:00
uint32 Material::getCustomFlag(const char* flag_name)
{
for (int i = 0; i < s_custom_flags.count; ++i)
{
2016-05-12 09:56:07 +02:00
if (equalStrings(s_custom_flags.flags[i], flag_name)) return 1 << i;
2016-03-14 00:59:28 +01:00
}
if (s_custom_flags.count >= lengthOf(s_custom_flags.flags))
{
ASSERT(false);
return 0;
}
copyString(s_custom_flags.flags[s_custom_flags.count], flag_name);
++s_custom_flags.count;
return 1 << (s_custom_flags.count - 1);
}
2016-02-08 00:18:19 +01:00
bool Material::isDefined(uint8 define_idx) const
2015-09-04 14:00:28 +02:00
{
2016-02-08 00:18:19 +01:00
return (m_define_mask & (1 << define_idx)) != 0;
2015-09-05 13:08:47 +02:00
}
2016-02-08 00:18:19 +01:00
bool Material::hasDefine(uint8 define_idx) const
2015-09-05 13:08:47 +02:00
{
2016-02-08 00:57:13 +01:00
return m_shader->hasDefine(define_idx) != 0;
2015-09-04 14:00:28 +02:00
}
2016-02-08 00:18:19 +01:00
void Material::setDefine(uint8 define_idx, bool enabled)
2015-09-05 20:54:26 +02:00
{
2016-02-08 00:57:13 +01:00
uint32 old_mask = m_define_mask;
2016-02-08 00:18:19 +01:00
if (enabled)
2015-09-04 14:00:28 +02:00
{
2016-02-08 00:18:19 +01:00
m_define_mask |= 1 << define_idx;
2015-09-04 14:00:28 +02:00
}
2015-09-05 20:54:26 +02:00
else
2015-09-04 14:00:28 +02:00
{
2016-02-08 00:18:19 +01:00
m_define_mask &= ~(1 << define_idx);
2015-09-04 14:00:28 +02:00
}
2015-09-05 20:54:26 +02:00
if (!isReady()) return;
2016-02-08 00:18:19 +01:00
if (!m_shader) return;
2015-09-05 20:54:26 +02:00
2016-02-08 00:57:13 +01:00
if (old_mask != m_define_mask)
2016-02-08 00:18:19 +01:00
{
2016-02-08 00:57:13 +01:00
m_shader_instance = &m_shader->getInstance(m_define_mask);
2016-02-08 00:18:19 +01:00
}
2014-10-06 23:58:33 +02:00
}
2015-10-03 01:14:38 +02:00
void Material::unload(void)
2014-06-16 21:18:15 +02:00
{
if(m_command_buffer != &DEFAULT_COMMAND_BUFFER) m_allocator.deallocate(m_command_buffer);
m_command_buffer = &DEFAULT_COMMAND_BUFFER;
2016-02-09 19:21:00 +01:00
m_uniforms.clear();
2015-07-25 19:33:19 +02:00
setShader(nullptr);
2014-06-16 21:18:15 +02:00
2016-07-25 01:02:36 +02:00
ResourceManagerBase* texture_manager = m_resource_manager.getOwner().get(TEXTURE_TYPE);
2015-05-31 15:48:35 +02:00
for (int i = 0; i < m_texture_count; i++)
2014-06-16 21:18:15 +02:00
{
2015-05-31 15:48:35 +02:00
if (m_textures[i])
2015-02-28 13:05:01 +01:00
{
2015-05-31 15:48:35 +02:00
removeDependency(*m_textures[i]);
texture_manager->unload(*m_textures[i]);
2015-02-28 13:05:01 +01:00
}
2014-06-16 21:18:15 +02:00
}
2015-05-31 15:48:35 +02:00
m_texture_count = 0;
m_define_mask = 0;
2014-06-16 21:18:15 +02:00
}
bool Material::save(JsonSerializer& serializer)
2014-06-16 21:18:15 +02:00
{
2016-02-09 19:21:00 +01:00
if(!isReady()) return false;
if(!m_shader) return false;
2016-07-25 01:02:36 +02:00
auto& renderer = static_cast<MaterialManager&>(m_resource_manager).getRenderer();
2016-02-08 00:18:19 +01:00
2014-06-16 21:18:15 +02:00
serializer.beginObject();
2016-01-07 13:33:52 +01:00
serializer.serialize("shader", m_shader ? m_shader->getPath() : Path(""));
for (int i = 0; i < lengthOf(m_layer_count); ++i)
{
if (m_layer_count[i] != 1)
{
serializer.beginObject("layer");
serializer.serialize("pass", renderer.getPassName(i));
serializer.serialize("count", m_layer_count[i]);
serializer.endObject();
}
}
2015-05-31 15:48:35 +02:00
for (int i = 0; i < m_texture_count; ++i)
2014-06-16 21:18:15 +02:00
{
char path[MAX_PATH_LENGTH];
2015-09-25 23:03:10 +02:00
int flags = 0;
2015-10-04 14:39:52 +02:00
int atlas_size = -1;
2015-05-31 15:48:35 +02:00
if (m_textures[i])
{
2016-05-12 12:00:35 +02:00
flags = m_textures[i]->bgfx_flags;
path[0] = '/';
Lumix::copyString(path + 1, MAX_PATH_LENGTH - 1, m_textures[i]->getPath().c_str());
2016-05-12 12:00:35 +02:00
atlas_size = m_textures[i]->atlas_size;
2015-05-31 15:48:35 +02:00
}
else
2014-09-28 17:29:39 +02:00
{
2015-05-31 15:48:35 +02:00
path[0] = '\0';
2014-09-28 17:29:39 +02:00
}
2015-05-31 15:48:35 +02:00
serializer.beginObject("texture");
serializer.serialize("source", path);
2015-10-04 14:39:52 +02:00
if (atlas_size > 0) serializer.serialize("atlas_size", atlas_size);
if (flags & BGFX_TEXTURE_SRGB) serializer.serialize("srgb", true);
2015-09-25 23:03:10 +02:00
if (flags & BGFX_TEXTURE_U_CLAMP) serializer.serialize("u_clamp", true);
if (flags & BGFX_TEXTURE_V_CLAMP) serializer.serialize("v_clamp", true);
if (flags & BGFX_TEXTURE_W_CLAMP) serializer.serialize("w_clamp", true);
if (flags & BGFX_TEXTURE_MIN_POINT) serializer.serialize("min_filter", "point");
if (flags & BGFX_TEXTURE_MIN_ANISOTROPIC) serializer.serialize("min_filter", "anisotropic");
if (flags & BGFX_TEXTURE_MAG_POINT) serializer.serialize("mag_filter", "point");
if (flags & BGFX_TEXTURE_MAG_ANISOTROPIC) serializer.serialize("mag_filter", "anisotropic");
if (m_textures[i] && m_textures[i]->getData()) serializer.serialize("keep_data", true);
2014-09-28 17:29:39 +02:00
serializer.endObject();
}
2016-02-08 00:18:19 +01:00
2016-03-14 00:59:28 +01:00
if (m_custom_flags != 0)
{
serializer.beginArray("custom_flags");
for (int i = 0; i < 32; ++i)
{
if (m_custom_flags & (1 << i)) serializer.serializeArrayItem(s_custom_flags.flags[i]);
}
serializer.endArray();
}
2016-02-08 00:18:19 +01:00
serializer.beginArray("defines");
for (int i = 0; i < sizeof(m_define_mask) * 8; ++i)
{
if (m_define_mask & (1 << i)) serializer.serializeArrayItem(renderer.getShaderDefine(i));
}
serializer.endArray();
2014-09-28 17:29:39 +02:00
serializer.beginArray("uniforms");
2016-05-07 12:59:47 +02:00
for (int i = 0; i < m_shader->m_uniforms.size(); ++i)
2014-09-28 17:29:39 +02:00
{
serializer.beginObject();
2016-05-07 12:59:47 +02:00
const auto& uniform = m_shader->m_uniforms[i];
2016-02-09 19:21:00 +01:00
serializer.serialize("name", uniform.name);
switch (uniform.type)
2014-09-28 17:29:39 +02:00
{
2016-02-09 19:21:00 +01:00
case Shader::Uniform::FLOAT:
serializer.serialize("float_value", m_uniforms[i].float_value);
2014-09-28 17:29:39 +02:00
break;
2016-02-09 19:21:00 +01:00
case Shader::Uniform::COLOR:
2016-02-08 23:23:07 +01:00
serializer.beginArray("color");
2016-02-09 19:21:00 +01:00
serializer.serializeArrayItem(m_uniforms[i].vec3[0]);
serializer.serializeArrayItem(m_uniforms[i].vec3[1]);
serializer.serializeArrayItem(m_uniforms[i].vec3[2]);
2016-02-08 23:23:07 +01:00
serializer.endArray();
break;
2016-02-09 19:21:00 +01:00
case Shader::Uniform::VEC3:
2016-02-08 23:23:07 +01:00
serializer.beginArray("vec3");
2016-02-09 19:21:00 +01:00
serializer.serializeArrayItem(m_uniforms[i].vec3[0]);
serializer.serializeArrayItem(m_uniforms[i].vec3[1]);
serializer.serializeArrayItem(m_uniforms[i].vec3[2]);
2016-02-08 23:23:07 +01:00
serializer.endArray();
break;
2016-02-09 19:21:00 +01:00
case Shader::Uniform::TIME:
serializer.serialize("time", 0);
2014-09-28 17:29:39 +02:00
break;
2016-02-09 19:21:00 +01:00
case Shader::Uniform::INT:
serializer.serialize("int_value", m_uniforms[i].int_value);
2014-09-28 17:29:39 +02:00
break;
2016-02-09 19:21:00 +01:00
case Shader::Uniform::MATRIX4:
2014-09-28 17:29:39 +02:00
serializer.beginArray("matrix_value");
for (int j = 0; j < 16; ++j)
{
2016-02-09 19:21:00 +01:00
serializer.serializeArrayItem(m_uniforms[i].matrix[j]);
2014-09-28 17:29:39 +02:00
}
serializer.endArray();
break;
default:
ASSERT(false);
break;
}
serializer.endObject();
2014-06-16 21:18:15 +02:00
}
2014-09-28 17:29:39 +02:00
serializer.endArray();
serializer.serialize("shininess", m_shininess);
serializer.serialize("alpha_ref", m_alpha_ref);
serializer.beginArray("color");
serializer.serializeArrayItem(m_color.x);
serializer.serializeArrayItem(m_color.y);
serializer.serializeArrayItem(m_color.z);
serializer.endArray();
2014-06-16 21:18:15 +02:00
serializer.endObject();
2015-09-25 23:03:10 +02:00
return true;
2014-06-16 21:18:15 +02:00
}
2016-03-14 00:59:28 +01:00
void Material::deserializeCustomFlags(JsonSerializer& serializer)
{
m_custom_flags = 0;
serializer.deserializeArrayBegin();
while (!serializer.isArrayEnd())
{
char tmp[32];
serializer.deserializeArrayItem(tmp, lengthOf(tmp), "");
setCustomFlag(getCustomFlag(tmp));
}
serializer.deserializeArrayEnd();
}
2016-02-08 00:18:19 +01:00
void Material::deserializeDefines(JsonSerializer& serializer)
{
2016-07-25 01:02:36 +02:00
auto& renderer = static_cast<MaterialManager&>(m_resource_manager).getRenderer();
2016-02-08 00:18:19 +01:00
serializer.deserializeArrayBegin();
m_define_mask = 0;
while (!serializer.isArrayEnd())
{
char tmp[32];
serializer.deserializeArrayItem(tmp, lengthOf(tmp), "");
m_define_mask |= 1 << renderer.getShaderDefineIdx(tmp);
}
serializer.deserializeArrayEnd();
}
void Material::deserializeUniforms(JsonSerializer& serializer)
2014-06-16 21:18:15 +02:00
{
serializer.deserializeArrayBegin();
2016-02-09 19:21:00 +01:00
m_uniforms.clear();
2014-06-16 21:18:15 +02:00
while (!serializer.isArrayEnd())
{
2016-01-14 16:22:25 +01:00
Uniform& uniform = m_uniforms.emplace();
2014-06-16 21:18:15 +02:00
serializer.nextArrayItem();
serializer.deserializeObjectBegin();
char label[256];
while (!serializer.isObjectEnd())
{
serializer.deserializeLabel(label, 255);
2016-05-12 09:56:07 +02:00
if (equalStrings(label, "name"))
2014-06-16 21:18:15 +02:00
{
2016-02-09 19:21:00 +01:00
char name[32];
serializer.deserialize(name, lengthOf(name), "");
uniform.name_hash = crc32(name);
2014-06-16 21:18:15 +02:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "int_value"))
2014-06-16 21:18:15 +02:00
{
2016-02-09 19:21:00 +01:00
serializer.deserialize(uniform.int_value, 0);
2014-06-16 21:18:15 +02:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "float_value"))
2014-06-16 21:18:15 +02:00
{
2016-02-09 19:21:00 +01:00
serializer.deserialize(uniform.float_value, 0);
2014-06-16 21:18:15 +02:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "matrix_value"))
2014-06-16 21:18:15 +02:00
{
serializer.deserializeArrayBegin();
for (int i = 0; i < 16; ++i)
{
2016-02-09 19:21:00 +01:00
serializer.deserializeArrayItem(uniform.matrix[i], 0);
2014-06-16 21:18:15 +02:00
}
serializer.deserializeArrayEnd();
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "time"))
2014-06-21 19:26:27 +02:00
{
2016-02-09 19:21:00 +01:00
serializer.deserialize(uniform.float_value, 0);
2014-06-21 19:26:27 +02:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "color"))
2016-02-08 23:23:07 +01:00
{
serializer.deserializeArrayBegin();
2016-02-09 19:21:00 +01:00
serializer.deserializeArrayItem(uniform.vec3[0], 0);
serializer.deserializeArrayItem(uniform.vec3[1], 0);
serializer.deserializeArrayItem(uniform.vec3[2], 0);
2016-02-08 23:23:07 +01:00
serializer.deserializeArrayEnd();
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "vec3"))
2016-02-08 23:23:07 +01:00
{
serializer.deserializeArrayBegin();
2016-02-09 19:21:00 +01:00
serializer.deserializeArrayItem(uniform.vec3[0], 0);
serializer.deserializeArrayItem(uniform.vec3[1], 0);
serializer.deserializeArrayItem(uniform.vec3[2], 0);
2016-02-08 23:23:07 +01:00
serializer.deserializeArrayEnd();
}
2014-06-16 21:18:15 +02:00
else
{
2016-02-13 14:22:18 +01:00
g_log_warning.log("Renderer") << "Unknown label \"" << label << "\"";
2014-06-16 21:18:15 +02:00
}
}
serializer.deserializeObjectEnd();
}
serializer.deserializeArrayEnd();
}
2015-05-28 23:30:50 +02:00
2015-05-31 15:48:35 +02:00
void Material::setTexturePath(int i, const Path& path)
2014-06-16 21:18:15 +02:00
{
2015-05-31 15:48:35 +02:00
if (path.length() == 0)
2014-06-16 21:18:15 +02:00
{
2015-05-31 15:48:35 +02:00
setTexture(i, nullptr);
2014-06-16 21:18:15 +02:00
}
2015-05-31 15:48:35 +02:00
else
2014-09-27 22:15:14 +02:00
{
2016-07-25 01:02:36 +02:00
Texture* texture = static_cast<Texture*>(m_resource_manager.getOwner().get(TEXTURE_TYPE)->load(path));
2015-05-31 15:48:35 +02:00
setTexture(i, texture);
2014-09-27 22:15:14 +02:00
}
2014-12-12 00:48:06 +01:00
}
2014-06-16 21:18:15 +02:00
void Material::setTexture(int i, Texture* texture)
2016-02-10 15:25:28 +01:00
{
2015-06-01 23:35:57 +02:00
Texture* old_texture = i < m_texture_count ? m_textures[i] : nullptr;
if (texture) addDependency(*texture);
2015-05-31 15:48:35 +02:00
m_textures[i] = texture;
if (i >= m_texture_count) m_texture_count = i + 1;
2015-05-28 23:30:50 +02:00
if (old_texture)
{
2016-05-12 12:00:35 +02:00
if (texture) texture->atlas_size = old_texture->atlas_size;
2015-05-28 23:30:50 +02:00
removeDependency(*old_texture);
2016-07-25 01:02:36 +02:00
m_resource_manager.getOwner().get(TEXTURE_TYPE)->unload(*old_texture);
2015-05-28 23:30:50 +02:00
}
2015-09-05 20:54:26 +02:00
if (isReady() && m_shader)
2014-06-16 21:18:15 +02:00
{
2016-05-07 12:59:47 +02:00
int define_idx = m_shader->m_texture_slots[i].define_idx;
2016-02-10 15:25:28 +01:00
if(define_idx >= 0)
2015-09-05 20:54:26 +02:00
{
2016-02-10 15:25:28 +01:00
if(m_textures[i])
{
m_define_mask |= 1 << define_idx;
}
else
{
m_define_mask &= ~(1 << define_idx);
}
2015-09-05 20:54:26 +02:00
}
2016-02-14 21:02:09 +01:00
createCommandBuffer();
2016-02-08 00:57:13 +01:00
m_shader_instance = &m_shader->getInstance(m_define_mask);
2014-06-16 21:18:15 +02:00
}
2014-10-06 23:58:33 +02:00
}
2014-12-12 00:48:06 +01:00
void Material::setShader(const Path& path)
{
2016-07-25 01:02:36 +02:00
Shader* shader = static_cast<Shader*>(m_resource_manager.getOwner().get(SHADER_TYPE)->load(path));
2014-12-12 00:48:06 +01:00
setShader(shader);
}
2016-02-14 16:49:37 +01:00
void Material::createCommandBuffer()
{
if (m_command_buffer != &DEFAULT_COMMAND_BUFFER) m_allocator.deallocate(m_command_buffer);
m_command_buffer = &DEFAULT_COMMAND_BUFFER;
2016-02-14 16:49:37 +01:00
if (!m_shader) return;
CommandBufferGenerator generator;
2016-05-07 12:59:47 +02:00
for (int i = 0; i < m_shader->m_uniforms.size(); ++i)
2016-02-14 16:49:37 +01:00
{
const Material::Uniform& uniform = m_uniforms[i];
2016-05-07 12:59:47 +02:00
const Shader::Uniform& shader_uniform = m_shader->m_uniforms[i];
2016-02-14 16:49:37 +01:00
switch (shader_uniform.type)
{
case Shader::Uniform::FLOAT:
generator.setUniform(shader_uniform.handle, Vec4(uniform.float_value, 0, 0, 0));
break;
case Shader::Uniform::VEC3:
case Shader::Uniform::COLOR:
generator.setUniform(shader_uniform.handle, Vec4(*(Vec3*)uniform.vec3, 0));
break;
case Shader::Uniform::TIME: generator.setTimeUniform(shader_uniform.handle); break;
default: ASSERT(false); break;
}
}
2016-05-07 12:59:47 +02:00
for (int i = 0; i < m_shader->m_texture_slot_count; ++i)
2016-02-14 16:49:37 +01:00
{
if (i >= m_texture_count || !m_textures[i]) continue;
2016-05-12 12:00:35 +02:00
generator.setTexture(i, m_shader->m_texture_slots[i].uniform_handle, m_textures[i]->handle);
2016-02-14 16:49:37 +01:00
}
Vec4 color_shininess(m_color, m_shininess);
2016-07-25 01:02:36 +02:00
auto& renderer = static_cast<MaterialManager&>(m_resource_manager).getRenderer();
2016-02-14 21:02:09 +01:00
auto& uniform = renderer.getMaterialColorShininessUniform();
generator.setUniform(uniform, color_shininess);
2016-02-15 17:10:40 +01:00
generator.end();
2016-02-14 16:49:37 +01:00
m_command_buffer = (uint8*)m_allocator.allocate(generator.getSize());
generator.getData(m_command_buffer);
}
2015-10-03 01:14:38 +02:00
void Material::onBeforeReady()
2015-05-31 15:48:35 +02:00
{
2015-10-03 01:14:38 +02:00
if (!m_shader) return;
2016-02-09 19:21:00 +01:00
2016-05-07 12:59:47 +02:00
for(int i = 0; i < m_shader->m_uniforms.size(); ++i)
2016-02-09 19:21:00 +01:00
{
2016-05-07 12:59:47 +02:00
auto& shader_uniform = m_shader->m_uniforms[i];
2016-02-09 19:21:00 +01:00
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;
}
2016-02-16 20:02:04 +01:00
uint8 alpha_ref = uint8(m_alpha_ref * 255.0f);
m_render_states = (m_render_states & ~BGFX_STATE_ALPHA_REF_MASK) | BGFX_STATE_ALPHA_REF(alpha_ref);
2016-02-17 00:44:42 +01:00
m_render_states |= m_shader->m_render_states;
2016-05-07 12:59:47 +02:00
for(int i = 0; i < m_shader->m_texture_slot_count; ++i)
2016-02-10 15:25:28 +01:00
{
2016-05-07 12:59:47 +02:00
int define_idx = m_shader->m_texture_slots[i].define_idx;
2016-02-10 15:25:28 +01:00
if(define_idx >= 0)
{
if(m_textures[i])
{
m_define_mask |= 1 << define_idx;
}
else
{
m_define_mask &= ~(1 << define_idx);
}
}
}
2016-02-14 16:49:37 +01:00
createCommandBuffer();
2016-02-08 00:57:13 +01:00
m_shader_instance = &m_shader->getInstance(m_define_mask);
2015-05-31 15:48:35 +02:00
}
2014-06-16 21:18:15 +02:00
void Material::setShader(Shader* shader)
{
2016-07-25 01:02:36 +02:00
auto& mat_manager = static_cast<MaterialManager&>(m_resource_manager);
2016-07-25 01:02:36 +02:00
if (m_shader && m_shader != mat_manager.getRenderer().getDefaultShader())
{
Shader* shader = m_shader;
m_shader = nullptr;
removeDependency(*shader);
2016-07-25 01:02:36 +02:00
m_resource_manager.getOwner().get(SHADER_TYPE)->unload(*shader);
2014-06-16 21:18:15 +02:00
}
m_shader = shader;
if (m_shader)
{
addDependency(*m_shader);
2016-02-08 00:18:19 +01:00
if (m_shader->isReady()) onBeforeReady();
2015-05-31 15:48:35 +02:00
}
else
{
2016-07-25 01:02:36 +02:00
m_shader = mat_manager.getRenderer().getDefaultShader();
2016-05-07 12:59:47 +02:00
m_shader_instance = m_shader->m_instances.empty() ? nullptr : m_shader->m_instances[0];
}
2015-05-31 15:48:35 +02:00
}
2015-06-18 01:33:49 +02:00
2015-06-01 23:35:57 +02:00
const char* Material::getTextureUniform(int i)
{
2016-05-07 12:59:47 +02:00
if (i < m_shader->m_texture_slot_count) return m_shader->m_texture_slots[i].uniform;
2015-06-01 23:35:57 +02:00
return "";
}
2015-06-18 01:33:49 +02:00
2015-05-31 15:48:35 +02:00
Texture* Material::getTextureByUniform(const char* uniform) const
{
2015-08-07 02:40:57 +02:00
if (!m_shader)
{
return nullptr;
}
2016-05-07 12:59:47 +02:00
for (int i = 0, c = m_shader->m_texture_slot_count; i < c; ++i)
2015-05-31 15:48:35 +02:00
{
2016-05-12 09:56:07 +02:00
if (equalStrings(m_shader->m_texture_slots[i].uniform, uniform))
2015-05-31 15:48:35 +02:00
{
return m_textures[i];
}
2014-06-16 21:18:15 +02:00
}
2015-05-31 15:48:35 +02:00
return nullptr;
2014-06-16 21:18:15 +02:00
}
bool Material::deserializeTexture(JsonSerializer& serializer, const char* material_dir)
2014-09-27 22:15:14 +02:00
{
char path[MAX_PATH_LENGTH];
2014-09-27 22:15:14 +02:00
serializer.deserializeObjectBegin();
char label[256];
2015-06-01 23:35:57 +02:00
bool keep_data = false;
uint32 flags = 0;
int atlas_size = -1;
2014-09-27 22:15:14 +02:00
while (!serializer.isObjectEnd())
{
serializer.deserializeLabel(label, sizeof(label));
2016-05-12 09:56:07 +02:00
if (equalStrings(label, "source"))
2014-09-27 22:15:14 +02:00
{
serializer.deserialize(path, MAX_PATH_LENGTH, "");
2014-09-27 22:15:14 +02:00
if (path[0] != '\0')
{
char texture_path[MAX_PATH_LENGTH];
if (path[0] != '/' && path[0] != '\\')
{
copyString(texture_path, material_dir);
catString(texture_path, path);
}
else
{
copyString(texture_path, path);
}
2016-07-25 01:02:36 +02:00
auto* mng = m_resource_manager.getOwner().get(TEXTURE_TYPE);
2016-01-05 23:43:12 +01:00
m_textures[m_texture_count] = static_cast<Texture*>(mng->load(Path(texture_path)));
2015-05-31 15:48:35 +02:00
addDependency(*m_textures[m_texture_count]);
2014-09-27 22:15:14 +02:00
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "atlas_size"))
{
serializer.deserialize(atlas_size, -1);
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "min_filter"))
2015-08-20 00:24:04 +02:00
{
serializer.deserialize(label, sizeof(label), "");
2016-05-12 09:56:07 +02:00
if (equalStrings(label, "point"))
2015-08-20 00:24:04 +02:00
{
flags |= BGFX_TEXTURE_MIN_POINT;
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "anisotropic"))
2015-08-20 00:24:04 +02:00
{
flags |= BGFX_TEXTURE_MIN_ANISOTROPIC;
}
else
{
2015-10-03 01:53:04 +02:00
g_log_error.log("Renderer") << "Unknown texture filter \"" << label
2016-01-07 10:03:28 +01:00
<< "\" in material " << getPath();
2015-08-20 00:24:04 +02:00
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "mag_filter"))
2015-08-20 00:24:04 +02:00
{
serializer.deserialize(label, sizeof(label), "");
2016-05-12 09:56:07 +02:00
if (equalStrings(label, "point"))
2015-08-20 00:24:04 +02:00
{
flags |= BGFX_TEXTURE_MAG_POINT;
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "anisotropic"))
2015-08-20 00:24:04 +02:00
{
flags |= BGFX_TEXTURE_MAG_ANISOTROPIC;
}
else
{
2015-10-03 01:53:04 +02:00
g_log_error.log("Renderer") << "Unknown texture filter \"" << label
2016-01-07 10:03:28 +01:00
<< "\" in material " << getPath();
2015-08-20 00:24:04 +02:00
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "u_clamp"))
2015-08-20 00:24:04 +02:00
{
bool b;
serializer.deserialize(b, false);
if (b)
{
flags |= BGFX_TEXTURE_U_CLAMP;
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "v_clamp"))
2015-08-20 00:24:04 +02:00
{
bool b;
serializer.deserialize(b, false);
if (b)
{
flags |= BGFX_TEXTURE_V_CLAMP;
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "w_clamp"))
2015-08-20 00:24:04 +02:00
{
bool b;
serializer.deserialize(b, false);
if (b)
{
flags |= BGFX_TEXTURE_W_CLAMP;
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "keep_data"))
2015-06-01 23:35:57 +02:00
{
serializer.deserialize(keep_data, false);
2015-06-01 23:35:57 +02:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "srgb"))
2016-02-01 20:33:40 +01:00
{
bool is_srgb;
serializer.deserialize(is_srgb, false);
if(is_srgb) flags |= BGFX_TEXTURE_SRGB;
}
2014-09-27 22:15:14 +02:00
else
{
2015-10-03 01:53:04 +02:00
g_log_warning.log("Renderer") << "Unknown data \"" << label << "\" in material "
2016-01-07 10:03:28 +01:00
<< getPath();
2014-09-27 22:15:14 +02:00
return false;
}
}
2015-08-20 00:24:04 +02:00
if (m_textures[m_texture_count])
2015-06-01 23:35:57 +02:00
{
2016-05-12 12:00:35 +02:00
m_textures[m_texture_count]->atlas_size = atlas_size;
2015-08-20 00:24:04 +02:00
m_textures[m_texture_count]->setFlags(flags);
if (keep_data)
{
m_textures[m_texture_count]->addDataReference();
}
2015-06-01 23:35:57 +02:00
}
2014-09-27 22:15:14 +02:00
serializer.deserializeObjectEnd();
2015-05-31 15:48:35 +02:00
++m_texture_count;
2014-09-27 22:15:14 +02:00
return true;
}
2015-06-07 18:17:25 +02:00
void Material::setAlphaRef(float value)
{
m_alpha_ref = value;
uint8 val = uint8(value * 255.0f);
m_render_states &= ~BGFX_STATE_ALPHA_REF_MASK;
m_render_states |= BGFX_STATE_ALPHA_REF(val);
}
2016-06-08 17:31:31 +02:00
void Material::enableBackfaceCulling(bool enable)
{
if (enable)
{
m_render_states |= BGFX_STATE_CULL_CW;
}
else
{
m_render_states &= ~BGFX_STATE_CULL_MASK;
}
}
bool Material::isBackfaceCulling() const
{
return (m_render_states & BGFX_STATE_CULL_MASK) != 0;
}
2015-10-03 01:14:38 +02:00
bool Material::load(FS::IFile& file)
2014-06-16 21:18:15 +02:00
{
PROFILE_FUNCTION();
2015-08-15 09:56:37 +02:00
2016-07-25 01:02:36 +02:00
auto& renderer = static_cast<MaterialManager&>(m_resource_manager).getRenderer();
m_render_states = BGFX_STATE_CULL_CW;
setAlphaRef(DEFAULT_ALPHA_REF_VALUE);
2015-08-15 09:56:37 +02:00
m_uniforms.clear();
2016-01-06 14:18:59 +01:00
JsonSerializer serializer(file, JsonSerializer::READ, getPath(), m_allocator);
2015-08-15 09:56:37 +02:00
serializer.deserializeObjectBegin();
char label[256];
char material_dir[MAX_PATH_LENGTH];
2015-10-03 01:53:04 +02:00
PathUtils::getDir(material_dir, MAX_PATH_LENGTH, getPath().c_str());
2015-08-15 09:56:37 +02:00
while (!serializer.isObjectEnd())
{
serializer.deserializeLabel(label, 255);
2016-05-12 09:56:07 +02:00
if (equalStrings(label, "defines"))
2016-02-08 00:18:19 +01:00
{
deserializeDefines(serializer);
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "custom_flags"))
2016-03-14 00:59:28 +01:00
{
deserializeCustomFlags(serializer);
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "uniforms"))
2014-06-16 21:18:15 +02:00
{
2015-08-15 09:56:37 +02:00
deserializeUniforms(serializer);
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "texture"))
2015-08-15 09:56:37 +02:00
{
if (!deserializeTexture(serializer, material_dir))
2014-06-16 21:18:15 +02:00
{
2015-10-03 01:14:38 +02:00
return false;
2014-06-16 21:18:15 +02:00
}
2015-08-15 09:56:37 +02:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "alpha_ref"))
{
serializer.deserialize(m_alpha_ref, 0.3f);
}
else if (equalStrings(label, "backface_culling"))
{
bool b = true;
serializer.deserialize(b, true);
if (b)
{
m_render_states |= BGFX_STATE_CULL_CW;
}
else
{
m_render_states &= ~BGFX_STATE_CULL_MASK;
}
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "layer"))
2016-02-18 13:17:18 +01:00
{
serializer.deserializeObjectBegin();
int pass = 0;
int layers_count = 1;
while (!serializer.isObjectEnd())
{
serializer.deserializeLabel(label, 255);
2016-05-12 09:56:07 +02:00
if (equalStrings(label, "pass"))
{
char pass_name[50];
serializer.deserialize(pass_name, lengthOf(pass_name), "");
pass = renderer.getPassIdx(pass_name);
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "count"))
{
serializer.deserialize(layers_count, 1);
}
}
m_layer_count[pass] = layers_count;
serializer.deserializeObjectEnd();
2016-02-18 13:17:18 +01:00
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "color"))
2015-08-15 09:56:37 +02:00
{
serializer.deserializeArrayBegin();
serializer.deserializeArrayItem(m_color.x, 1.0f);
serializer.deserializeArrayItem(m_color.y, 1.0f);
serializer.deserializeArrayItem(m_color.z, 1.0f);
2015-08-15 09:56:37 +02:00
serializer.deserializeArrayEnd();
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "shininess"))
2015-08-15 09:56:37 +02:00
{
serializer.deserialize(m_shininess, 4.0f);
}
2016-05-12 09:56:07 +02:00
else if (equalStrings(label, "shader"))
2015-08-15 09:56:37 +02:00
{
2016-01-07 13:33:52 +01:00
Path path;
serializer.deserialize(path, Path(""));
2016-07-25 01:02:36 +02:00
auto* manager = m_resource_manager.getOwner().get(SHADER_TYPE);
2016-01-05 23:43:12 +01:00
setShader(static_cast<Shader*>(manager->load(Path(path))));
2015-08-15 09:56:37 +02:00
}
else
2014-06-16 21:18:15 +02:00
{
g_log_error.log("Renderer") << "Unknown parameter " << label << " in material "
2016-01-07 10:03:28 +01:00
<< getPath();
2014-06-16 21:18:15 +02:00
}
}
2015-08-15 09:56:37 +02:00
serializer.deserializeObjectEnd();
if (!m_shader)
2014-06-16 21:18:15 +02:00
{
2016-02-13 14:22:18 +01:00
g_log_error.log("Renderer") << "Material " << getPath() << " without a shader";
2015-10-03 01:14:38 +02:00
return false;
2014-06-16 21:18:15 +02:00
}
2015-08-15 09:56:37 +02:00
m_size = file.size();
2015-10-03 01:14:38 +02:00
return true;
2014-06-16 21:18:15 +02:00
}
} // ~namespace Lumix