LumixEngine/src/renderer/material.cpp

761 lines
18 KiB
C++
Raw Normal View History

2015-08-17 23:45:26 +02:00
#include "renderer/material.h"
#include "engine/engine.h"
2019-06-11 22:39:39 +02:00
#include "engine/file_system.h"
2022-03-12 00:45:40 +01:00
#include "engine/hash.h"
2016-05-10 08:24:31 +02:00
#include "engine/log.h"
2018-06-30 15:18:27 +02:00
#include "engine/lua_wrapper.h"
2020-02-21 22:09:11 +01:00
#include "engine/path.h"
2016-05-10 08:24:31 +02:00
#include "engine/profiler.h"
#include "engine/resource_manager.h"
2019-06-11 01:09:14 +02:00
#include "engine/stream.h"
2022-11-10 00:33:26 +01:00
#include "renderer/draw_stream.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"
2019-10-24 21:53:19 +02:00
#include "gpu/gpu.h"
2014-06-16 21:18:15 +02:00
namespace Lumix
{
2014-09-07 01:10:24 +02:00
2016-03-14 00:59:28 +01:00
static struct CustomFlags
{
char flags[32][32];
2019-09-10 18:12:05 +02:00
u32 count;
2016-03-14 00:59:28 +01:00
} s_custom_flags = {};
2014-09-07 01:10:24 +02:00
2018-01-11 21:13:59 +01:00
const ResourceType Material::TYPE("material");
Material::Material(const Path& path, ResourceManager& resource_manager, Renderer& renderer, IAllocator& allocator)
2015-09-04 14:00:28 +02:00
: Resource(path, resource_manager, allocator)
, m_shader(nullptr)
, m_uniforms(allocator)
, m_texture_count(0)
2018-07-01 18:13:44 +02:00
, m_renderer(renderer)
2020-11-26 20:25:14 +01:00
, m_render_states(gpu::StateFlags::CULL_BACK)
2016-02-08 00:18:19 +01:00
, m_define_mask(0)
2016-03-14 00:59:28 +01:00
, m_custom_flags(0)
2015-09-04 14:00:28 +02:00
{
2018-10-13 23:24:44 +02:00
static u32 last_sort_key = 0;
m_sort_key = ++last_sort_key;
2018-10-13 15:08:58 +02:00
m_layer = m_renderer.getLayerIdx("default");
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
}
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;
}
void Material::setLayer(u8 layer) {
if (m_layer == layer) return;
m_layer = layer;
refresh();
}
2016-11-20 17:27:41 +01:00
u32 Material::getCustomFlag(const char* flag_name)
2016-03-14 00:59:28 +01:00
{
2019-09-10 18:12:05 +02:00
for (u32 i = 0; i < s_custom_flags.count; ++i)
2016-03-14 00:59:28 +01:00
{
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-11-20 17:27:41 +01:00
bool Material::isDefined(u8 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-11-20 17:27:41 +01:00
void Material::setDefine(u8 define_idx, bool enabled)
2015-09-05 20:54:26 +02:00
{
2019-07-23 00:08:28 +02:00
u32 old_mask = m_define_mask;
2018-07-01 18:13:44 +02:00
if (enabled) {
2016-02-08 00:18:19 +01:00
m_define_mask |= 1 << define_idx;
2015-09-04 14:00:28 +02:00
}
2018-07-01 18:13:44 +02:00
else {
2016-02-08 00:18:19 +01:00
m_define_mask &= ~(1 << define_idx);
2015-09-04 14:00:28 +02:00
}
if (old_mask != m_define_mask) updateRenderData(false);
2014-10-06 23:58:33 +02:00
}
2022-03-12 00:45:40 +01:00
Material::Uniform* Material::findUniform(RuntimeHash name_hash) {
2019-08-12 18:10:01 +02:00
for (Uniform& u : m_uniforms) {
if (u.name_hash == name_hash) return &u;
}
return nullptr;
}
2017-11-28 19:37:15 +01:00
void Material::unload()
2014-06-16 21:18:15 +02:00
{
2016-02-09 19:21:00 +01:00
m_uniforms.clear();
2019-09-10 18:12:05 +02:00
for (u32 i = 0; i < m_texture_count; i++) {
2019-07-23 18:24:13 +02:00
if (m_textures[i]) {
2015-05-31 15:48:35 +02:00
removeDependency(*m_textures[i]);
2020-10-14 21:13:29 +02:00
m_textures[i]->decRefCount();
2015-02-28 13:05:01 +01:00
}
2014-06-16 21:18:15 +02:00
}
2018-07-01 18:13:44 +02:00
m_texture_count = 0;
2022-11-10 00:33:26 +01:00
2022-11-30 21:32:05 +01:00
m_renderer.getEndFrameDrawStream().destroy(m_bind_group);
2022-11-10 00:33:26 +01:00
m_bind_group = gpu::INVALID_BIND_GROUP;
2022-11-08 22:04:52 +01:00
for (Texture*& tex : m_textures) tex = nullptr;
2018-07-01 18:13:44 +02:00
2018-04-19 20:49:20 +02:00
setShader(nullptr);
2017-09-05 22:32:28 +02:00
m_custom_flags = 0;
m_define_mask = 0;
2020-11-26 20:25:14 +01:00
m_render_states = gpu::StateFlags::CULL_BACK;
2014-06-16 21:18:15 +02:00
}
2022-12-06 23:28:08 +01:00
void Material::deserialize(InputMemoryStream& blob) {
unload();
2023-08-06 12:42:31 +02:00
bool res = load(Span((const u8*)blob.getData(), (u32)blob.size()));
2022-12-06 23:28:08 +01:00
ASSERT(res);
}
2014-06-16 21:18:15 +02:00
2022-12-06 23:28:08 +01:00
void Material::serialize(OutputMemoryStream& blob) {
StringView mat_dir = Path::getDir(getPath());
2023-09-19 22:11:02 +02:00
StringView shader_path = m_shader ? m_shader->getPath() : StringView("");
2023-08-08 22:05:37 +02:00
if (startsWith(shader_path, mat_dir)) {
shader_path.removePrefix(mat_dir.size());
blob << "shader \"" << shader_path << "\"\n";
}
else {
blob << "shader \"/" << shader_path << "\"\n";
}
2022-12-06 23:28:08 +01:00
blob << "backface_culling(" << (isBackfaceCulling() ? "true" : "false") << ")\n";
blob << "layer \"" << m_renderer.getLayerName(m_layer) << "\"\n";
2016-02-09 19:21:00 +01:00
2022-12-06 23:28:08 +01:00
blob << "defines {";
2019-09-13 02:15:25 +02:00
bool first_define = true;
2018-08-05 18:00:30 +02:00
for (int i = 0; i < sizeof(m_define_mask) * 8; ++i) {
if ((m_define_mask & (1 << i)) == 0) continue;
2018-10-27 21:05:52 +02:00
const char* def = m_renderer.getShaderDefine(i);
2022-12-06 23:28:08 +01:00
if (!first_define) blob << ", ";
2019-09-13 02:15:25 +02:00
first_define = false;
2022-12-06 23:28:08 +01:00
blob << "\"" << def << "\"";
2018-08-05 18:00:30 +02:00
}
2022-12-06 23:28:08 +01:00
blob << "}\n";
2018-08-05 18:00:30 +02:00
2019-09-10 18:12:05 +02:00
for (u32 i = 0; i < m_texture_count; ++i) {
2018-08-05 18:00:30 +02:00
if (m_textures[i] && m_textures[i] != m_shader->m_texture_slots[i].default_texture) {
StringView texture_path = m_textures[i]->getPath();
if (startsWith(texture_path, mat_dir)) {
2023-08-13 23:53:34 +02:00
texture_path.removePrefix(mat_dir.size());
2023-08-08 22:05:37 +02:00
blob << "texture \"" << texture_path << "\"\n";
}
else {
blob << "texture \"/" << texture_path << "\"\n";
}
2015-05-31 15:48:35 +02:00
}
2018-08-05 18:00:30 +02:00
else {
2022-12-06 23:28:08 +01:00
blob << "texture \"\"\n";
2014-09-28 17:29:39 +02:00
}
}
2016-02-08 00:18:19 +01:00
2019-08-12 18:10:01 +02:00
if (m_custom_flags != 0) {
2016-03-14 00:59:28 +01:00
for (int i = 0; i < 32; ++i)
{
2019-08-12 18:10:01 +02:00
if (m_custom_flags & (1 << i)) {
2022-12-06 23:28:08 +01:00
blob << "custom_flag \"" << s_custom_flags.flags[i] << "\"\n";
2019-08-12 18:10:01 +02:00
}
2016-03-14 00:59:28 +01:00
}
}
2019-08-12 18:10:01 +02:00
2022-12-06 23:28:08 +01:00
auto writeArray = [&blob](const float* value, u32 num) {
blob << "{ ";
2019-08-12 18:10:01 +02:00
for (u32 i = 0; i < num; ++i) {
2022-12-06 23:28:08 +01:00
if (i > 0) blob << ", ";
blob << value[i];
2019-08-12 18:10:01 +02:00
}
2022-12-06 23:28:08 +01:00
blob << " }";
2019-08-12 18:10:01 +02:00
};
2023-09-19 22:11:02 +02:00
if (m_shader) {
for (const Shader::Uniform& su : m_shader->m_uniforms) {
for (const Uniform& mu : m_uniforms) {
if(mu.name_hash == su.name_hash) {
if (su.type == Shader::Uniform::INT) {
blob << "int_uniform(\"" << su.name << "\", " << mu.int_value << ")\n";
}
else {
blob << "uniform(\"" << su.name << "\", ";
switch(su.type) {
case Shader::Uniform::INT: blob << mu.int_value; break;
case Shader::Uniform::NORMALIZED_FLOAT: blob << mu.float_value; break;
case Shader::Uniform::FLOAT: blob << mu.float_value; break;
case Shader::Uniform::COLOR:
case Shader::Uniform::VEC4: writeArray(mu.vec4, 4); break;
case Shader::Uniform::VEC3: writeArray(mu.vec4, 3); break;
case Shader::Uniform::VEC2: writeArray(mu.vec4, 2); break;
}
blob << ")\n";
2021-03-28 12:54:06 +02:00
}
2023-09-19 22:11:02 +02:00
break;
2014-09-28 17:29:39 +02:00
}
2019-08-12 18:10:01 +02:00
}
2014-09-28 17:29:39 +02:00
}
2019-08-12 18:10:01 +02:00
}
2014-06-16 21:18:15 +02:00
}
2019-08-12 18:10:01 +02:00
int Material::uniform(lua_State* L) {
const char* name = LuaWrapper::checkArg<const char*>(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
Uniform u;
2022-03-12 00:45:40 +01:00
u.name_hash = RuntimeHash(name);
2019-08-12 18:10:01 +02:00
switch (lua_type(L, 2)) {
case LUA_TNUMBER: u.float_value = LuaWrapper::toType<float>(L, 2); break;
case LUA_TTABLE: {
const size_t len = lua_objlen(L, 2);
switch (len) {
case 2: *(Vec2*)u.vec2 = LuaWrapper::toType<Vec2>(L, 2); break;
case 3: *(Vec3*)u.vec3 = LuaWrapper::toType<Vec3>(L, 2); break;
case 4: *(Vec4*)u.vec4 = LuaWrapper::toType<Vec4>(L, 2); break;
2019-08-12 18:10:01 +02:00
default: luaL_error(L, "Uniform %s has unsupported type", name); break;
2014-06-16 21:18:15 +02:00
}
2019-08-12 18:10:01 +02:00
break;
}
2019-08-12 18:10:01 +02:00
default: luaL_error(L, "Uniform %s has unsupported type", name); break;
2014-06-16 21:18:15 +02:00
}
2019-08-12 18:10:01 +02:00
material->m_uniforms.push(u);
return 0;
2014-06-16 21:18:15 +02:00
}
2015-05-28 23:30:50 +02:00
2021-03-28 12:54:06 +02:00
int Material::int_uniform(lua_State* L) {
const char* name = LuaWrapper::checkArg<const char*>(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
Uniform u;
2022-03-12 00:45:40 +01:00
u.name_hash = RuntimeHash(name);
2021-03-28 12:54:06 +02:00
switch (lua_type(L, 2)) {
case LUA_TNUMBER: u.int_value = LuaWrapper::toType<i32>(L, 2); break;
default: luaL_error(L, "Uniform %s has unsupported type", name); break;
}
material->m_uniforms.push(u);
return 0;
}
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
{
Texture* texture = m_resource_manager.getOwner().load<Texture>(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
}
2019-09-10 18:12:05 +02:00
void Material::setTexture(u32 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;
2018-08-19 22:01:20 +02:00
if (!texture && m_shader && m_shader->isReady() && m_shader->m_texture_slots[i].default_texture)
2018-04-19 20:49:20 +02:00
{
texture = m_shader->m_texture_slots[i].default_texture;
2020-10-14 21:13:29 +02:00
ASSERT(texture->wantReady());
texture->incRefCount();
2018-04-19 20:49:20 +02:00
}
2019-07-23 18:24:13 +02:00
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;
2019-07-23 18:24:13 +02:00
if (old_texture) {
2015-05-28 23:30:50 +02:00
removeDependency(*old_texture);
2020-10-14 21:13:29 +02:00
old_texture->decRefCount();
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
}
2014-06-16 21:18:15 +02:00
}
updateRenderData(false);
2014-10-06 23:58:33 +02:00
}
2014-12-12 00:48:06 +01:00
void Material::setShader(const Path& path)
{
Shader* shader = m_resource_manager.getOwner().load<Shader>(path);
2014-12-12 00:48:06 +01:00
setShader(shader);
}
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
2021-03-07 19:00:19 +01:00
for (u32 i = 0; i < m_shader->m_texture_slot_count; ++i) {
2019-07-23 18:24:13 +02:00
if (!m_textures[i] && m_shader->m_texture_slots[i].default_texture) {
m_textures[i] = m_shader->m_texture_slots[i].default_texture;
if (i >= m_texture_count) m_texture_count = i + 1;
2020-10-14 21:13:29 +02:00
ASSERT(m_textures[i]->wantReady());
m_textures[i]->incRefCount();
2019-07-23 18:24:13 +02:00
addDependency(*m_textures[i]);
return;
}
}
2021-03-07 19:00:19 +01:00
for (u32 i = 0; i < m_shader->m_texture_slot_count; ++i) {
2018-07-01 18:13:44 +02:00
const int define_idx = m_shader->m_texture_slots[i].define_idx;
2021-03-07 19:00:19 +01:00
if (define_idx >= 0) {
if (m_textures[i]) {
2016-02-10 15:25:28 +01:00
m_define_mask |= 1 << define_idx;
2021-03-07 19:00:19 +01:00
} else {
2016-02-10 15:25:28 +01:00
m_define_mask &= ~(1 << define_idx);
}
}
}
2018-08-19 22:01:20 +02:00
2019-09-10 18:12:05 +02:00
for (u32 i = m_shader->m_texture_slot_count; i < m_texture_count; ++i) {
2018-08-19 22:01:20 +02:00
setTexture(i, nullptr);
}
2019-06-13 17:26:52 +02:00
m_texture_count = minimum(m_texture_count, m_shader->m_texture_slot_count);
2018-10-28 17:38:15 +01:00
2019-06-24 21:17:23 +02:00
updateRenderData(true);
}
void Material::updateRenderData(bool on_before_ready)
{
if (!m_shader) return;
if (!on_before_ready && !isReady()) return;
2022-11-08 22:04:52 +01:00
if (m_material_constants) m_renderer.destroyMaterialConstants(m_material_constants);
2019-06-24 21:17:23 +02:00
2022-10-24 23:27:20 +02:00
float cs[Material::MAX_UNIFORMS_FLOATS] = {};
2019-08-12 18:10:01 +02:00
for (const Shader::Uniform& shader_uniform : m_shader->m_uniforms) {
2021-03-07 19:00:19 +01:00
bool found = false;
const u32 size = shader_uniform.size();
2022-10-24 23:27:20 +02:00
for (Uniform& uniform : m_uniforms) {
if (shader_uniform.name_hash == uniform.name_hash) {
2022-12-15 18:55:52 +01:00
memcpy((u8*)cs + shader_uniform.offset, uniform.vec4, size);
2021-03-07 19:00:19 +01:00
found = true;
2019-08-12 18:10:01 +02:00
break;
}
}
2021-03-07 19:00:19 +01:00
if (!found) {
2022-12-15 18:55:52 +01:00
memcpy((u8*)cs + shader_uniform.offset, shader_uniform.default_value.vec4, size);
2021-03-07 19:00:19 +01:00
}
2019-08-12 18:10:01 +02:00
}
2022-11-08 22:04:52 +01:00
m_material_constants = m_renderer.createMaterialConstants(Span(cs));
2019-08-07 21:21:31 +02:00
DrawStream& stream = m_renderer.getDrawStream();
2022-11-10 00:33:26 +01:00
if (m_bind_group) stream.destroy(m_bind_group);
m_bind_group = gpu::allocBindGroupHandle();
gpu::BindGroupEntryDesc descs[MAX_TEXTURE_COUNT + 1];
2019-09-10 18:12:05 +02:00
for(u32 i = 0; i < m_texture_count; ++i) {
2022-11-10 00:33:26 +01:00
descs[i].texture = m_textures[i] ? m_textures[i]->handle : gpu::INVALID_TEXTURE;
descs[i].type = gpu::BindGroupEntryDesc::TEXTURE;
descs[i].bind_point = i;
2018-10-28 17:38:15 +01:00
}
2022-11-10 00:33:26 +01:00
descs[m_texture_count].type = gpu::BindGroupEntryDesc::UNIFORM_BUFFER;
descs[m_texture_count].buffer = m_renderer.getMaterialUniformBuffer();
descs[m_texture_count].size = MAX_UNIFORMS_BYTES;
descs[m_texture_count].offset = m_material_constants * MAX_UNIFORMS_BYTES;
descs[m_texture_count].bind_point = UniformBuffer::MATERIAL;
stream.createBindGroup(m_bind_group, Span(descs, m_texture_count + 1));
2015-05-31 15:48:35 +02:00
}
2014-06-16 21:18:15 +02:00
void Material::setShader(Shader* shader)
{
2018-07-01 18:13:44 +02:00
if (m_shader) {
Shader* shader = m_shader;
m_shader = nullptr;
removeDependency(*shader);
2020-10-14 21:13:29 +02:00
shader->decRefCount();
2014-06-16 21:18:15 +02:00
}
m_shader = shader;
2018-07-01 18:13:44 +02:00
if (m_shader) {
2014-06-16 21:18:15 +02:00
addDependency(*m_shader);
2015-05-31 15:48:35 +02:00
}
updateRenderData(false);
2015-05-31 15:48:35 +02:00
}
2015-06-18 01:33:49 +02:00
Texture* Material::getTextureByName(const char* name) const
2015-05-31 15:48:35 +02:00
{
2016-08-04 20:53:20 +02:00
if (!m_shader) return nullptr;
2015-08-07 02:40:57 +02:00
2018-07-01 18:13:44 +02:00
for (int i = 0, c = m_shader->m_texture_slot_count; i < c; ++i) {
if (equalStrings(m_shader->m_texture_slots[i].name, name)) {
2015-05-31 15:48:35 +02:00
return m_textures[i];
}
2018-07-01 18:13:44 +02:00
}
2015-05-31 15:48:35 +02:00
return nullptr;
2014-06-16 21:18:15 +02:00
}
2016-08-04 20:53:20 +02:00
2016-11-20 17:27:41 +01:00
bool Material::isTextureDefine(u8 define_idx) const
2016-08-04 20:53:20 +02:00
{
if (!m_shader) return false;
2018-07-01 18:13:44 +02:00
for (int i = 0, c = m_shader->m_texture_slot_count; i < c; ++i) {
if (m_shader->m_texture_slots[i].define_idx == define_idx) {
2016-08-04 20:53:20 +02:00
return true;
}
2014-09-27 22:15:14 +02:00
}
2018-07-01 18:13:44 +02:00
return false;
2014-09-27 22:15:14 +02:00
}
2015-06-07 18:17:25 +02:00
2016-06-08 17:31:31 +02:00
void Material::enableBackfaceCulling(bool enable)
{
2018-07-15 17:35:41 +02:00
if (enable) {
2020-11-26 20:25:14 +01:00
m_render_states = m_render_states | gpu::StateFlags::CULL_BACK;
2018-07-15 17:35:41 +02:00
}
else {
2020-11-26 20:25:14 +01:00
m_render_states = m_render_states & ~gpu::StateFlags::CULL_BACK;
2016-06-08 17:31:31 +02:00
}
}
bool Material::isBackfaceCulling() const
{
2020-11-26 20:25:14 +01:00
return u64(m_render_states & gpu::StateFlags::CULL_BACK);
2018-06-30 15:18:27 +02:00
}
namespace LuaAPI
{
2018-10-13 15:08:58 +02:00
int layer(lua_State* L)
{
const char* layer_name = LuaWrapper::checkArg<const char*>(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2019-12-20 19:25:33 +01:00
const u8 layer = material->getRenderer().getLayerIdx(layer_name);
2018-10-13 15:08:58 +02:00
material->setLayer(layer);
return 0;
}
2018-08-05 18:00:30 +02:00
int roughness(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2023-08-08 22:05:37 +02:00
logWarning(material->getPath(), ": roughness deprecated");
2018-08-05 18:00:30 +02:00
return 0;
}
2018-08-22 19:52:08 +02:00
int alpha_ref(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2021-03-27 16:55:13 +01:00
logWarning(material->getPath(), ": alpha_ref deprecated");
2018-08-22 19:52:08 +02:00
return 0;
}
2018-09-09 15:31:09 +02:00
int backface_culling(lua_State* L)
{
const bool enable = LuaWrapper::checkArg<bool>(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
material->enableBackfaceCulling(enable);
return 0;
}
2018-08-22 19:52:08 +02:00
int color(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2023-08-08 22:05:37 +02:00
logWarning(material->getPath(), ": color deprecated");
2022-10-24 23:27:20 +02:00
2018-08-22 19:52:08 +02:00
return 0;
}
int custom_flag(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
const char* flag_name = LuaWrapper::checkArg<const char*>(L, 1);
const u32 flag = material->getCustomFlag(flag_name);
material->setCustomFlag(flag);
return 0;
}
2018-08-05 18:00:30 +02:00
int metallic(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2023-08-08 22:05:37 +02:00
logWarning(material->getPath(), ": metallic deprecated");
2018-08-05 18:00:30 +02:00
return 0;
}
2018-08-22 19:52:08 +02:00
int emission(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2023-08-08 22:05:37 +02:00
logWarning(material->getPath(), ": emission deprecated");
2018-08-22 19:52:08 +02:00
return 0;
}
2021-02-06 22:17:03 +01:00
int translucency(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2023-08-08 22:05:37 +02:00
logWarning(material->getPath(), ": translucency deprecated");
2021-02-06 22:17:03 +01:00
return 0;
}
2018-07-01 18:13:44 +02:00
int defines(lua_State* L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2018-11-11 13:46:42 +01:00
LuaWrapper::forEachArrayItem<const char*>(L, 1, "array of strings expected", [&](const char* v){
material->setDefine(material->getRenderer().getShaderDefineIdx(v), true);
});
2018-07-01 18:13:44 +02:00
return 0;
}
2018-06-30 15:18:27 +02:00
int shader(lua_State* L)
{
const char* path = LuaWrapper::checkArg<const char*>(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
if (!path[0]) material->setShader(nullptr);
else {
char c = path[0];
if (c != '\\' && c != '/') {
2023-08-08 22:05:37 +02:00
StringView material_dir = Path::getDir(material->getPath());
Path fullpath(material_dir, path);
material->setShader(fullpath);
}
else {
2023-09-13 19:47:53 +02:00
material->setShader(Path(path + 1));
}
}
2018-06-30 15:18:27 +02:00
return 0;
}
2023-08-08 22:05:37 +02:00
int texture(lua_State* L) {
2018-06-30 15:18:27 +02:00
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Material* material = (Material*)lua_touserdata(L, -1);
lua_pop(L, 1);
2023-08-08 22:05:37 +02:00
StringView material_dir = Path::getDir(material->getPath());
2018-07-05 15:54:14 +02:00
if (lua_istable(L, 1)) {
lua_getfield(L, 1, "source");
if (lua_isstring(L, -1)) {
const char* path = lua_tostring(L, -1);
const int idx = material->getTextureCount();
2018-07-11 23:35:34 +02:00
2023-08-08 22:05:37 +02:00
Path texture_path;
2023-09-13 19:47:53 +02:00
if (path[0] == '\0') {
texture_path = path;
}
else if (path[0] != '/' && path[0] != '\\') {
2023-08-08 22:05:37 +02:00
texture_path = material_dir;
texture_path.append(path);
2018-07-11 23:35:34 +02:00
}
2023-08-08 22:05:37 +02:00
else {
2023-09-13 19:47:53 +02:00
texture_path = path + 1;
2018-07-11 23:35:34 +02:00
}
2023-08-08 22:05:37 +02:00
material->setTexturePath(idx, texture_path);
2018-07-05 15:54:14 +02:00
}
else {
logError(material->getPath(), " texture's source is not a string.");
2018-07-05 15:54:14 +02:00
lua_pop(L, 1);
return 0;
}
lua_pop(L, 1);
2018-07-22 15:22:36 +02:00
Texture* texture = material->getTexture(material->getTextureCount() - 1);
bool keep_data = false;
LuaWrapper::getOptionalField(L, 1, "keep_data", &keep_data);
if (keep_data) texture->addDataReference();
2018-07-05 15:54:14 +02:00
return 0;
}
const char* path = LuaWrapper::checkArg<const char*>(L, 1);
2018-06-30 15:18:27 +02:00
const int idx = material->getTextureCount();
2018-07-11 23:35:34 +02:00
2023-08-08 22:05:37 +02:00
Path texture_path;
2023-09-13 19:47:53 +02:00
if (path[0] == '\0') {
texture_path = path;
}
else if (path[0] != '/' && path[0] != '\\') {
2023-08-08 22:05:37 +02:00
texture_path.append(material_dir, path);
2018-07-11 23:35:34 +02:00
}
2023-08-08 22:05:37 +02:00
else {
2023-09-13 19:47:53 +02:00
texture_path = path + 1;
2018-07-11 23:35:34 +02:00
}
2023-08-08 22:05:37 +02:00
material->setTexturePath(idx, texture_path);
2018-06-30 15:18:27 +02:00
return 0;
2016-06-08 17:31:31 +02:00
}
2018-06-30 15:18:27 +02:00
} // namespace LuaAPI
bool Material::wireframe() const {
return u32(m_render_states & gpu::StateFlags::WIREFRAME);
}
void Material::setWireframe(bool enable) {
if (enable) m_render_states = m_render_states | gpu::StateFlags::WIREFRAME;
else m_render_states = m_render_states & ~gpu::StateFlags::WIREFRAME;
}
2018-06-30 15:18:27 +02:00
2023-08-06 12:42:31 +02:00
bool Material::load(Span<const u8> mem) {
PROFILE_FUNCTION();
2015-08-15 09:56:37 +02:00
MaterialManager& mng = static_cast<MaterialManager&>(getResourceManager());
lua_State* L = mng.getState(*this);
2018-06-30 15:18:27 +02:00
2019-08-12 18:10:01 +02:00
m_uniforms.clear();
2020-11-26 20:25:14 +01:00
m_render_states = gpu::StateFlags::CULL_BACK;
m_custom_flags = 0;
StringView content((const char*)mem.begin(), (u32)mem.length());
if (!LuaWrapper::execute(L, content, getPath().c_str(), 0)) {
return false;
}
if (!m_shader) {
logError("Material ", getPath(), " does not have a shader.");
return false;
}
return true;
}
lua_State* MaterialManager::getState(Material& material) const {
lua_pushlightuserdata(m_state, &material);
lua_setfield(m_state, LUA_GLOBALSINDEX, "this");
return m_state;
}
MaterialManager::~MaterialManager() {
lua_close(m_state);
}
MaterialManager::MaterialManager(Renderer& renderer, IAllocator& allocator)
: ResourceManager(allocator)
, m_renderer(renderer)
{
m_state = luaL_newstate();
2018-08-22 19:52:08 +02:00
#define DEFINE_LUA_FUNC(func) \
2023-09-07 20:28:39 +02:00
lua_pushcfunction(m_state, LuaAPI::func, #func); \
lua_setfield(m_state, LUA_GLOBALSINDEX, #func);
2018-08-22 19:52:08 +02:00
2018-10-13 15:08:58 +02:00
DEFINE_LUA_FUNC(alpha_ref);
DEFINE_LUA_FUNC(backface_culling);
DEFINE_LUA_FUNC(color);
DEFINE_LUA_FUNC(custom_flag);
2018-08-22 19:52:08 +02:00
DEFINE_LUA_FUNC(defines);
DEFINE_LUA_FUNC(emission);
2021-02-06 22:17:03 +01:00
DEFINE_LUA_FUNC(translucency);
2018-10-13 15:08:58 +02:00
DEFINE_LUA_FUNC(layer);
DEFINE_LUA_FUNC(metallic);
DEFINE_LUA_FUNC(roughness);
DEFINE_LUA_FUNC(shader);
DEFINE_LUA_FUNC(texture);
2019-08-12 18:10:01 +02:00
2023-09-07 20:28:39 +02:00
lua_pushcfunction(m_state, &Material::uniform, "uniform");
lua_setfield(m_state, LUA_GLOBALSINDEX, "uniform");
2019-08-12 18:10:01 +02:00
2023-09-07 20:28:39 +02:00
lua_pushcfunction(m_state, &Material::int_uniform, "int_uniform");
2021-03-28 12:54:06 +02:00
lua_setfield(m_state, LUA_GLOBALSINDEX, "int_uniform");
2018-08-22 19:52:08 +02:00
#undef DEFINE_LUA_FUNC
}
2015-08-15 09:56:37 +02:00
Resource* MaterialManager::createResource(const Path& path) {
return LUMIX_NEW(m_allocator, Material)(path, *this, m_renderer, m_allocator);
2014-06-16 21:18:15 +02:00
}
void MaterialManager::destroyResource(Resource& resource) {
LUMIX_DELETE(m_allocator, &resource);
};
2014-06-16 21:18:15 +02:00
2018-02-12 17:02:10 +01:00
} // namespace Lumix