improved editing of materials
This commit is contained in:
parent
cb28c53a0a
commit
240ed44ed8
11 changed files with 300 additions and 124 deletions
|
@ -238,6 +238,7 @@
|
|||
<ClCompile Include="..\..\..\tmp\studio\moc_profilergraph.cpp" />
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_profilerui.cpp" />
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_property_view.cpp" />
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_resource_model.cpp" />
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_sceneview.cpp" />
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_scriptcompiler.cpp" />
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_scriptcompilerwidget.cpp" />
|
||||
|
@ -318,7 +319,20 @@
|
|||
<ClInclude Include="..\..\..\src\studio\file_path_edit.h" />
|
||||
<ClInclude Include="..\..\..\src\studio\metadata.h" />
|
||||
<ClInclude Include="..\..\..\src\studio\property_view\dynamic_object_model.h" />
|
||||
<ClInclude Include="..\..\..\src\studio\property_view\resource_model.h" />
|
||||
<CustomBuild Include="..\..\..\src\studio\property_view\resource_model.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='AppVeyor|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='AppVeyor|Win32'">Moc%27ing resource_model.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='AppVeyor|Win32'">.\..\..\..\tmp\studio\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='AppVeyor|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\..\..\..\tmp\studio\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_OPENGL_ES_2 -DQT_OPENGL_ES_2_ANGLE -DNDEBUG -DQT_DLL "-I.\..\.." "-I.\..\..\..\src\studio" "-I.\..\..\..\src" "-I.\..\..\..\external\crunch\include" "-I.\..\..\..\external\assimp\include" "-I.\..\..\..\external\glew\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\mkspecs\win32-msvc2013" "-I.\..\..\..\tmp\studio" "-I.\..\..\..\tmp\studio\GeneratedFiles"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing resource_model.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\..\..\..\tmp\studio\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\..\..\..\tmp\studio\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_OPENGL_ES_2 -DQT_OPENGL_ES_2_ANGLE -DQT_DLL "-I.\..\.." "-I.\..\..\..\src\studio" "-I.\..\..\..\src" "-I.\..\..\..\external\crunch\include" "-I.\..\..\..\external\assimp\include" "-I.\..\..\..\external\glew\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2013" "-I.\..\..\..\tmp\studio" "-I.\..\..\..\tmp\studio\GeneratedFiles"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing resource_model.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\..\..\..\tmp\studio\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\..\..\..\tmp\studio\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_OPENGL_ES_2 -DQT_OPENGL_ES_2_ANGLE -DNDEBUG -DQT_DLL "-I.\..\.." "-I.\..\..\..\src\studio" "-I.\..\..\..\src" "-I.\..\..\..\external\crunch\include" "-I.\..\..\..\external\assimp\include" "-I.\..\..\..\external\glew\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtOpenGL" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\mkspecs\win32-msvc2013" "-I.\..\..\..\tmp\studio" "-I.\..\..\..\tmp\studio\GeneratedFiles"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="..\..\..\tmp\studio\GeneratedFiles\ui_assetbrowser.h" />
|
||||
<ClInclude Include="..\..\..\tmp\studio\GeneratedFiles\ui_entity_list.h" />
|
||||
<ClInclude Include="..\..\..\tmp\studio\GeneratedFiles\ui_entity_template_list.h" />
|
||||
|
|
|
@ -202,6 +202,9 @@
|
|||
<ClCompile Include="..\..\..\src\studio\metadata.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tmp\studio\moc_resource_model.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\..\src\studio\assetbrowser.h">
|
||||
|
@ -300,6 +303,9 @@
|
|||
<CustomBuild Include="..\..\..\src\studio\notifications.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\..\src\studio\property_view\resource_model.h">
|
||||
<Filter>Header Files\property_view</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\studio\file_system_watcher.h">
|
||||
|
@ -365,9 +371,6 @@
|
|||
<ClInclude Include="..\..\..\src\studio\animation_editor\animation_editor_commands.h">
|
||||
<Filter>Header Files\animation_editor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\studio\property_view\resource_model.h">
|
||||
<Filter>Header Files\property_view</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\studio\property_view\dynamic_object_model.h">
|
||||
<Filter>Header Files\property_view</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace Lumix
|
|||
void Resource::addDependency(Resource& dependent_resource)
|
||||
{
|
||||
dependent_resource.m_cb.bind<Resource, &Resource::onStateChanged>(this);
|
||||
if (!dependent_resource.isReady())
|
||||
if (!dependent_resource.isReady() && !dependent_resource.isFailure())
|
||||
{
|
||||
incrementDepCount();
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ namespace Lumix
|
|||
void Resource::removeDependency(Resource& dependent_resource)
|
||||
{
|
||||
dependent_resource.m_cb.unbind<Resource, &Resource::onStateChanged>(this);
|
||||
if (!dependent_resource.isReady() && !dependent_resource.isFailure())
|
||||
if (!dependent_resource.isReady())
|
||||
{
|
||||
decrementDepCount();
|
||||
}
|
||||
|
|
|
@ -54,7 +54,12 @@ void Material::apply(Renderer& renderer, PipelineInstance& pipeline) const
|
|||
}
|
||||
for (int i = 0, c = m_textures.size(); i < c; ++i)
|
||||
{
|
||||
m_textures[i].m_texture->apply(i);
|
||||
const TextureInfo& info = m_textures[i];
|
||||
info.m_texture->apply(i);
|
||||
if (info.m_uniform_hash)
|
||||
{
|
||||
renderer.setUniform(*m_shader, m_textures[i].m_uniform, info.m_uniform_hash, i);
|
||||
}
|
||||
}
|
||||
renderer.enableAlphaToCoverage(m_is_alpha_to_coverage);
|
||||
renderer.enableZTest(m_is_z_test);
|
||||
|
@ -122,7 +127,7 @@ void Material::doUnload(void)
|
|||
bool Material::save(JsonSerializer& serializer)
|
||||
{
|
||||
serializer.beginObject();
|
||||
serializer.serialize("shader", m_shader->getPath().c_str());
|
||||
serializer.serialize("shader", m_shader ? m_shader->getPath().c_str() : "");
|
||||
for (int i = 0; i < m_textures.size(); ++i)
|
||||
{
|
||||
char path[LUMIX_MAX_PATH];
|
||||
|
@ -141,7 +146,6 @@ bool Material::save(JsonSerializer& serializer)
|
|||
{
|
||||
serializer.beginObject();
|
||||
serializer.serialize("name", m_uniforms[i].m_name);
|
||||
serializer.serialize("is_editable", m_uniforms[i].m_is_editable);
|
||||
switch (m_uniforms[i].m_type)
|
||||
{
|
||||
case Uniform::FLOAT:
|
||||
|
@ -190,11 +194,7 @@ void Material::deserializeUniforms(JsonSerializer& serializer)
|
|||
while (!serializer.isObjectEnd())
|
||||
{
|
||||
serializer.deserializeLabel(label, 255);
|
||||
if (strcmp(label, "is_editable") == 0)
|
||||
{
|
||||
serializer.deserialize(uniform.m_is_editable, false);
|
||||
}
|
||||
else if (strcmp(label, "name") == 0)
|
||||
if (strcmp(label, "name") == 0)
|
||||
{
|
||||
serializer.deserialize(uniform.m_name, Uniform::MAX_NAME_LENGTH, "");
|
||||
uniform.m_name_hash = crc32(uniform.m_name);
|
||||
|
@ -235,6 +235,7 @@ void Material::deserializeUniforms(JsonSerializer& serializer)
|
|||
serializer.deserializeArrayEnd();
|
||||
}
|
||||
|
||||
|
||||
void Material::removeTexture(int i)
|
||||
{
|
||||
if (m_textures[i].m_texture)
|
||||
|
@ -245,6 +246,14 @@ void Material::removeTexture(int i)
|
|||
m_textures.erase(i);
|
||||
}
|
||||
|
||||
|
||||
void Material::setTextureUniform(int index, const char* uniform)
|
||||
{
|
||||
copyString(m_textures[index].m_uniform, sizeof(m_textures[index].m_uniform), uniform);
|
||||
m_textures[index].m_uniform_hash = crc32(uniform);
|
||||
}
|
||||
|
||||
|
||||
Texture* Material::getTextureByUniform(const char* uniform) const
|
||||
{
|
||||
for (int i = 0; i < m_textures.size(); ++i)
|
||||
|
@ -267,16 +276,17 @@ void Material::setTexturePath(int i, const Path& path)
|
|||
|
||||
void Material::setTexture(int i, Texture* texture)
|
||||
{
|
||||
if (m_textures[i].m_texture)
|
||||
{
|
||||
removeDependency(*m_textures[i].m_texture);
|
||||
m_resource_manager.get(ResourceManager::TEXTURE)->unload(*m_textures[i].m_texture);
|
||||
}
|
||||
Texture* old_texture = m_textures[i].m_texture;
|
||||
if (texture)
|
||||
{
|
||||
addDependency(*texture);
|
||||
}
|
||||
m_textures[i].m_texture = texture;
|
||||
if (old_texture)
|
||||
{
|
||||
removeDependency(*old_texture);
|
||||
m_resource_manager.get(ResourceManager::TEXTURE)->unload(*old_texture);
|
||||
}
|
||||
}
|
||||
|
||||
void Material::addTexture(Texture* texture)
|
||||
|
@ -355,12 +365,8 @@ bool Material::deserializeTexture(JsonSerializer& serializer, const char* materi
|
|||
}
|
||||
else if (strcmp("uniform", label) == 0)
|
||||
{
|
||||
Uniform& uniform = m_uniforms.pushEmpty();
|
||||
serializer.deserialize(uniform.m_name, Uniform::MAX_NAME_LENGTH, "");
|
||||
copyString(info.m_uniform, sizeof(info.m_uniform), uniform.m_name);
|
||||
uniform.m_name_hash = crc32(uniform.m_name);
|
||||
uniform.m_type = Uniform::INT;
|
||||
uniform.m_int = info.m_texture ? m_textures.size() - 1 : m_textures.size();
|
||||
serializer.deserialize(label, sizeof(label), "");
|
||||
setTextureUniform(m_textures.size() - 1, label);
|
||||
}
|
||||
else if (strcmp("keep_data", label) == 0)
|
||||
{
|
||||
|
@ -394,6 +400,7 @@ void Material::loaded(FS::IFile* file, bool success, FS::FileSystem& fs)
|
|||
PROFILE_FUNCTION();
|
||||
if(success)
|
||||
{
|
||||
m_uniforms.clear();
|
||||
JsonSerializer serializer(*file, JsonSerializer::READ, m_path.c_str(), m_allocator);
|
||||
serializer.deserializeObjectBegin();
|
||||
char path[LUMIX_MAX_PATH];
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
struct Uniform
|
||||
{
|
||||
Uniform() : m_is_editable(false) {}
|
||||
Uniform() {}
|
||||
|
||||
enum Type
|
||||
{
|
||||
|
@ -54,7 +54,6 @@ public:
|
|||
float m_float;
|
||||
float m_matrix[16];
|
||||
};
|
||||
bool m_is_editable;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -79,6 +78,8 @@ public:
|
|||
int getTextureCount() const { return m_textures.size(); }
|
||||
Texture* getTexture(int i) const { return m_textures[i].m_texture; }
|
||||
Texture* getTextureByUniform(const char* uniform) const;
|
||||
void setTextureUniform(int i, const char* uniform);
|
||||
const char* getTextureUniform(int i) const { return m_textures[i].m_uniform; }
|
||||
void addTexture(Texture* texture);
|
||||
void setTexture(int i, Texture* texture);
|
||||
void setTexturePath(int i, const Path& path);
|
||||
|
@ -121,10 +122,12 @@ private:
|
|||
m_texture = NULL;
|
||||
m_keep_data = false;
|
||||
m_uniform[0] = '\0';
|
||||
m_uniform_hash = 0;
|
||||
}
|
||||
|
||||
Texture* m_texture;
|
||||
bool m_keep_data;
|
||||
uint32_t m_uniform_hash;
|
||||
char m_uniform[Uniform::MAX_NAME_LENGTH];
|
||||
};
|
||||
|
||||
|
|
|
@ -874,11 +874,14 @@ namespace Lumix
|
|||
m_allocator.deleteObject(m_root);
|
||||
m_heightmap = m_material->getTextureByUniform("hm_texture");
|
||||
m_splatmap = m_material->getTextureByUniform("splat_texture");
|
||||
if (m_heightmap && m_splatmap)
|
||||
{
|
||||
m_width = m_heightmap->getWidth();
|
||||
m_height = m_heightmap->getHeight();
|
||||
m_root = generateQuadTree((float)m_width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Lumix
|
|
@ -405,6 +405,7 @@ void AssetBrowser::on_treeView_customContextMenuRequested(const QPoint &pos)
|
|||
QAction* delete_file_action = new QAction("Delete", menu);
|
||||
QAction* rename_file_action = new QAction("Rename", menu);
|
||||
QAction* create_dir_action = new QAction("Create directory", menu);
|
||||
QAction* create_material_action = new QAction("Create material", menu);
|
||||
QAction* import_asset_action = new QAction("Import asset", menu);
|
||||
QAction* reimport_asset_action = new QAction("Reimport asset", menu);
|
||||
|
||||
|
@ -414,6 +415,7 @@ void AssetBrowser::on_treeView_customContextMenuRequested(const QPoint &pos)
|
|||
{
|
||||
menu->addAction(import_asset_action);
|
||||
menu->addAction(create_dir_action);
|
||||
menu->addAction(create_material_action);
|
||||
}
|
||||
|
||||
char relative_path[LUMIX_MAX_PATH];
|
||||
|
@ -468,6 +470,20 @@ void AssetBrowser::on_treeView_customContextMenuRequested(const QPoint &pos)
|
|||
QDir().mkdir(file_info.absoluteFilePath() + "/" + text);
|
||||
}
|
||||
}
|
||||
else if (selected_action == create_material_action)
|
||||
{
|
||||
auto material_name = QInputDialog::getText(nullptr, "Set filename", "Filename", QLineEdit::Normal, ".mat");
|
||||
auto path = file_info.absoluteFilePath() + "/" + material_name;
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QMessageBox::warning(nullptr, "Error", QString("Could not create file %1").arg(path), QMessageBox::StandardButton::Ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetBrowser::setExtentionsFilter(const QStringList& filters)
|
||||
|
|
|
@ -67,6 +67,10 @@ void PropertyView::setSelectedResourceFilename(const char* filename)
|
|||
{
|
||||
m_world_editor->selectEntities(NULL, 0);
|
||||
ResourceModel* model = new ResourceModel(*m_world_editor, Lumix::Path(filename));
|
||||
connect(model, &ResourceModel::modelReady, [this]()
|
||||
{
|
||||
m_ui->treeView->expandToDepth(1);
|
||||
});
|
||||
if (model->getResource())
|
||||
{
|
||||
setModel(model, new DynamicObjectItemDelegate(this));
|
||||
|
|
|
@ -77,29 +77,6 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
class Object
|
||||
{
|
||||
public:
|
||||
class ArrayProperty
|
||||
{
|
||||
public:
|
||||
ArrayProperty(Node* node, int index)
|
||||
: m_node(node)
|
||||
, m_index(index)
|
||||
{}
|
||||
|
||||
|
||||
template <typename Callback>
|
||||
void onClick(Callback callback)
|
||||
{
|
||||
for (int i = 0; i < m_node->m_children.size(); ++i)
|
||||
{
|
||||
Node* node = m_node->m_children[i]->m_children[m_index];
|
||||
node->onClick = [i, callback](QWidget* widget, QPoint p) { callback(i, widget, p); };
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Node* m_node;
|
||||
int m_index;
|
||||
};
|
||||
|
||||
template <typename Getter, typename Namer>
|
||||
class Array
|
||||
|
@ -118,20 +95,31 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Getter>
|
||||
typename IsFunctor<Getter, Array>::type property(QString name, Getter getter)
|
||||
template <typename Functor, typename Adder>
|
||||
Array<Getter, Namer>& forEach(Functor functor, Adder adder)
|
||||
{
|
||||
for (int i = 0; i < m_node->m_children.size(); ++i)
|
||||
auto array_node = m_node;
|
||||
auto parent = m_parent;
|
||||
auto getter = m_getter;
|
||||
m_node->onCreateEditor = [=](QWidget* parent_widget, const QStyleOptionViewItem&) -> QWidget* {
|
||||
auto button = new QPushButton(" + ", parent_widget);
|
||||
button->connect(button, &QPushButton::clicked, [=](){
|
||||
if (adder())
|
||||
{
|
||||
Node& node = m_node->m_children[i]->addChild(name);
|
||||
auto o = (m_parent->*m_getter)(i);
|
||||
node.m_getter = [getter, o]() -> QVariant { return (getter)(o); };
|
||||
int i = array_node->m_children.size();
|
||||
Node& child = array_node->addChild(QString("%1").arg(i));
|
||||
auto o = (parent->*getter)(i);
|
||||
functor(i, o, child);
|
||||
}
|
||||
return *this;
|
||||
});
|
||||
return button;
|
||||
};
|
||||
m_node->m_setter = [](const QVariant&) {};
|
||||
return forEach(functor);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void forEach(Functor functor)
|
||||
Array<Getter, Namer>& forEach(Functor functor)
|
||||
{
|
||||
for (int i = 0; i < m_node->m_children.size(); ++i)
|
||||
{
|
||||
|
@ -139,24 +127,9 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
Node& node = *m_node->m_children[i];
|
||||
functor(i, o, node);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Getter>
|
||||
typename IsNotFunctor<Getter, Array>::type property(QString name, Getter getter)
|
||||
{
|
||||
for (int i = 0; i < m_node->m_children.size(); ++i)
|
||||
{
|
||||
Node& node = m_node->m_children[i]->addChild(name);
|
||||
auto o = (m_parent->*m_getter)(i);
|
||||
node.m_getter = [getter, o]() -> QVariant { return (o->*getter)(); };
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArrayProperty back() {
|
||||
return ArrayProperty(m_node, m_node->m_children[0]->m_children.size() - 1);
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_parent;
|
||||
Node* m_node;
|
||||
|
@ -181,7 +154,7 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
}
|
||||
|
||||
template <typename Getter, typename Setter>
|
||||
typename IsFunctor<Getter, Object>::type property(QString name, Getter getter, Setter setter)
|
||||
Object& property(QString name, Getter getter, Setter setter)
|
||||
{
|
||||
Node& node = m_node->addChild(name);
|
||||
T* inst = m_instance;
|
||||
|
@ -193,7 +166,7 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
}
|
||||
|
||||
template <typename Getter>
|
||||
typename IsFunctor<Getter, Object>::type property(QString name, Getter getter)
|
||||
typename IsFunctor<Getter, Object&>::type property(QString name, Getter getter)
|
||||
{
|
||||
Node& node = m_node->addChild(name);
|
||||
T* inst = m_instance;
|
||||
|
@ -202,7 +175,7 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
}
|
||||
|
||||
template <typename Getter>
|
||||
typename IsNotFunctor<Getter, Object>::type property(QString name, Getter getter)
|
||||
typename IsNotFunctor<Getter, Object&>::type property(QString name, Getter getter)
|
||||
{
|
||||
Node& node = m_node->addChild(name);
|
||||
T* inst = m_instance;
|
||||
|
@ -215,6 +188,12 @@ class DynamicObjectModel : public QAbstractItemModel
|
|||
{
|
||||
Node& node = m_node->addChild(name);
|
||||
node.m_getter = []() -> QVariant { return ""; };
|
||||
/*node.onCreateEditor = [adder, this](QWidget* parent, const QStyleOptionViewItem&) -> QWidget* {
|
||||
auto button = new QPushButton(" + ", parent);
|
||||
connect(button, &QPushButton::clicked, adder);
|
||||
return button;
|
||||
};
|
||||
node.m_setter = [](const QVariant&) {};*/
|
||||
|
||||
return Array<Getter, Namer>(m_instance, count, &node, getter, namer);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,52 @@
|
|||
#include <qapplication.h>
|
||||
#include <qfile.h>
|
||||
#include <qfiledialog.h>
|
||||
#include <qlayout.h>
|
||||
#include <qlineedit.h>
|
||||
#include <qpainter.h>
|
||||
#include <qpushbutton.h>
|
||||
|
||||
|
||||
FileInput::FileInput(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
m_edit = new QLineEdit(this);
|
||||
layout->addWidget(m_edit);
|
||||
QPushButton* browse_button = new QPushButton("...", this);
|
||||
layout->addWidget(browse_button);
|
||||
connect(browse_button, &QPushButton::clicked, this, &FileInput::browseClicked);
|
||||
connect(m_edit, &QLineEdit::editingFinished, this, &FileInput::editingFinished);
|
||||
}
|
||||
|
||||
|
||||
void FileInput::editingFinished()
|
||||
{
|
||||
setValue(m_edit->text());
|
||||
}
|
||||
|
||||
|
||||
void FileInput::setValue(const QString& path)
|
||||
{
|
||||
m_edit->setText(path);
|
||||
emit valueChanged();
|
||||
}
|
||||
|
||||
|
||||
QString FileInput::value() const
|
||||
{
|
||||
return m_edit->text();
|
||||
}
|
||||
|
||||
|
||||
void FileInput::browseClicked()
|
||||
{
|
||||
auto path = QFileDialog::getOpenFileName(this);
|
||||
setValue(path);
|
||||
}
|
||||
|
||||
|
||||
static QSize getPreviewSize(Lumix::Texture* texture)
|
||||
{
|
||||
int w = texture->getWidth();
|
||||
|
@ -91,12 +133,9 @@ void ResourceModel::fillModelInfo()
|
|||
.property("Bone count", &Lumix::Model::getBoneCount)
|
||||
.property("Bounding radius", &Lumix::Model::getBoundingRadius);
|
||||
auto meshes = object.array("Meshes", model->getMeshCount(), &Lumix::Model::getMeshPtr, [](const Lumix::Mesh* mesh) -> const char* { return mesh->getName(); });
|
||||
meshes.property("Triangles", &Lumix::Mesh::getTriangleCount);
|
||||
/*meshes.property("Material", [](const Lumix::Mesh* mesh) -> const char* { return mesh->getMaterial()->getPath().c_str(); });
|
||||
meshes.back().onClick([this, model](int index, QWidget*, QPoint) {
|
||||
setResource(model->getMesh(index).getMaterial()->getPath());
|
||||
});*/
|
||||
meshes.forEach([this](int, const Lumix::Mesh* mesh, Node& node){
|
||||
Object<Lumix::Mesh>((Lumix::Mesh*)mesh, &node)
|
||||
.property("Triangles", &Lumix::Mesh::getTriangleCount);
|
||||
fillMaterialInfo(mesh->getMaterial(), node.addChild("material"));
|
||||
});
|
||||
}
|
||||
|
@ -140,7 +179,7 @@ void ResourceModel::saveMaterial(Lumix::Material* material)
|
|||
}
|
||||
|
||||
|
||||
void ResourceModel::showFileDialog(DynamicObjectModel::Node* node, QString filter)
|
||||
void ResourceModel::showFileDialog(const DynamicObjectModel::Node* node, QString filter)
|
||||
{
|
||||
auto fileName = QFileDialog::getOpenFileName(NULL, "Select file", "", filter);
|
||||
if (!fileName.isEmpty())
|
||||
|
@ -159,6 +198,52 @@ void ResourceModel::setMaterialShader(Lumix::Material* material, QString value)
|
|||
}
|
||||
|
||||
|
||||
class BaseEditorProperty
|
||||
{
|
||||
public:
|
||||
BaseEditorProperty();
|
||||
virtual ~BaseEditorProperty();
|
||||
|
||||
virtual int childCount() const { return m_children.size(); }
|
||||
virtual void addChild(BaseEditorProperty* child);
|
||||
virtual void removeChild(int index);
|
||||
virtual QVariant getValue() const = 0;
|
||||
virtual BaseEditorProperty* getParent() const { return m_parent; }
|
||||
|
||||
private:
|
||||
BaseEditorProperty* m_parent;
|
||||
QVector<BaseEditorProperty*> m_children;
|
||||
};
|
||||
|
||||
|
||||
BaseEditorProperty::BaseEditorProperty()
|
||||
: m_parent(nullptr)
|
||||
{}
|
||||
|
||||
|
||||
BaseEditorProperty::~BaseEditorProperty()
|
||||
{
|
||||
for (auto child : m_children)
|
||||
{
|
||||
delete child;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BaseEditorProperty::addChild(BaseEditorProperty* child)
|
||||
{
|
||||
child->m_parent = this;
|
||||
m_children.append(child);
|
||||
}
|
||||
|
||||
|
||||
void BaseEditorProperty::removeChild(int index)
|
||||
{
|
||||
delete m_children[index];
|
||||
m_children.removeAt(index);
|
||||
}
|
||||
|
||||
|
||||
void ResourceModel::fillMaterialInfo(Lumix::Material* material, Node& node)
|
||||
{
|
||||
auto object = Object<Lumix::Material>(material, &node);
|
||||
|
@ -181,7 +266,7 @@ void ResourceModel::fillMaterialInfo(Lumix::Material* material, Node& node)
|
|||
.property("Shadow receiver", &Lumix::Material::isShadowReceiver, &Lumix::Material::enableShadowReceiving)
|
||||
.property("Z test", &Lumix::Material::isZTest, &Lumix::Material::enableZTest)
|
||||
.property("Shader",
|
||||
[](Lumix::Material* material) -> QVariant { return material->getShader()->getPath().c_str(); },
|
||||
[](Lumix::Material* material) -> QVariant { return material->getShader() ? material->getShader()->getPath().c_str() : ""; },
|
||||
[this](Lumix::Material* material, QVariant value) { setMaterialShader(material, value.toString()); }
|
||||
);
|
||||
auto shader_node = object.getNode().m_children.back();
|
||||
|
@ -190,8 +275,6 @@ void ResourceModel::fillMaterialInfo(Lumix::Material* material, Node& node)
|
|||
for (int i = 0; i < material->getUniformCount(); ++i)
|
||||
{
|
||||
auto& uniform = material->getUniform(i);
|
||||
if (uniform.m_is_editable)
|
||||
{
|
||||
QString name = uniform.m_name;
|
||||
object.property(uniform.m_name
|
||||
, [name](Lumix::Material* material) -> QVariant {
|
||||
|
@ -220,13 +303,41 @@ void ResourceModel::fillMaterialInfo(Lumix::Material* material, Node& node)
|
|||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
.array("Textures", material->getTextureCount(), &Lumix::Material::getTexture, [](Lumix::Texture* texture) -> const char* { return texture->getPath().c_str(); })
|
||||
.forEach([this](int i, Lumix::Texture* texture, Node& node) {
|
||||
.array("Textures", material->getTextureCount(), &Lumix::Material::getTexture,
|
||||
[](Lumix::Texture* texture) -> const char* { return texture->getPath().c_str(); }
|
||||
)
|
||||
.forEach([this, material](int i, Lumix::Texture* texture, Node& node) {
|
||||
fillTextureInfo(texture, node);
|
||||
Object<Lumix::Texture>(texture, &node)
|
||||
.property("uniform"
|
||||
, [material, i](Lumix::Texture*) -> QVariant { return material->getTextureUniform(i); }
|
||||
, [material, i](Lumix::Texture*, QVariant value) { material->setTextureUniform(i, value.toString().toLatin1().data()); }
|
||||
);
|
||||
node.m_name = QString("Texture %1").arg(i);
|
||||
node.onCreateEditor = [&node, i, texture, material](QWidget* parent, const QStyleOptionViewItem&) -> QWidget* {
|
||||
auto input = new FileInput(parent);
|
||||
input->setValue(texture->getPath().c_str());
|
||||
input->connect(input, &FileInput::valueChanged, [&node, input]() {
|
||||
node.m_setter(input->value());
|
||||
});
|
||||
return input;
|
||||
};
|
||||
node.m_setter = [material, i](const QVariant& value) {
|
||||
if (value.isValid())
|
||||
{
|
||||
material->setTexturePath(i, Lumix::Path(value.toString().toLatin1().data()));
|
||||
}
|
||||
};
|
||||
//node.onClick = [node, this](QWidget*, QPoint) { showFileDialog(&node, "Textures (*.dds|*.tga)"); };
|
||||
}
|
||||
, [material]() {
|
||||
auto texture = static_cast<Lumix::Texture*>(material->getResourceManager().get(Lumix::ResourceManager::TEXTURE)->load(Lumix::Path("texture.dds")));
|
||||
material->addTexture(texture);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -253,13 +364,20 @@ void ResourceModel::fillTextureInfo(Lumix::Texture* texture, Node& node)
|
|||
|
||||
void ResourceModel::onResourceLoaded(Lumix::Resource::State, Lumix::Resource::State new_state)
|
||||
{
|
||||
beginResetModel();
|
||||
/*
|
||||
endResetModel closes any opened property editor, if this is done in the end of this method
|
||||
it can result in a crash, since the editor can access some destroyed node
|
||||
*/
|
||||
endResetModel();
|
||||
beginResetModel();
|
||||
for (int i = 0; i < getRoot().m_children.size(); ++i)
|
||||
{
|
||||
delete getRoot().m_children[i];
|
||||
}
|
||||
getRoot().m_children.clear();
|
||||
if (new_state == Lumix::Resource::State::READY)
|
||||
this->getRoot().m_getter = [new_state]() -> QVariant { return new_state == Lumix::Resource::State::LOADING ? "Loading..." : "Ready"; };
|
||||
if (new_state == Lumix::Resource::State::READY || new_state == Lumix::Resource::State::FAILURE)
|
||||
{
|
||||
if (dynamic_cast<Lumix::Model*>(m_resource))
|
||||
{
|
||||
|
@ -279,4 +397,8 @@ void ResourceModel::onResourceLoaded(Lumix::Resource::State, Lumix::Resource::St
|
|||
}
|
||||
}
|
||||
endResetModel();
|
||||
if (new_state == Lumix::Resource::State::READY || new_state == Lumix::Resource::State::FAILURE)
|
||||
{
|
||||
emit modelReady();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,30 @@ namespace Lumix
|
|||
}
|
||||
|
||||
|
||||
|
||||
class FileInput : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FileInput(QWidget* parent);
|
||||
void setValue(const QString& path);
|
||||
QString value() const;
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
private:
|
||||
void editingFinished();
|
||||
void browseClicked();
|
||||
|
||||
private:
|
||||
QLineEdit* m_edit;
|
||||
};
|
||||
|
||||
|
||||
class ResourceModel : public DynamicObjectModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ResourceModel(Lumix::WorldEditor& editor, const Lumix::Path& path);
|
||||
~ResourceModel();
|
||||
|
@ -23,13 +45,16 @@ class ResourceModel : public DynamicObjectModel
|
|||
Lumix::Resource* getResource() { return m_resource; }
|
||||
void setResource(const Lumix::Path& path);
|
||||
|
||||
signals:
|
||||
void modelReady();
|
||||
|
||||
private:
|
||||
void onResourceLoaded(Lumix::Resource::State, Lumix::Resource::State new_state);
|
||||
void fillModelInfo();
|
||||
void fillMaterialInfo(Lumix::Material* material, Node& node);
|
||||
void fillTextureInfo(Lumix::Texture*, Node& node);
|
||||
void saveMaterial(Lumix::Material* material);
|
||||
void showFileDialog(DynamicObjectModel::Node* node, QString filter);
|
||||
void showFileDialog(const DynamicObjectModel::Node* node, QString filter);
|
||||
void setMaterialShader(Lumix::Material* material, QString value);
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue