alpha cutout; create resources from asset browser

This commit is contained in:
Mikulas Florek 2019-07-18 18:34:52 +02:00
parent 849c0939ed
commit 01dc91985c
14 changed files with 135 additions and 96 deletions

View file

@ -20,6 +20,8 @@ texture_slot {
include "pipelines/common.glsl"
define "ALPHA_CUTOUT"
------------------
vertex_shader [[

View file

@ -93,26 +93,23 @@ struct PropertyAnimationAssetBrowserPlugin : AssetBrowser::IPlugin
app.getAssetCompiler().registerExtension("anp", PropertyAnimation::TYPE);
}
bool canCreateResource() const override { return true; }
const char* getFileDialogFilter() const override { return "Property animation\0*.anp\0"; }
const char* getFileDialogExtensions() const override { return "anp"; }
const char* getDefaultExtension() const override { return "anp"; }
bool createResource(char* out, int max_size) override
bool createResource(const char* path) override
{
char full_path[MAX_PATH_LENGTH];
if (!OS::getSaveFilename(full_path, lengthOf(full_path), "Property animation\0*.anp\0", "anp")) return false;
OS::OutputFile file;
WorldEditor& editor = m_app.getWorldEditor();
if (!file.open(full_path))
if (!file.open(path))
{
logError("Animation") << "Failed to create " << full_path;
logError("Animation") << "Failed to create " << path;
return false;
}
file << "[]";
file.close();
editor.makeRelative(out, max_size, full_path);
return true;
}

View file

@ -339,6 +339,12 @@ void AssetBrowser::fileColumn()
{
selectResource(Path(tile.filepath), true);
}
/*
if (ImGui::BeginPopupContextItem("item_context")) {
ImGui::Selectable("Delete");
ImGui::EndMenu();
}*/
// TODO
};
while (clipper.Step())
@ -369,6 +375,28 @@ void AssetBrowser::fileColumn()
}
}
ImGui::EndChild();
if (ImGui::BeginPopupContextItem("context")) {
const char* base_path = m_editor.getEngine().getFileSystem().getBasePath();
for (IPlugin* plugin : m_plugins) {
if (!plugin->canCreateResource()) continue;
if (ImGui::BeginMenu(plugin->getName())) {
static char tmp[MAX_PATH_LENGTH];
ImGui::InputText("Name", tmp, sizeof(tmp));
if (ImGui::Button("Create")) {
StaticString<MAX_PATH_LENGTH> rel_path(m_dir, "/", tmp, ".", plugin->getDefaultExtension());
StaticString<MAX_PATH_LENGTH> full_path(base_path, rel_path);
plugin->createResource(full_path);
changeDir(m_dir);
m_wanted_resource = rel_path;
ImGui::CloseCurrentPopup();
}
ImGui::EndMenu();
}
}
ImGui::EndPopup();
}
}
@ -586,7 +614,7 @@ bool AssetBrowser::resourceInput(const char* label, const char* str_id, char* bu
ImGui::PopID();
return true;
}
if (resourceList(buf, max_size, type, 0))
if (resourceList(buf, max_size, type, 0, true))
{
ImGui::EndPopup();
ImGui::PopID();
@ -641,19 +669,19 @@ void AssetBrowser::endSaveResource(Resource& resource, OutputMemoryStream& strea
}
bool AssetBrowser::resourceList(char* buf, int max_size, ResourceType type, float height) const
bool AssetBrowser::resourceList(char* buf, int max_size, ResourceType type, float height, bool can_create_new) const
{
auto iter = m_plugins.find(type);
if (!iter.isValid()) return false;
IPlugin* plugin = iter.value();
if (plugin->canCreateResource() && ImGui::Selectable("New"))
{
char path[MAX_PATH_LENGTH];
if (plugin->createResource(path, lengthOf(path)))
{
copyString(buf, max_size, path);
return true;
if (can_create_new && plugin->canCreateResource() && ImGui::Selectable("New")) {
char full_path[MAX_PATH_LENGTH];
if (OS::getSaveFilename(full_path, lengthOf(full_path), plugin->getFileDialogFilter(), plugin->getFileDialogExtensions())) {
if (plugin->createResource(full_path)) {
m_editor.makeRelative(buf, max_size, full_path);
return true;
}
}
}

View file

@ -28,7 +28,12 @@ public:
virtual ~IPlugin() {}
virtual bool canCreateResource() const { return false; }
virtual bool createResource(char* out_path, int max_size) { return false; }
virtual bool createResource(const char* path) { return false; }
virtual const char* getFileDialogFilter() const { return ""; }
virtual const char* getFileDialogExtensions() const { return ""; }
virtual const char* getDefaultExtension() const { return ""; }
virtual void onGUI(Resource* resource) = 0;
virtual void onResourceUnloaded(Resource* resource) = 0;
virtual const char* getName() const = 0;
@ -51,7 +56,7 @@ public:
void removePlugin(IPlugin& plugin);
void openInExternalEditor(Resource* resource) const;
void openInExternalEditor(const char* path) const;
bool resourceList(char* buf, int max_size, ResourceType type, float height) const;
bool resourceList(char* buf, int max_size, ResourceType type, float height, bool can_create_new) const;
OutputMemoryStream* beginSaveResource(Resource& resource);
void endSaveResource(Resource& resource, OutputMemoryStream& file, bool success);

View file

@ -512,7 +512,7 @@ public:
if (!ImGui::BeginMenu(last)) return;
char buf[MAX_PATH_LENGTH];
bool create_empty = ImGui::MenuItem("Empty");
if (asset_browser->resourceList(buf, lengthOf(buf), resource_type, 0) || create_empty)
if (asset_browser->resourceList(buf, lengthOf(buf), resource_type, 0, true) || create_empty)
{
if (create_entity)
{

View file

@ -46,26 +46,21 @@ struct SpritePlugin final : public AssetBrowser::IPlugin
app.getAssetCompiler().registerExtension("spr", Sprite::TYPE);
}
bool canCreateResource() const override { return true; }
const char* getFileDialogFilter() const { return "Sprite\0*.spr\0"; }
const char* getFileDialogExtensions() const { return "spr"; }
const char* getDefaultExtension() const override { return "spr"; }
bool createResource(char* out, int max_size) override
{
char full_path[MAX_PATH_LENGTH];
if (!OS::getSaveFilename(full_path, lengthOf(full_path), "Sprite\0*.spr\0", "spr")) return false;
bool createResource(const char* path) override {
OS::OutputFile file;
WorldEditor& editor = app.getWorldEditor();
if (!file.open(full_path))
{
logError("GUI") << "Failed to create " << full_path;
if (!file.open(path)) {
logError("GUI") << "Failed to create " << path;
return false;
}
file << "{ \"type\" : \"simple\" }";
file.close();
editor.makeRelative(out, max_size, full_path);
return true;
}

View file

@ -784,7 +784,7 @@ struct AddComponentPlugin final : public StudioApp::IAddComponentPlugin
}
bool create_empty = ImGui::Selectable("Empty", false);
if (asset_browser.resourceList(buf, lengthOf(buf), LuaScript::TYPE, 0) || create_empty || new_created)
if (asset_browser.resourceList(buf, lengthOf(buf), LuaScript::TYPE, 0, false) || create_empty || new_created)
{
WorldEditor& editor = app.getWorldEditor();
if (create_entity)

View file

@ -206,6 +206,23 @@ struct MaterialPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
app.getAssetCompiler().registerExtension("mat", Material::TYPE);
}
bool canCreateResource() const override { return true; }
const char* getFileDialogFilter() const override { return "Material\0*.mat\0"; }
const char* getFileDialogExtensions() const override { return "mat"; }
const char* getDefaultExtension() const override { return "mat"; }
bool createResource(const char* path) override {
OS::OutputFile file;
WorldEditor& editor = m_app.getWorldEditor();
if (!file.open(path)) {
logError("Renderer") << "Failed to create " << path;
return false;
}
file << "shader \"/pipelines/standard.shd\"";
file.close();
return true;
}
bool compile(const Path& src) override
{
@ -233,9 +250,7 @@ struct MaterialPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
}
}
void onGUI(Resource* resource) override
{
void onGUI(Resource* resource) override {
Material* material = static_cast<Material*>(resource);
if (ImGui::Button("Open in external editor")) m_app.getAssetBrowser().openInExternalEditor(material);
if (!material->isReady()) return;
@ -251,49 +266,43 @@ struct MaterialPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
bool b = material->isBackfaceCulling();
if (ImGui::Checkbox("Backface culling", &b)) material->enableBackfaceCulling(b);
/*if (material->hasDefine(alpha_cutout_define))
if (material->getShader()
&& material->getShader()->isReady()
&& material->getShader()->hasDefine(alpha_cutout_define))
{
b = material->isDefined(alpha_cutout_define);
if (ImGui::Checkbox("Is alpha cutout", &b)) material->setDefine(alpha_cutout_define, b);
if (b)
{
if (b) {
float tmp = material->getAlphaRef();
if (ImGui::DragFloat("Alpha reference value", &tmp, 0.01f, 0.0f, 1.0f))
{
if (ImGui::DragFloat("Alpha reference value", &tmp, 0.01f, 0.0f, 1.0f)) {
material->setAlphaRef(tmp);
}
}
}*/
// TODO
}
Vec4 color = material->getColor();
if (ImGui::ColorEdit4("Color", &color.x))
{
if (ImGui::ColorEdit4("Color", &color.x)) {
material->setColor(color);
}
float roughness = material->getRoughness();
if (ImGui::DragFloat("Roughness", &roughness, 0.01f, 0.0f, 1.0f))
{
if (ImGui::DragFloat("Roughness", &roughness, 0.01f, 0.0f, 1.0f)) {
material->setRoughness(roughness);
}
float metallic = material->getMetallic();
if (ImGui::DragFloat("Metallic", &metallic, 0.01f, 0.0f, 1.0f))
{
if (ImGui::DragFloat("Metallic", &metallic, 0.01f, 0.0f, 1.0f)) {
material->setMetallic(metallic);
}
float emission = material->getEmission();
if (ImGui::DragFloat("Emission", &emission, 0.01f, 0.0f))
{
if (ImGui::DragFloat("Emission", &emission, 0.01f, 0.0f)) {
material->setEmission(emission);
}
char buf[MAX_PATH_LENGTH];
copyString(buf, material->getShader() ? material->getShader()->getPath().c_str() : "");
if (m_app.getAssetBrowser().resourceInput("Shader", "shader", buf, sizeof(buf), Shader::TYPE))
{
if (m_app.getAssetBrowser().resourceInput("Shader", "shader", buf, sizeof(buf), Shader::TYPE)) {
material->setShader(Path(buf));
}
@ -308,8 +317,7 @@ struct MaterialPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
ImGui::EndCombo();
}
for (int i = 0; i < material->getShader()->m_texture_slot_count; ++i)
{
for (int i = 0; material->getShader() && i < material->getShader()->m_texture_slot_count; ++i) {
auto& slot = material->getShader()->m_texture_slots[i];
Texture* texture = material->getTexture(i);
copyString(buf, texture ? texture->getPath().c_str() : "");
@ -328,8 +336,7 @@ struct MaterialPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
{
material->setTexturePath(i, Path(buf));
}
if (!texture && is_node_open)
{
if (!texture && is_node_open) {
ImGui::TreePop();
continue;
}
@ -367,8 +374,7 @@ struct MaterialPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin
}
}
auto* shader = material->getShader();
if (shader && material->isReady())
if (material->getShader() && material->isReady())
{
// TODO
/*
@ -2841,7 +2847,7 @@ struct AddTerrainComponentPlugin final : public StudioApp::IAddComponentPlugin
ImGui::EndMenu();
}
bool create_empty = ImGui::Selectable("Empty", false);
if (asset_browser.resourceList(buf, lengthOf(buf), Material::TYPE, 0) || create_empty || new_created)
if (asset_browser.resourceList(buf, lengthOf(buf), Material::TYPE, 0, false) || create_empty || new_created)
{
if (create_entity)
{

View file

@ -108,6 +108,7 @@ void Material::setDefine(u8 define_idx, bool enabled)
else {
m_define_mask &= ~(1 << define_idx);
}
updateRenderData(false);
}
@ -161,12 +162,13 @@ bool Material::save(IOutputStream& file)
file << "metallic(" << tmp << ")\n";
toCString(m_roughness, tmp, lengthOf(tmp), 9);
file << "roughness(" << tmp << ")\n";
toCString(m_alpha_ref, tmp, lengthOf(tmp), 2);
file << "alpha_ref(" << tmp << ")\n";
file << "defines {";
for (int i = 0; i < sizeof(m_define_mask) * 8; ++i) {
if ((m_define_mask & (1 << i)) == 0) continue;
const char* def = m_renderer.getShaderDefine(i);
if (equalStrings("SKINNED", def)) continue;
if (i > 0) file << ", ";
file << "\"" << def << "\"";
}
@ -279,7 +281,6 @@ bool Material::save(IOutputStream& file)
}
serializer.endArray();
serializer.serialize("emission", m_emission);
serializer.serialize("alpha_ref", m_alpha_ref);
serializer.beginArray("color");
serializer.serializeArrayItem(m_color.x);
serializer.serializeArrayItem(m_color.y);
@ -496,6 +497,7 @@ void Material::updateRenderData(bool on_before_ready)
m_render_data->color = m_color;
m_render_data->emission = m_emission;
m_render_data->metallic = m_metallic;
m_render_data->define_mask = m_define_mask;
m_render_data->render_states = m_render_states;
m_render_data->roughness = m_roughness;
m_render_data->shader = m_shader->m_render_data;

View file

@ -34,6 +34,7 @@ public:
float metallic;
float emission;
ShaderRenderData* shader;
u32 define_mask;
};
struct Uniform

View file

@ -2125,13 +2125,11 @@ struct PipelineImpl final : Pipeline
READ(const u16, instances_count);
READ(const ffr::BufferHandle, buffer);
READ(const uint, offset);
const uint size = instances_count * instance_decl.size;
ShaderRenderData* shader = material->shader;
ffr::bindTextures(material->textures, 0, material->textures_count);
const ffr::ProgramHandle prog = Shader::getProgram(shader, instanced_mask);
const ffr::ProgramHandle prog = Shader::getProgram(shader, instanced_mask | material->define_mask);
if(prog.isValid()) {
ffr::bindTextures(material->textures, 0, material->textures_count);
ffr::setState(material->render_states | render_states);
const Vec4 params(material->roughness, material->metallic, material->emission, 0);
ffr::setUniform4f(m_pipeline->m_material_params_uniform, &params.x);
@ -2168,7 +2166,7 @@ struct PipelineImpl final : Pipeline
ShaderRenderData* shader = material->shader;
ffr::bindTextures(material->textures, 0, material->textures_count);
const ffr::ProgramHandle prog = Shader::getProgram(shader, skinned_mask);
const ffr::ProgramHandle prog = Shader::getProgram(shader, skinned_mask | material->define_mask);
if(prog.isValid()) {
ffr::setState(material->render_states | render_states);
const Vec4 params(material->roughness, material->metallic, material->emission, 0);
@ -2200,7 +2198,7 @@ struct PipelineImpl final : Pipeline
ShaderRenderData* shader = material->shader;
ffr::bindTextures(material->textures, 0, material->textures_count);
const ffr::ProgramHandle prog = Shader::getProgram(shader, m_define_mask);
const ffr::ProgramHandle prog = Shader::getProgram(shader, m_define_mask | material->define_mask);
if (prog.isValid()) {
ffr::useProgram(prog);
ffr::setState(material->render_states | render_states);
@ -2231,7 +2229,7 @@ struct PipelineImpl final : Pipeline
const u32 deferred_define_mask = 1 << m_pipeline->m_renderer.getShaderDefineIdx("DEFERRED");
const u32 define_mask = (1 << m_pipeline->m_renderer.getShaderDefineIdx("GRASS")) | deferred_define_mask;
const ffr::ProgramHandle prg = Shader::getProgram(material->shader, define_mask);
const ffr::ProgramHandle prg = Shader::getProgram(material->shader, define_mask | material->define_mask);
if (prg.isValid()) {
ffr::bindTextures(material->textures, 0, material->textures_count);
ffr::bindVAO(mesh->vao);
@ -2419,7 +2417,7 @@ struct PipelineImpl final : Pipeline
ffr::setUniform3f(m_pipeline->m_position_uniform, &pos.x);
ffr::setUniform3f(m_pipeline->m_rel_camera_pos_uniform, &lpos.x);
ffr::bindTextures(inst.material->textures, 0, inst.material->textures_count);
ffr::bindTextures(inst.material->textures, 0, inst.material->textures_count | inst.material->define_mask);
ffr::setState(state);
const int loc = ffr::getUniformLocation(p, m_pipeline->m_lod_uniform);

View file

@ -30,6 +30,7 @@ Shader::Shader(const Path& path, ResourceManager& resource_manager, Renderer& re
, m_render_states(0)
, m_all_defines_mask(0)
, m_render_data(nullptr)
, m_defines(m_allocator)
{
}
@ -39,6 +40,9 @@ Shader::~Shader()
ASSERT(isEmpty());
}
bool Shader::hasDefine(u8 define) const {
return m_defines.indexOf(define) >= 0;
}
const ffr::ProgramHandle& Shader::getProgram(ShaderRenderData* rd, u32 defines)
{
@ -201,32 +205,25 @@ static void uniform(lua_State* L, const char* name, const char* type)
}
static void alpha_blending(lua_State* L, const char* mode)
{
// TODO
ASSERT(false);
/*
Shader* shader = getShader(L);
if (!shader) return;
if (equalStrings(mode, "add"))
{
shader->m_render_states |= BGFX_STATE_BLEND_ADD;
}
else if (equalStrings(mode, "alpha"))
{
shader->m_render_states |= BGFX_STATE_BLEND_ALPHA;
}
else
{
logError("Renderer") << "Uknown blend mode " << mode << " in " << shader->getPath().c_str();
}*/
}
namespace LuaAPI
{
int define(lua_State* L)
{
const char* def = LuaWrapper::checkArg<const char*>(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "this");
Shader* shader = (Shader*)lua_touserdata(L, -1);
lua_pop(L, 1);
const u8 def_idx = shader->m_renderer.getShaderDefineIdx(def);
shader->m_defines.push(def_idx);
return 0;
}
int texture_slot(lua_State* L)
{
LuaWrapper::checkTableArg(L, 1);
@ -405,6 +402,8 @@ bool Shader::load(u64 size, const u8* mem)
lua_setfield(L, LUA_GLOBALSINDEX, "include");
lua_pushcclosure(L, LuaAPI::texture_slot, 0);
lua_setfield(L, LUA_GLOBALSINDEX, "texture_slot");
lua_pushcclosure(L, LuaAPI::define, 0);
lua_setfield(L, LUA_GLOBALSINDEX, "define");
lua_pushinteger(L, (int)Mesh::AttributeSemantic::POSITION);
lua_setglobal(L, "SEMANTICS_POSITION");
@ -438,9 +437,6 @@ bool Shader::load(u64 size, const u8* mem)
m_size = size;
lua_close(L);
return true;
// TODO
//m_render_states = BGFX_STATE_DEPTH_TEST_GEQUAL;
}

View file

@ -73,6 +73,7 @@ public:
~Shader();
ResourceType getType() const override { return TYPE; }
bool hasDefine(u8 define) const;
static const ffr::ProgramHandle& getProgram(ShaderRenderData* rd, u32 defines);
@ -83,6 +84,7 @@ public:
TextureSlot m_texture_slots[MAX_TEXTURE_SLOT_COUNT];
int m_texture_slot_count;
Array<Uniform> m_uniforms;
Array<u8> m_defines;
static const ResourceType TYPE;

View file

@ -574,7 +574,14 @@ bool Texture::loadTGA(IInputStream& file)
bytes_per_pixel = 4;
mips = 1;
if (data_reference) mem = renderer.copy(image_dest, image_size);
handle = renderer.createTexture(header.width, header.height, 1, ffr::TextureFormat::RGBA8, getFFRFlags(), mem, getPath().c_str());
const bool is_srgb = flags & (u32)ffr::TextureFlags::SRGB;
handle = renderer.createTexture(header.width
, header.height
, 1
, is_srgb ? ffr::TextureFormat::SRGBA : ffr::TextureFormat::RGBA8
, getFFRFlags() & ~(u32)ffr::TextureFlags::SRGB
, mem
, getPath().c_str());
depth = 1;
layers = 1;
return handle.isValid();