text format - prefabs
This commit is contained in:
parent
1e6b082087
commit
0247b351a0
21 changed files with 696 additions and 1292 deletions
|
@ -7,13 +7,13 @@
|
|||
#include "engine/blob.h"
|
||||
#include "engine/crc32.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/lua_wrapper.h"
|
||||
#include "engine/profiler.h"
|
||||
#include "engine/property_descriptor.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "renderer/model.h"
|
||||
#include "renderer/pose.h"
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
#include "engine/crc32.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/iallocator.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/lua_wrapper.h"
|
||||
#include "engine/matrix.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/resource_manager_base.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "lua_script/lua_script_system.h"
|
||||
|
||||
|
|
|
@ -10,17 +10,19 @@
|
|||
#include "engine/fs/os_file.h"
|
||||
#include "engine/hash_map.h"
|
||||
#include "engine/iplugin.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/log.h"
|
||||
#include "engine/math_utils.h"
|
||||
#include "engine/matrix.h"
|
||||
#include "engine/prefab.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/resource.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/string.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
|
||||
|
@ -44,32 +46,27 @@ public:
|
|||
{}
|
||||
|
||||
|
||||
bool onGUI(Lumix::Resource* resource, Lumix::ResourceType type) override
|
||||
bool onGUI(Resource* resource, ResourceType type) override
|
||||
{
|
||||
if (type != PREFAB_TYPE) return false;
|
||||
|
||||
if (ImGui::Button("Instantiate"))
|
||||
{
|
||||
system.instantiatePrefab(editor.getCameraRaycastHit(), resource->getPath());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Lumix::ResourceType getResourceType(const char* ext) override
|
||||
ResourceType getResourceType(const char* ext) override
|
||||
{
|
||||
if (equalStrings(ext, "fab")) return PREFAB_TYPE;
|
||||
return INVALID_RESOURCE_TYPE;
|
||||
}
|
||||
|
||||
|
||||
void onResourceUnloaded(Lumix::Resource* resource) override {}
|
||||
void onResourceUnloaded(Resource* resource) override {}
|
||||
const char* getName() const override { return "Prefab"; }
|
||||
bool hasResourceManager(Lumix::ResourceType type) const override { return type == PREFAB_TYPE; }
|
||||
bool hasResourceManager(ResourceType type) const override { return type == PREFAB_TYPE; }
|
||||
|
||||
|
||||
bool acceptExtension(const char* ext, Lumix::ResourceType type) const override
|
||||
bool acceptExtension(const char* ext, ResourceType type) const override
|
||||
{
|
||||
return type == PREFAB_TYPE && equalStrings(ext, "fab");
|
||||
}
|
||||
|
@ -82,330 +79,17 @@ public:
|
|||
|
||||
class EntityTemplateSystemImpl LUMIX_FINAL : public EntityTemplateSystem
|
||||
{
|
||||
private:
|
||||
struct InstantiatePrefabCommand LUMIX_FINAL : public IEditorCommand
|
||||
{
|
||||
InstantiatePrefabCommand(WorldEditor& _editor)
|
||||
: editor(_editor)
|
||||
, entities(_editor.getAllocator())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool execute() override
|
||||
{
|
||||
Lumix::Path path(path_hash);
|
||||
FS::OsFile file;
|
||||
if (!file.open(path.c_str(), Lumix::FS::Mode::OPEN_AND_READ, editor.getAllocator()))
|
||||
{
|
||||
g_log_error.log("Editor") << "Failed to open " << path.c_str();
|
||||
return false;
|
||||
}
|
||||
|
||||
Array<u8> data(editor.getAllocator());
|
||||
data.resize((int)file.size());
|
||||
file.read(&data[0], data.size());
|
||||
InputBlob blob(&data[0], data.size());
|
||||
entities.clear();
|
||||
editor.getEngine().pasteEntities(position, *editor.getUniverse(), blob, entities);
|
||||
|
||||
auto& system = static_cast<EntityTemplateSystemImpl&>(editor.getEntityTemplateSystem());
|
||||
if (record_instance)
|
||||
{
|
||||
auto& inst = system.m_prefab_instances.emplace();
|
||||
inst.position = position;
|
||||
inst.path_hash = path.getHash();
|
||||
}
|
||||
|
||||
for (int i = 0; i < entities.size(); ++i)
|
||||
{
|
||||
Entity entity = entities[i];
|
||||
PrefabEntity prefab_entity;
|
||||
prefab_entity.path_hash = path.getHash();
|
||||
prefab_entity.prev = i > 0 ? entities[i - 1] : INVALID_ENTITY;
|
||||
prefab_entity.next = i < entities.size() - 1 ? entities[i + 1] : INVALID_ENTITY;
|
||||
system.m_prefab_entities.insert(entity, prefab_entity);
|
||||
StaticString<MAX_PATH_LENGTH + 32> tmp(path.c_str(), "_", i);
|
||||
auto& instances = system.getMutableInstances(crc32(tmp));
|
||||
string tmp_str(tmp, editor.getAllocator());
|
||||
if (system.m_template_names.indexOf(tmp_str) < 0)
|
||||
{
|
||||
system.m_template_names.emplace(tmp, editor.getAllocator());
|
||||
}
|
||||
instances.push(entity);
|
||||
}
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void undo() override
|
||||
{
|
||||
auto& system = static_cast<EntityTemplateSystemImpl&>(editor.getEntityTemplateSystem());
|
||||
Universe& universe = *editor.getUniverse();
|
||||
for (auto entity : entities) universe.destroyEntity(entity);
|
||||
|
||||
system.m_prefab_instances.pop();
|
||||
}
|
||||
|
||||
|
||||
void serialize(JsonSerializer& serializer) override
|
||||
{
|
||||
serializer.serialize("position_x", position.x);
|
||||
serializer.serialize("position_y", position.y);
|
||||
serializer.serialize("position_z", position.z);
|
||||
serializer.serialize("path_hash", path_hash);
|
||||
serializer.serialize("record_instance", record_instance);
|
||||
}
|
||||
|
||||
|
||||
void deserialize(JsonSerializer& serializer) override
|
||||
{
|
||||
serializer.deserialize("position_x", position.x, 0);
|
||||
serializer.deserialize("position_y", position.y, 0);
|
||||
serializer.deserialize("position_z", position.z, 0);
|
||||
serializer.deserialize("path_hash", path_hash, 0);
|
||||
serializer.deserialize("record_instance", record_instance, true);
|
||||
}
|
||||
|
||||
|
||||
const char* getType() override
|
||||
{
|
||||
return "instantiate_prefab";
|
||||
}
|
||||
|
||||
|
||||
bool merge(IEditorCommand& command) { return false; }
|
||||
|
||||
|
||||
Vec3 position;
|
||||
u32 path_hash;
|
||||
bool record_instance;
|
||||
WorldEditor& editor;
|
||||
Array<Entity> entities;
|
||||
};
|
||||
|
||||
class CreateTemplateCommand LUMIX_FINAL : public IEditorCommand
|
||||
{
|
||||
public:
|
||||
explicit CreateTemplateCommand(WorldEditor& editor)
|
||||
: m_entity_system(
|
||||
static_cast<EntityTemplateSystemImpl&>(editor.getEntityTemplateSystem()))
|
||||
, m_editor(editor)
|
||||
, m_name(editor.getAllocator())
|
||||
, m_entity(INVALID_ENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CreateTemplateCommand(WorldEditor& editor,
|
||||
const char* template_name,
|
||||
Entity entity_template)
|
||||
: m_entity_system(
|
||||
static_cast<EntityTemplateSystemImpl&>(editor.getEntityTemplateSystem()))
|
||||
, m_name(template_name, editor.getAllocator())
|
||||
, m_entity(entity_template)
|
||||
, m_editor(editor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void serialize(JsonSerializer& serializer) override
|
||||
{
|
||||
serializer.serialize("template_name", m_name.c_str());
|
||||
serializer.serialize("entity", m_entity);
|
||||
}
|
||||
|
||||
|
||||
void deserialize(JsonSerializer& serializer) override
|
||||
{
|
||||
char name[50];
|
||||
serializer.deserialize("template_name", name, sizeof(name), "");
|
||||
m_name = name;
|
||||
serializer.deserialize("entity", m_entity, INVALID_ENTITY);
|
||||
}
|
||||
|
||||
|
||||
bool execute() override
|
||||
{
|
||||
u32 name_hash = crc32(m_name.c_str());
|
||||
if (m_entity_system.m_instances.find(name_hash) < 0)
|
||||
{
|
||||
m_entity_system.m_template_names.push(m_name);
|
||||
m_entity_system.m_instances.emplace(name_hash, m_editor.getAllocator());
|
||||
m_entity_system.m_instances.get(name_hash).push(m_entity);
|
||||
m_entity_system.m_updated.invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void undo() override
|
||||
{
|
||||
m_entity_system.m_template_names.eraseItem(m_name);
|
||||
u32 name_hash = crc32(m_name.c_str());
|
||||
m_entity_system.m_instances.erase(name_hash);
|
||||
m_entity_system.m_updated.invoke();
|
||||
}
|
||||
|
||||
|
||||
bool merge(IEditorCommand&) override { return false; }
|
||||
|
||||
|
||||
const char* getType() override
|
||||
{
|
||||
return "create_entity_template";
|
||||
}
|
||||
|
||||
|
||||
Entity getEntity() const { return m_entity; }
|
||||
|
||||
private:
|
||||
EntityTemplateSystemImpl& m_entity_system;
|
||||
WorldEditor& m_editor;
|
||||
string m_name;
|
||||
Entity m_entity;
|
||||
};
|
||||
|
||||
class CreateInstanceCommand LUMIX_FINAL : public IEditorCommand
|
||||
{
|
||||
public:
|
||||
explicit CreateInstanceCommand(WorldEditor& editor)
|
||||
: m_entity_system(static_cast<EntityTemplateSystemImpl&>(editor.getEntityTemplateSystem()))
|
||||
, m_editor(editor)
|
||||
, m_template_name_hash(0)
|
||||
, m_position(0, 0, 0)
|
||||
, m_rotation(0, 0, 0, 1)
|
||||
, m_size(1)
|
||||
, m_entity(INVALID_ENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CreateInstanceCommand(EntityTemplateSystemImpl& entity_system,
|
||||
WorldEditor& editor,
|
||||
const char* template_name,
|
||||
const Vec3& position,
|
||||
const Quat& rot,
|
||||
float size)
|
||||
: m_entity_system(entity_system)
|
||||
, m_editor(editor)
|
||||
, m_template_name_hash(crc32(template_name))
|
||||
, m_position(position)
|
||||
, m_rotation(rot)
|
||||
, m_size(size)
|
||||
, m_entity(INVALID_ENTITY)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void serialize(JsonSerializer& serializer) override
|
||||
{
|
||||
serializer.serialize("template_name_hash", m_template_name_hash);
|
||||
serializer.serialize("entity", m_entity);
|
||||
serializer.serialize("position_x", m_position.x);
|
||||
serializer.serialize("position_y", m_position.y);
|
||||
serializer.serialize("position_z", m_position.z);
|
||||
serializer.serialize("rotation_x", m_rotation.x);
|
||||
serializer.serialize("rotation_y", m_rotation.y);
|
||||
serializer.serialize("rotation_z", m_rotation.z);
|
||||
serializer.serialize("rotation_w", m_rotation.w);
|
||||
serializer.serialize("size", m_size);
|
||||
}
|
||||
|
||||
|
||||
void deserialize(JsonSerializer& serializer) override
|
||||
{
|
||||
serializer.deserialize("template_name_hash", m_template_name_hash, 0);
|
||||
serializer.deserialize("entity", m_entity, INVALID_ENTITY);
|
||||
serializer.deserialize("position_x", m_position.x, 0);
|
||||
serializer.deserialize("position_y", m_position.y, 0);
|
||||
serializer.deserialize("position_z", m_position.z, 0);
|
||||
serializer.deserialize("rotation_x", m_rotation.x, 0);
|
||||
serializer.deserialize("rotation_y", m_rotation.y, 0);
|
||||
serializer.deserialize("rotation_z", m_rotation.z, 0);
|
||||
serializer.deserialize("rotation_w", m_rotation.w, 0);
|
||||
serializer.deserialize("size", m_size, 1);
|
||||
}
|
||||
|
||||
|
||||
bool execute() override
|
||||
{
|
||||
int instance_index = m_entity_system.m_instances.find(m_template_name_hash);
|
||||
if (instance_index >= 0)
|
||||
{
|
||||
Universe* universe = m_entity_system.m_editor.getUniverse();
|
||||
m_entity = universe->createEntity(m_position, m_rotation);
|
||||
universe->setScale(m_entity, m_size);
|
||||
|
||||
m_entity_system.m_instances.at(instance_index).push(m_entity);
|
||||
Entity template_entity = m_entity_system.m_instances.at(instance_index)[0];
|
||||
for (ComponentUID cmp = universe->getFirstComponent(template_entity); cmp.isValid();
|
||||
cmp = universe->getNextComponent(cmp))
|
||||
{
|
||||
m_entity_system.m_editor.cloneComponent(cmp, m_entity);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void undo() override
|
||||
{
|
||||
m_entity_system.m_universe->destroyEntity(m_entity);
|
||||
m_entity = INVALID_ENTITY;
|
||||
}
|
||||
|
||||
|
||||
bool merge(IEditorCommand&) override { return false; }
|
||||
|
||||
|
||||
const char* getType() override
|
||||
{
|
||||
return "create_entity_template_instance";
|
||||
}
|
||||
|
||||
|
||||
Entity getEntity() const { return m_entity; }
|
||||
|
||||
private:
|
||||
EntityTemplateSystemImpl& m_entity_system;
|
||||
WorldEditor& m_editor;
|
||||
u32 m_template_name_hash;
|
||||
Entity m_entity;
|
||||
Vec3 m_position;
|
||||
Quat m_rotation;
|
||||
float m_size;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit EntityTemplateSystemImpl(WorldEditor& editor)
|
||||
: m_editor(editor)
|
||||
, m_prefab_entities(editor.getAllocator())
|
||||
, m_prefab_instances(editor.getAllocator())
|
||||
, m_universe(nullptr)
|
||||
, m_instances(editor.getAllocator())
|
||||
, m_updated(editor.getAllocator())
|
||||
, m_template_names(editor.getAllocator())
|
||||
, m_prefabs(editor.getAllocator())
|
||||
{
|
||||
editor.universeCreated().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseCreated>(this);
|
||||
editor.universeDestroyed().bind<EntityTemplateSystemImpl, &EntityTemplateSystemImpl::onUniverseDestroyed>(this);
|
||||
setUniverse(editor.getUniverse());
|
||||
editor.registerEditorCommandCreator(
|
||||
"create_entity_template_instance", &EntityTemplateSystemImpl::createCreateInstanceCommand);
|
||||
editor.registerEditorCommandCreator(
|
||||
"create_entity_template", &EntityTemplateSystemImpl::createCreateTemplateCommand);
|
||||
editor.registerEditorCommandCreator(
|
||||
"instantiate_prefab", &EntityTemplateSystemImpl::createInstantiatePrefabCommand);
|
||||
}
|
||||
|
||||
|
||||
|
@ -415,24 +99,6 @@ public:
|
|||
}
|
||||
|
||||
|
||||
static IEditorCommand* createCreateInstanceCommand(WorldEditor& editor)
|
||||
{
|
||||
return LUMIX_NEW(editor.getAllocator(), CreateInstanceCommand)(editor);
|
||||
}
|
||||
|
||||
|
||||
static IEditorCommand* createCreateTemplateCommand(WorldEditor& editor)
|
||||
{
|
||||
return LUMIX_NEW(editor.getAllocator(), CreateTemplateCommand)(editor);
|
||||
}
|
||||
|
||||
|
||||
static IEditorCommand* createInstantiatePrefabCommand(WorldEditor& editor)
|
||||
{
|
||||
return LUMIX_NEW(editor.getAllocator(), InstantiatePrefabCommand)(editor);
|
||||
}
|
||||
|
||||
|
||||
~EntityTemplateSystemImpl()
|
||||
{
|
||||
m_editor.universeCreated()
|
||||
|
@ -466,7 +132,11 @@ public:
|
|||
void onUniverseCreated()
|
||||
{
|
||||
m_instances.clear();
|
||||
m_template_names.clear();
|
||||
for (PrefabResource* prefab : m_prefabs)
|
||||
{
|
||||
prefab->getResourceManager().unload(*prefab);
|
||||
}
|
||||
m_prefabs.clear();
|
||||
setUniverse(m_editor.getUniverse());
|
||||
}
|
||||
|
||||
|
@ -474,250 +144,137 @@ public:
|
|||
void onUniverseDestroyed()
|
||||
{
|
||||
m_instances.clear();
|
||||
m_template_names.clear();
|
||||
for (PrefabResource* prefab : m_prefabs)
|
||||
{
|
||||
prefab->getResourceManager().unload(*prefab);
|
||||
}
|
||||
m_prefabs.clear();
|
||||
setUniverse(nullptr);
|
||||
}
|
||||
|
||||
|
||||
void onEntityDestroyed(Entity entity)
|
||||
{
|
||||
u32 tpl = getTemplate(entity);
|
||||
if (tpl != 0)
|
||||
u64 prefab = getPrefab(entity);
|
||||
if (prefab != 0)
|
||||
{
|
||||
Array<Entity>& instances = m_instances.get(tpl);
|
||||
Array<Entity>& instances = m_instances.get(prefab);
|
||||
instances.eraseItemFast(entity);
|
||||
if (instances.empty())
|
||||
{
|
||||
m_instances.erase(tpl);
|
||||
}
|
||||
}
|
||||
|
||||
auto iter = m_prefab_entities.find(entity);
|
||||
if (iter != m_prefab_entities.end())
|
||||
{
|
||||
PrefabEntity tmp = iter.value();
|
||||
if (isValid(tmp.prev)) m_prefab_entities[tmp.prev].next = tmp.next;
|
||||
if (isValid(tmp.next)) m_prefab_entities[tmp.next].prev = tmp.prev;
|
||||
m_prefab_entities.erase(iter);
|
||||
if (instances.empty()) m_instances.erase(prefab);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setPrefab(Entity entity, const PrefabEntity& prefab) override
|
||||
void setPrefab(Entity entity, u64 prefab) override
|
||||
{
|
||||
if (isValid(prefab.prev)) m_prefab_entities[prefab.prev].next = entity;
|
||||
if (isValid(prefab.next)) m_prefab_entities[prefab.next].prev = entity;
|
||||
m_prefab_entities.insert(entity, prefab);
|
||||
getMutableInstances(prefab).push(entity);
|
||||
}
|
||||
|
||||
|
||||
PrefabEntity getPrefabEntity(Entity entity) override
|
||||
{
|
||||
auto iter = m_prefab_entities.find(entity);
|
||||
if (iter.isValid()) return iter.value();
|
||||
|
||||
return {0, INVALID_ENTITY, INVALID_ENTITY};
|
||||
}
|
||||
|
||||
|
||||
bool isPrefab() override
|
||||
{
|
||||
auto& selected = m_editor.getSelectedEntities();
|
||||
if (selected.empty()) return false;
|
||||
|
||||
auto iter = m_prefab_entities.find(selected[0]);
|
||||
if (!iter.isValid()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void selectPrefab() override
|
||||
{
|
||||
auto& selected = m_editor.getSelectedEntities();
|
||||
if (selected.empty()) return;
|
||||
|
||||
auto iter = m_prefab_entities.find(selected[0]);
|
||||
if (!iter.isValid()) return;
|
||||
|
||||
PrefabEntity tmp = iter.value();
|
||||
Array<Entity> entities(m_editor.getAllocator());
|
||||
|
||||
Entity e = selected[0];
|
||||
while (isValid(tmp.prev))
|
||||
{
|
||||
e = tmp.prev;
|
||||
tmp = m_prefab_entities[e];
|
||||
}
|
||||
|
||||
while (isValid(e))
|
||||
{
|
||||
entities.push(e);
|
||||
e = m_prefab_entities[e].next;
|
||||
}
|
||||
|
||||
m_editor.selectEntities(&entities[0], entities.size());
|
||||
}
|
||||
|
||||
|
||||
void applyPrefab() override
|
||||
{
|
||||
auto& selected = m_editor.getSelectedEntities();
|
||||
if (selected.empty()) return;
|
||||
|
||||
auto iter = m_prefab_entities.find(selected[0]);
|
||||
if (!iter.isValid()) return;
|
||||
|
||||
PrefabEntity tmp = iter.value();
|
||||
Array<Entity> entities(m_editor.getAllocator());
|
||||
|
||||
Entity e = selected[0];
|
||||
while (isValid(tmp.prev))
|
||||
{
|
||||
e = tmp.prev;
|
||||
tmp = m_prefab_entities[e];
|
||||
}
|
||||
|
||||
while (isValid(e))
|
||||
{
|
||||
entities.push(e);
|
||||
e = m_prefab_entities[e].next;
|
||||
}
|
||||
|
||||
FS::OsFile file;
|
||||
Lumix::Path path(tmp.path_hash);
|
||||
if (!file.open(path.c_str(), Lumix::FS::Mode::CREATE_AND_WRITE, m_editor.getAllocator()))
|
||||
{
|
||||
g_log_error.log("Editor") << "Failed to create " << path.c_str();
|
||||
return;
|
||||
}
|
||||
|
||||
OutputBlob blob(m_editor.getAllocator());
|
||||
m_editor.copyEntities(&entities[0], entities.size(), blob);
|
||||
|
||||
file.write(blob.getData(), blob.getPos());
|
||||
|
||||
file.close();
|
||||
|
||||
refreshPrefabs();
|
||||
}
|
||||
|
||||
|
||||
void createTemplateFromEntity(const char* name, Entity entity) override
|
||||
{
|
||||
CreateTemplateCommand* command =
|
||||
LUMIX_NEW(m_editor.getAllocator(), CreateTemplateCommand)(m_editor, name, entity);
|
||||
m_editor.executeCommand(command);
|
||||
}
|
||||
|
||||
|
||||
void setTemplate(Entity entity, u32 template_name_hash) override
|
||||
{
|
||||
int idx = m_instances.find(template_name_hash);
|
||||
if (idx >= 0)
|
||||
{
|
||||
m_instances.at(idx).push(entity);
|
||||
return;
|
||||
}
|
||||
auto& value = m_instances.emplace(template_name_hash, m_editor.getAllocator());
|
||||
value.push(entity);
|
||||
}
|
||||
|
||||
|
||||
u32 getTemplate(Entity entity) override
|
||||
u64 getPrefab(Entity entity) override
|
||||
{
|
||||
for (int j = 0; j < m_instances.size(); ++j)
|
||||
{
|
||||
Array<Entity>& entities = m_instances.at(j);
|
||||
for (int i = 0, c = entities.size(); i < c; ++i)
|
||||
{
|
||||
if (entities[i] == entity)
|
||||
{
|
||||
return m_instances.getKey(j);
|
||||
}
|
||||
if (entities[i] == entity) return m_instances.getKey(j);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const Array<Entity>& getInstances(u32 template_name_hash) override
|
||||
const Array<Entity>& getInstances(u64 prefab) override
|
||||
{
|
||||
int instances_index = m_instances.find(template_name_hash);
|
||||
int instances_index = m_instances.find(prefab);
|
||||
if (instances_index >= 0) return m_instances.at(instances_index);
|
||||
return m_instances.emplace(template_name_hash, m_editor.getAllocator());
|
||||
return m_instances.emplace(prefab, m_editor.getAllocator());
|
||||
}
|
||||
|
||||
|
||||
Array<Entity>& getMutableInstances(u32 template_name_hash)
|
||||
Array<Entity>& getMutableInstances(u64 prefab)
|
||||
{
|
||||
int instances_index = m_instances.find(template_name_hash);
|
||||
int instances_index = m_instances.find(prefab);
|
||||
if (instances_index >= 0) return m_instances.at(instances_index);
|
||||
return m_instances.emplace(template_name_hash, m_editor.getAllocator());
|
||||
return m_instances.emplace(prefab, m_editor.getAllocator());
|
||||
}
|
||||
|
||||
|
||||
void savePrefab(const Lumix::Path& path) override
|
||||
void instantiatePrefab(PrefabResource& prefab, const Vec3& pos, const Quat& rot, float scale) override
|
||||
{
|
||||
if (m_prefabs.indexOf(&prefab) < 0)
|
||||
{
|
||||
m_prefabs.emplace(&prefab);
|
||||
prefab.getResourceManager().load(prefab);
|
||||
}
|
||||
InputBlob blob(prefab.blob.getData(), prefab.blob.getPos());
|
||||
TextDeserializer deserializer(blob);
|
||||
while (blob.getPosition() < blob.getSize())
|
||||
{
|
||||
u64 prefab;
|
||||
deserializer.read(&prefab);
|
||||
Array<Entity>& instances = getMutableInstances(prefab);
|
||||
Entity e = m_universe->createEntity(pos, rot);
|
||||
m_universe->setScale(e, scale);
|
||||
instances.emplace(e);
|
||||
u32 cmp_type;
|
||||
deserializer.read(&cmp_type);
|
||||
while (cmp_type != 0)
|
||||
{
|
||||
m_universe->deserializeComponent(deserializer, e, PropertyRegister::getComponentTypeFromHash(cmp_type));
|
||||
deserializer.read(&cmp_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void serializePrefab(Universe* universe, const Entity* entities, int count, const Path& path, TextSerializer& serializer)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
Entity entity = entities[i];
|
||||
u64 prefab = path.getHash();
|
||||
prefab |= ((u64)i) << 32;
|
||||
serializer.write("prefab", prefab);
|
||||
for (ComponentUID cmp = universe->getFirstComponent(entity); cmp.isValid(); cmp = universe->getNextComponent(cmp))
|
||||
{
|
||||
const char* cmp_name = PropertyRegister::getComponentTypeID(cmp.type.index);
|
||||
u32 type_hash = PropertyRegister::getComponentTypeHash(cmp.type);
|
||||
serializer.write(cmp_name, type_hash);
|
||||
universe->serializeComponent(serializer, cmp.type, cmp.handle);
|
||||
}
|
||||
serializer.write("cmp_end", 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void savePrefab(const Path& path) override
|
||||
{
|
||||
auto& entities = m_editor.getSelectedEntities();
|
||||
if (entities.empty()) return;
|
||||
|
||||
FS::OsFile file;
|
||||
if (!file.open(path.c_str(), Lumix::FS::Mode::CREATE_AND_WRITE, m_editor.getAllocator()))
|
||||
if (!file.open(path.c_str(), FS::Mode::CREATE_AND_WRITE, m_editor.getAllocator()))
|
||||
{
|
||||
g_log_error.log("Editor") << "Failed to create " << path.c_str();
|
||||
return;
|
||||
}
|
||||
|
||||
OutputBlob blob(m_editor.getAllocator());
|
||||
m_editor.copyEntities(&entities[0], entities.size(), blob);
|
||||
TextSerializer serializer(blob);
|
||||
|
||||
auto& ents = m_editor.getSelectedEntities();
|
||||
serializePrefab(m_universe, &ents[0], ents.size(), path, serializer);
|
||||
|
||||
file.write(blob.getData(), blob.getPos());
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
void instantiatePrefab(const Vec3& pos, const Lumix::Path& path, bool record_instance)
|
||||
{
|
||||
InstantiatePrefabCommand* cmd = LUMIX_NEW(m_editor.getAllocator(), InstantiatePrefabCommand)(m_editor);
|
||||
cmd->position = pos;
|
||||
cmd->path_hash = path.getHash();
|
||||
cmd->record_instance = record_instance;
|
||||
if (record_instance)
|
||||
{
|
||||
m_editor.executeCommand(cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd->execute();
|
||||
LUMIX_DELETE(m_editor.getAllocator(), cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void instantiatePrefab(const Vec3& pos, const Lumix::Path& path) override
|
||||
{
|
||||
instantiatePrefab(pos, path, true);
|
||||
}
|
||||
|
||||
|
||||
Entity createInstance(const char* name, const Vec3& position, const Quat& rotation, float size) override
|
||||
{
|
||||
CreateInstanceCommand* command = LUMIX_NEW(m_editor.getAllocator(), CreateInstanceCommand)(
|
||||
*this, m_editor, name, position, rotation, size);
|
||||
m_editor.executeCommand(command);
|
||||
return command->getEntity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void serialize(ISerializer& serializer) override
|
||||
{
|
||||
serializer.write("count", m_template_names.size());
|
||||
for (auto& name : m_template_names)
|
||||
{
|
||||
serializer.write("name", name.c_str());
|
||||
}
|
||||
serializer.write("count", m_instances.size());
|
||||
for (int i = 0; i < m_instances.size(); ++i)
|
||||
{
|
||||
|
@ -726,7 +283,7 @@ public:
|
|||
serializer.write("count", (i32)entities.size());
|
||||
for (int j = 0, c = entities.size(); j < c; ++j)
|
||||
{
|
||||
serializer.write("entity", entities[j]);
|
||||
serializer.write("", entities[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,13 +294,6 @@ public:
|
|||
int count;
|
||||
serializer.read(&count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
char name[64];
|
||||
serializer.read(name, lengthOf(name));
|
||||
m_template_names.emplace(name, m_editor.getAllocator());
|
||||
}
|
||||
serializer.read(&count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
u32 hash;
|
||||
serializer.read(&hash);
|
||||
|
@ -760,123 +310,15 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void serialize(OutputBlob& serializer) override
|
||||
{
|
||||
serializer.write((i32)m_template_names.size());
|
||||
for (int i = 0, c = m_template_names.size(); i < c; ++i)
|
||||
{
|
||||
serializer.writeString(m_template_names[i].c_str());
|
||||
}
|
||||
serializer.write((i32)m_instances.size());
|
||||
for (int i = 0; i < m_instances.size(); ++i)
|
||||
{
|
||||
serializer.write(m_instances.getKey(i));
|
||||
Array<Entity>& entities = m_instances.at(i);
|
||||
serializer.write((i32)entities.size());
|
||||
for (int j = 0, c = entities.size(); j < c; ++j)
|
||||
{
|
||||
serializer.write(entities[j]);
|
||||
}
|
||||
}
|
||||
|
||||
serializer.write(m_prefab_entities.size());
|
||||
for (auto iter = m_prefab_entities.begin(), end = m_prefab_entities.end(); iter != end; ++iter)
|
||||
{
|
||||
serializer.write(iter.key());
|
||||
serializer.write(iter.value());
|
||||
}
|
||||
|
||||
serializer.write(m_prefab_instances.size());
|
||||
for (auto& inst : m_prefab_instances)
|
||||
{
|
||||
serializer.write(inst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void refreshPrefabs() override
|
||||
{
|
||||
while(!m_prefab_entities.empty())
|
||||
{
|
||||
m_universe->destroyEntity(m_prefab_entities.begin().key());
|
||||
}
|
||||
m_prefab_entities.clear();
|
||||
for (auto& inst : m_prefab_instances)
|
||||
{
|
||||
instantiatePrefab(inst.position, Lumix::Path(inst.path_hash), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void deserialize(InputBlob& serializer, bool has_prefabs) override
|
||||
{
|
||||
m_template_names.clear();
|
||||
m_instances.clear();
|
||||
m_prefab_entities.clear();
|
||||
m_prefab_instances.clear();
|
||||
i32 count;
|
||||
serializer.read(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
const int MAX_NAME_LENGTH = 50;
|
||||
char name[MAX_NAME_LENGTH];
|
||||
serializer.readString(name, MAX_NAME_LENGTH);
|
||||
m_template_names.emplace(name, m_editor.getAllocator());
|
||||
}
|
||||
serializer.read(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
u32 hash;
|
||||
serializer.read(hash);
|
||||
i32 instances_per_template;
|
||||
serializer.read(instances_per_template);
|
||||
Array<Entity>& entities = m_instances.emplace(hash, m_editor.getAllocator());
|
||||
for (int j = 0; j < instances_per_template; ++j)
|
||||
{
|
||||
Entity entity;
|
||||
serializer.read(entity);
|
||||
entities.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_prefabs)
|
||||
{
|
||||
serializer.read(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
Entity entity;
|
||||
serializer.read(entity);
|
||||
PrefabEntity prefab_entity;
|
||||
serializer.read(prefab_entity);
|
||||
m_prefab_entities.insert(entity, prefab_entity);
|
||||
}
|
||||
|
||||
serializer.read(count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
PrefabInstance& inst = m_prefab_instances.emplace();
|
||||
serializer.read(inst);
|
||||
}
|
||||
}
|
||||
|
||||
m_updated.invoke();
|
||||
}
|
||||
|
||||
|
||||
Array<string>& getTemplateNames() override { return m_template_names; }
|
||||
|
||||
|
||||
DelegateList<void()>& updated() override { return m_updated; }
|
||||
|
||||
|
||||
private:
|
||||
AssociativeArray<u32, Array<Entity>> m_instances;
|
||||
Array<string> m_template_names;
|
||||
AssociativeArray<u64, Array<Entity>> m_instances;
|
||||
Array<PrefabResource*> m_prefabs;
|
||||
Universe* m_universe;
|
||||
WorldEditor& m_editor;
|
||||
DelegateList<void()> m_updated;
|
||||
HashMap<Entity, PrefabEntity> m_prefab_entities;
|
||||
Array<PrefabInstance> m_prefab_instances;
|
||||
}; // class EntityTemplateSystemImpl
|
||||
|
||||
|
||||
|
|
|
@ -18,19 +18,12 @@ class InputBlob;
|
|||
struct ISerializer;
|
||||
class OutputBlob;
|
||||
class Path;
|
||||
struct PrefabResource;
|
||||
struct Quat;
|
||||
struct Vec3;
|
||||
class WorldEditor;
|
||||
|
||||
|
||||
struct PrefabEntity
|
||||
{
|
||||
u32 path_hash;
|
||||
Entity prev;
|
||||
Entity next;
|
||||
};
|
||||
|
||||
|
||||
class LUMIX_EDITOR_API EntityTemplateSystem
|
||||
{
|
||||
public:
|
||||
|
@ -41,24 +34,11 @@ public:
|
|||
virtual void setStudioApp(StudioApp& app) = 0;
|
||||
virtual void serialize(ISerializer& serializer) = 0;
|
||||
virtual void deserialize(IDeserializer& serializer) = 0;
|
||||
virtual void serialize(OutputBlob& serializer) = 0;
|
||||
virtual void deserialize(InputBlob& serializer, bool has_prefabs) = 0;
|
||||
virtual void createTemplateFromEntity(const char* name, Entity entity) = 0;
|
||||
virtual u32 getTemplate(Entity entity) = 0;
|
||||
virtual void setTemplate(Entity entity, u32 template_name_hash) = 0;
|
||||
virtual const Array<Entity>& getInstances(u32 template_name_hash) = 0;
|
||||
virtual Array<string>& getTemplateNames() = 0;
|
||||
virtual Entity createInstance(const char* name, const Vec3& position, const Quat& rot, float size) = 0;
|
||||
virtual void refreshPrefabs() = 0;
|
||||
|
||||
virtual bool isPrefab() = 0;
|
||||
virtual void applyPrefab() = 0;
|
||||
virtual void selectPrefab() = 0;
|
||||
virtual void instantiatePrefab(PrefabResource& prefab, const Vec3& pos, const Quat& rot, float scale) = 0;
|
||||
virtual u64 getPrefab(Entity entity) = 0;
|
||||
virtual void setPrefab(Entity entity, u64 prefab) = 0;
|
||||
virtual const Array<Entity>& getInstances(u64 prefab) = 0;
|
||||
virtual void savePrefab(const Lumix::Path& path) = 0;
|
||||
virtual void instantiatePrefab(const Vec3& pos, const Lumix::Path& path) = 0;
|
||||
virtual PrefabEntity getPrefabEntity(Entity entity) = 0;
|
||||
virtual void setPrefab(Entity entity, const PrefabEntity& prefab) = 0;
|
||||
|
||||
virtual DelegateList<void()>& updated() = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -116,7 +116,6 @@ public:
|
|||
StudioAppImpl()
|
||||
: m_is_entity_list_opened(true)
|
||||
, m_finished(false)
|
||||
, m_is_entity_template_list_opened(false)
|
||||
, m_selected_template_name(m_allocator)
|
||||
, m_profiler_ui(nullptr)
|
||||
, m_asset_browser(nullptr)
|
||||
|
@ -507,7 +506,6 @@ public:
|
|||
m_log_ui->onGUI();
|
||||
m_property_grid->onGUI();
|
||||
showEntityList();
|
||||
showEntityTemplateList();
|
||||
for (auto* plugin : m_plugins)
|
||||
{
|
||||
plugin->onWindowGUI();
|
||||
|
@ -732,16 +730,6 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void instantiateTemplate()
|
||||
{
|
||||
if (m_selected_template_name.length() <= 0) return;
|
||||
|
||||
Lumix::Vec3 pos = m_editor->getCameraRaycastHit();
|
||||
auto& template_system = m_editor->getEntityTemplateSystem();
|
||||
template_system.createInstance(m_selected_template_name.c_str(), pos, Lumix::Quat(0, 0, 0, 1), 1);
|
||||
}
|
||||
|
||||
|
||||
void undo() { if (!hasPluginFocus()) m_editor->undo(); }
|
||||
void redo() { if (!hasPluginFocus()) m_editor->redo(); }
|
||||
void copy() { m_editor->copyEntities(); }
|
||||
|
@ -777,6 +765,16 @@ public:
|
|||
void setRotateGizmoMode() { m_editor->getGizmo().setRotateMode(); }
|
||||
|
||||
|
||||
void savePrefab()
|
||||
{
|
||||
char filename[Lumix::MAX_PATH_LENGTH];
|
||||
if (PlatformInterface::getSaveFilename(filename, Lumix::lengthOf(filename), "Prefab files\0*.fab\0", "fab"))
|
||||
{
|
||||
m_editor->getEntityTemplateSystem().savePrefab(Lumix::Path(filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void autosnapDown()
|
||||
{
|
||||
auto& gizmo = m_editor->getGizmo();
|
||||
|
@ -921,20 +919,7 @@ public:
|
|||
}
|
||||
doMenuItem(*getAction("destroyEntity"), is_any_entity_selected);
|
||||
|
||||
if (ImGui::BeginMenu("Create template", is_any_entity_selected))
|
||||
{
|
||||
static char name[255] = "";
|
||||
ImGui::InputText("Name###templatename", name, sizeof(name));
|
||||
if (ImGui::Button("Create"))
|
||||
{
|
||||
auto entity = m_editor->getSelectedEntities()[0];
|
||||
auto& system = m_editor->getEntityTemplateSystem();
|
||||
system.createTemplateFromEntity(name, entity);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
doMenuItem(*getAction("instantiateTemplate"), m_selected_template_name.length() > 0);
|
||||
doMenuItem(*getAction("savePrefab"), is_any_entity_selected);
|
||||
doMenuItem(*getAction("showEntities"), is_any_entity_selected);
|
||||
doMenuItem(*getAction("hideEntities"), is_any_entity_selected);
|
||||
ImGui::EndMenu();
|
||||
|
@ -1030,7 +1015,6 @@ public:
|
|||
|
||||
ImGui::MenuItem("Asset browser", nullptr, &m_asset_browser->m_is_opened);
|
||||
doMenuItem(*getAction("entityList"), true);
|
||||
ImGui::MenuItem("Entity templates", nullptr, &m_is_entity_template_list_opened);
|
||||
ImGui::MenuItem("Log", nullptr, &m_log_ui->m_is_opened);
|
||||
ImGui::MenuItem("Profiler", nullptr, &m_profiler_ui->m_is_opened);
|
||||
ImGui::MenuItem("Properties", nullptr, &m_property_grid->m_is_opened);
|
||||
|
@ -1143,73 +1127,6 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void showEntityTemplateList()
|
||||
{
|
||||
if (ImGui::BeginDock("Entity Templates", &m_is_entity_template_list_opened))
|
||||
{
|
||||
if (m_editor->getSelectedEntities().size() == 1)
|
||||
{
|
||||
if (ImGui::Button("Create template"))
|
||||
{
|
||||
ImGui::OpenPopup("create template");
|
||||
}
|
||||
if (ImGui::BeginPopup("create template"))
|
||||
{
|
||||
ImGui::InputText("Template name", m_template_name, Lumix::lengthOf(m_template_name));
|
||||
if (ImGui::Button("Create"))
|
||||
{
|
||||
auto entity = m_editor->getSelectedEntities()[0];
|
||||
auto& system = m_editor->getEntityTemplateSystem();
|
||||
system.createTemplateFromEntity(m_template_name, entity);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
if (!m_editor->getSelectedEntities().empty())
|
||||
{
|
||||
auto& system = m_editor->getEntityTemplateSystem();
|
||||
bool is_prefab = system.isPrefab();
|
||||
|
||||
if (is_prefab)
|
||||
{
|
||||
if (ImGui::Button("Apply")) system.applyPrefab();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Revert")) system.refreshPrefabs();
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Select")) system.selectPrefab();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Save prefab"))
|
||||
{
|
||||
char tmp[Lumix::MAX_PATH_LENGTH];
|
||||
if (PlatformInterface::getSaveFilename(tmp, Lumix::lengthOf(tmp), "Prefabs\0*.fab\0", "fab"))
|
||||
{
|
||||
system.savePrefab(Lumix::Path(tmp));
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::Text("Templates:");
|
||||
auto& template_system = m_editor->getEntityTemplateSystem();
|
||||
|
||||
for (auto& template_name : template_system.getTemplateNames())
|
||||
{
|
||||
bool b = m_selected_template_name == template_name;
|
||||
auto& instances = template_system.getInstances(Lumix::crc32(template_name.c_str()));
|
||||
if (!instances.empty() && ImGui::Selectable(template_name.c_str(), &b))
|
||||
{
|
||||
m_selected_template_name = template_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDock();
|
||||
}
|
||||
|
||||
|
||||
void showEntityListToolbar()
|
||||
{
|
||||
auto pos = ImGui::GetCursorScreenPos();
|
||||
|
@ -1363,7 +1280,6 @@ public:
|
|||
{
|
||||
m_settings.m_is_asset_browser_opened = m_asset_browser->m_is_opened;
|
||||
m_settings.m_is_entity_list_opened = m_is_entity_list_opened;
|
||||
m_settings.m_is_entity_template_list_opened = m_is_entity_template_list_opened;
|
||||
m_settings.m_is_log_opened = m_log_ui->m_is_opened;
|
||||
m_settings.m_is_profiler_opened = m_profiler_ui->m_is_opened;
|
||||
m_settings.m_is_properties_opened = m_property_grid->m_is_opened;
|
||||
|
@ -1424,7 +1340,6 @@ public:
|
|||
|
||||
m_asset_browser->m_is_opened = m_settings.m_is_asset_browser_opened;
|
||||
m_is_entity_list_opened = m_settings.m_is_entity_list_opened;
|
||||
m_is_entity_template_list_opened = m_settings.m_is_entity_template_list_opened;
|
||||
m_log_ui->m_is_opened = m_settings.m_is_log_opened;
|
||||
m_profiler_ui->m_is_opened = m_settings.m_is_profiler_opened;
|
||||
m_property_grid->m_is_opened = m_settings.m_is_properties_opened;
|
||||
|
@ -1482,7 +1397,7 @@ public:
|
|||
addAction<&StudioAppImpl::destroyEntity>("Destroy", "destroyEntity", SDLK_DELETE, -1, -1);
|
||||
addAction<&StudioAppImpl::showEntities>("Show", "showEntities");
|
||||
addAction<&StudioAppImpl::hideEntities>("Hide", "hideEntities");
|
||||
addAction<&StudioAppImpl::instantiateTemplate>("Instantiate template", "instantiateTemplate");
|
||||
addAction<&StudioAppImpl::savePrefab>("Save prefab", "savePrefab");
|
||||
|
||||
addAction<&StudioAppImpl::toggleGameMode>("Game Mode", "toggleGameMode")
|
||||
.is_selected.bind<Lumix::WorldEditor, &Lumix::WorldEditor::isGameMode>(m_editor);
|
||||
|
@ -1623,12 +1538,6 @@ public:
|
|||
}
|
||||
|
||||
|
||||
void LUA_createEntityTemplate(Lumix::Entity entity, const char* name)
|
||||
{
|
||||
m_editor->getEntityTemplateSystem().createTemplateFromEntity(name, entity);
|
||||
}
|
||||
|
||||
|
||||
void LUA_exitGameMode()
|
||||
{
|
||||
m_editor->toggleGameMode();
|
||||
|
@ -1663,7 +1572,6 @@ public:
|
|||
REGISTER_FUNCTION(runTest);
|
||||
REGISTER_FUNCTION(exit);
|
||||
REGISTER_FUNCTION(exitGameMode);
|
||||
REGISTER_FUNCTION(createEntityTemplate);
|
||||
|
||||
#undef REGISTER_FUNCTION
|
||||
}
|
||||
|
@ -2257,7 +2165,6 @@ public:
|
|||
|
||||
bool m_is_welcome_screen_opened;
|
||||
bool m_is_entity_list_opened;
|
||||
bool m_is_entity_template_list_opened;
|
||||
DragData m_drag_data;
|
||||
ImFont* m_font;
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "engine/input_system.h"
|
||||
#include "engine/iplugin.h"
|
||||
#include "engine/iproperty_descriptor.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/log.h"
|
||||
#include "engine/matrix.h"
|
||||
|
@ -718,8 +718,8 @@ public:
|
|||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (!m_editor.getUniverse()->getComponent(entities[i], m_component_type).isValid()) continue;
|
||||
u32 tpl = editor.getEntityTemplateSystem().getTemplate(entities[i]);
|
||||
if (tpl == 0)
|
||||
u64 prefab = editor.getEntityTemplateSystem().getPrefab(entities[i]);
|
||||
if (prefab == 0)
|
||||
{
|
||||
ComponentUID component = m_editor.getUniverse()->getComponent(entities[i], component_type);
|
||||
m_property_descriptor->get(component, index, m_old_value);
|
||||
|
@ -727,7 +727,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
const Array<Entity>& instances = editor.getEntityTemplateSystem().getInstances(tpl);
|
||||
const Array<Entity>& instances = editor.getEntityTemplateSystem().getInstances(prefab);
|
||||
for (int i = 0; i < instances.size(); ++i)
|
||||
{
|
||||
ComponentUID component = m_editor.getUniverse()->getComponent(instances[i], component_type);
|
||||
|
@ -874,14 +874,14 @@ private:
|
|||
{
|
||||
if (!m_editor.getUniverse()->getComponent(entities[i], type).isValid())
|
||||
{
|
||||
u32 tpl = editor.getEntityTemplateSystem().getTemplate(entities[i]);
|
||||
if (tpl == 0)
|
||||
u64 prefab = editor.getEntityTemplateSystem().getPrefab(entities[i]);
|
||||
if (prefab == 0)
|
||||
{
|
||||
m_entities.push(entities[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Array<Entity>& instances = editor.getEntityTemplateSystem().getInstances(tpl);
|
||||
const Array<Entity>& instances = editor.getEntityTemplateSystem().getInstances(prefab);
|
||||
for (int i = 0; i < instances.size(); ++i)
|
||||
{
|
||||
m_entities.push(instances[i]);
|
||||
|
@ -1080,9 +1080,8 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
u32 tpl = m_editor.getEntityTemplateSystem().getTemplate(m_entities[i]);
|
||||
m_old_values.write(tpl);
|
||||
m_old_values.write(m_editor.getEntityTemplateSystem().getPrefabEntity(m_entities[i]));
|
||||
u64 prefab = m_editor.getEntityTemplateSystem().getPrefab(m_entities[i]);
|
||||
m_old_values.write(prefab);
|
||||
|
||||
universe->destroyEntity(m_entities[i]);
|
||||
}
|
||||
|
@ -1122,12 +1121,9 @@ private:
|
|||
props[k]->set(new_component, -1, blob);
|
||||
}
|
||||
}
|
||||
u32 tpl;
|
||||
u64 tpl;
|
||||
blob.read(tpl);
|
||||
if (tpl) m_editor.getEntityTemplateSystem().setTemplate(new_entity, tpl);
|
||||
PrefabEntity prefab;
|
||||
blob.read(prefab);
|
||||
if (prefab.path_hash) m_editor.getEntityTemplateSystem().setPrefab(new_entity, prefab);
|
||||
if (tpl) m_editor.getEntityTemplateSystem().setPrefab(new_entity, tpl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1177,14 +1173,14 @@ private:
|
|||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (!m_editor.getUniverse()->getComponent(entities[i], m_cmp_type).isValid()) continue;
|
||||
u32 tpl = editor.getEntityTemplateSystem().getTemplate(entities[i]);
|
||||
if (tpl == 0)
|
||||
u64 prefab = editor.getEntityTemplateSystem().getPrefab(entities[i]);
|
||||
if (prefab == 0)
|
||||
{
|
||||
m_entities.push(entities[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Array<Entity>& instances = editor.getEntityTemplateSystem().getInstances(tpl);
|
||||
const Array<Entity>& instances = editor.getEntityTemplateSystem().getInstances(prefab);
|
||||
for (int i = 0; i < instances.size(); ++i)
|
||||
{
|
||||
m_entities.push(instances[i]);
|
||||
|
@ -1676,285 +1672,6 @@ public:
|
|||
bool isUniverseChanged() const override { return m_is_universe_changed; }
|
||||
|
||||
|
||||
struct Serializer : public ISerializer
|
||||
{
|
||||
Serializer(OutputBlob& _blob) : blob(_blob) {}
|
||||
|
||||
void write(const char* label, Entity entity) override
|
||||
{
|
||||
blob << "#" << label << "\n\t"
|
||||
<< entity.index << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, ComponentHandle value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t"
|
||||
<< value.index << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, const Transform& value) override
|
||||
{
|
||||
blob << "#" << label
|
||||
<< " (" << value.pos.x << ", " << value.pos.y << ", " << value.pos.z << ") "
|
||||
<< " (" << value.rot.x << ", " << value.rot.y << ", " << value.rot.z << ", " << value.rot.w << ")\n\t"
|
||||
<< asU32(value.pos.x) << "\n\t" << asU32(value.pos.y) << "\n\t" << asU32(value.pos.z) << "\n\t"
|
||||
<< asU32(value.rot.x) << "\n\t" << asU32(value.rot.y) << "\n\t" << asU32(value.rot.z) << "\n\t" << asU32(value.rot.w) << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, const Vec3& value) override
|
||||
{
|
||||
blob << "#" << label
|
||||
<< " (" << value.x << ", " << value.y << ", " << value.z << ")\n\t"
|
||||
<< asU32(value.x) << "\n\t" << asU32(value.y) << "\n\t" << asU32(value.z) << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, const Vec4& value) override
|
||||
{
|
||||
blob << "#" << label
|
||||
<< " (" << value.x << ", " << value.y << ", " << value.z << ", " << value.w << ")\n\t"
|
||||
<< asU32(value.x) << "\n\t" << asU32(value.y) << "\n\t" << asU32(value.z) << "\n\t" << asU32(value.w) << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, float value) override
|
||||
{
|
||||
blob << "#" << label << " " << value << "\n\t" << asU32(value) << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, bool value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t" << (u32)value << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, const char* value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t\"" << value << "\"\n";
|
||||
}
|
||||
|
||||
void write(const char* label, u32 value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, i64 value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, i32 value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, i8 value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void write(const char* label, u8 value) override
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
static u32 asU32(float v)
|
||||
{
|
||||
return *(u32*)&v;
|
||||
}
|
||||
|
||||
|
||||
OutputBlob& blob;
|
||||
};
|
||||
|
||||
|
||||
struct Deserializer : public IDeserializer
|
||||
{
|
||||
Deserializer(InputBlob& _blob)
|
||||
: blob(_blob)
|
||||
{
|
||||
}
|
||||
|
||||
void read(Entity* entity) override
|
||||
{
|
||||
skip();
|
||||
entity->index = readU32();
|
||||
}
|
||||
|
||||
|
||||
void read(Transform* value) override
|
||||
{
|
||||
skip();
|
||||
value->pos.x = asFloat(readU32());
|
||||
skip();
|
||||
value->pos.y = asFloat(readU32());
|
||||
skip();
|
||||
value->pos.z = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.x = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.y = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.z = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.w = asFloat(readU32());
|
||||
}
|
||||
|
||||
|
||||
void read(Vec3* value) override
|
||||
{
|
||||
skip();
|
||||
value->x = asFloat(readU32());
|
||||
skip();
|
||||
value->y = asFloat(readU32());
|
||||
skip();
|
||||
value->z = asFloat(readU32());
|
||||
}
|
||||
|
||||
|
||||
void read(Vec4* value) override
|
||||
{
|
||||
skip();
|
||||
value->x = asFloat(readU32());
|
||||
skip();
|
||||
value->y = asFloat(readU32());
|
||||
skip();
|
||||
value->z = asFloat(readU32());
|
||||
skip();
|
||||
value->w = asFloat(readU32());
|
||||
}
|
||||
|
||||
void read(ComponentHandle* value) override
|
||||
{
|
||||
skip();
|
||||
value->index = readU32();
|
||||
}
|
||||
|
||||
|
||||
void read(float* value) override
|
||||
{
|
||||
skip();
|
||||
*value = asFloat(readU32());
|
||||
}
|
||||
|
||||
|
||||
void read(bool* value) override
|
||||
{
|
||||
skip();
|
||||
*value = readU32() != 0;
|
||||
}
|
||||
|
||||
|
||||
void read(u32* value) override
|
||||
{
|
||||
skip();
|
||||
*value = readU32();
|
||||
}
|
||||
|
||||
|
||||
void read(i64* value) override
|
||||
{
|
||||
skip();
|
||||
char tmp[40];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
if (*c == '-')
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
fromCString(tmp, lengthOf(tmp), value);
|
||||
}
|
||||
|
||||
|
||||
void read(i32* value) override
|
||||
{
|
||||
skip();
|
||||
char tmp[20];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
if (*c == '-')
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
fromCString(tmp, lengthOf(tmp), value);
|
||||
}
|
||||
|
||||
|
||||
void read(u8* value) override
|
||||
{
|
||||
skip();
|
||||
*value = (u8)readU32();
|
||||
}
|
||||
|
||||
|
||||
void read(i8* value) override
|
||||
{
|
||||
skip();
|
||||
*value = (i8)readU32();
|
||||
}
|
||||
|
||||
|
||||
void read(char* value, int max_size) override
|
||||
{
|
||||
skip();
|
||||
u8 c = blob.readChar();
|
||||
ASSERT(c == '"');
|
||||
char* out = value;
|
||||
*out = blob.readChar();
|
||||
while (*out != '"' && out - value < max_size - 1)
|
||||
{
|
||||
++out;
|
||||
*out = blob.readChar();
|
||||
}
|
||||
ASSERT(*out == '"');
|
||||
*out = 0;
|
||||
}
|
||||
|
||||
|
||||
u32 readU32()
|
||||
{
|
||||
char tmp[20];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
u32 v;
|
||||
fromCString(tmp, lengthOf(tmp), &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void skip()
|
||||
{
|
||||
u8 c = blob.readChar();
|
||||
if (c == '#') while (blob.readChar() != '\n');
|
||||
if (c == '\t') return;
|
||||
while (blob.readChar() != '\t');
|
||||
}
|
||||
|
||||
float asFloat(u32 v)
|
||||
{
|
||||
return *(float*)&v;
|
||||
}
|
||||
|
||||
InputBlob& blob;
|
||||
};
|
||||
|
||||
|
||||
void saveUniverse(const Path& path, bool save_path) override
|
||||
{
|
||||
g_log_info.log("Editor") << "Saving universe " << path << "...";
|
||||
|
@ -1981,6 +1698,7 @@ public:
|
|||
|
||||
void deserialize(const Path& path)
|
||||
{
|
||||
PROFILE_FUNCTION();
|
||||
if (isValid(m_camera)) m_universe->destroyEntity(m_camera);
|
||||
|
||||
PathUtils::FileInfo file_info(path.c_str());
|
||||
|
@ -1996,7 +1714,7 @@ public:
|
|||
data.resize((int)file.size());
|
||||
file.read(&data[0], data.size());
|
||||
InputBlob blob(&data[0], data.size());
|
||||
Deserializer deserializer(blob);
|
||||
TextDeserializer deserializer(blob);
|
||||
x(deserializer);
|
||||
}
|
||||
file.close();
|
||||
|
@ -2006,7 +1724,7 @@ public:
|
|||
while (PlatformInterface::getNextFile(scn_file_iter, &info))
|
||||
{
|
||||
StaticString<MAX_PATH_LENGTH> filepath(scn_dir, info.filename);
|
||||
loadFile(filepath, [&filepath, this](Deserializer& deserializer) {
|
||||
loadFile(filepath, [&filepath, this](TextDeserializer& deserializer) {
|
||||
char plugin_name[64];
|
||||
PathUtils::getBasename(plugin_name, lengthOf(plugin_name), filepath);
|
||||
IScene* scene = m_universe->getScene(crc32(plugin_name)); // todo if scene does not exist
|
||||
|
@ -2016,7 +1734,7 @@ public:
|
|||
PlatformInterface::destroyFileIterator(scn_file_iter);
|
||||
|
||||
StaticString<MAX_PATH_LENGTH> filepath(file_info.m_dir, file_info.m_basename, "/systems/templates.sys");
|
||||
loadFile(filepath, [this](Deserializer& deserializer) {
|
||||
loadFile(filepath, [this](TextDeserializer& deserializer) {
|
||||
m_template_system->deserialize(deserializer);
|
||||
});
|
||||
|
||||
|
@ -2030,7 +1748,7 @@ public:
|
|||
PathUtils::getBasename(tmp, lengthOf(tmp), filepath);
|
||||
Entity entity;
|
||||
fromCString(tmp, lengthOf(tmp), &entity.index);
|
||||
loadFile(filepath, [this, entity](Deserializer& deserializer) {
|
||||
loadFile(filepath, [this, entity](TextDeserializer& deserializer) {
|
||||
char name[64];
|
||||
deserializer.read(name, lengthOf(name));
|
||||
Transform tr;
|
||||
|
@ -2062,7 +1780,7 @@ public:
|
|||
|
||||
FS::OsFile file;
|
||||
OutputBlob blob(m_allocator);
|
||||
Serializer serializer(blob);
|
||||
TextSerializer serializer(blob);
|
||||
auto saveFile = [&file, this, &blob](const char* path) {
|
||||
if (file.open(path, FS::Mode::CREATE_AND_WRITE, m_allocator))
|
||||
{
|
||||
|
@ -2117,7 +1835,6 @@ public:
|
|||
int hashed_offset = sizeof(header);
|
||||
|
||||
header.engine_hash = m_engine->serialize(*m_universe, blob);
|
||||
m_template_system->serialize(blob);
|
||||
m_entity_groups.serialize(blob);
|
||||
header.hash = crc32((const u8*)blob.getData() + hashed_offset, blob.getPos() - hashed_offset);
|
||||
*(Header*)blob.getData() = header;
|
||||
|
@ -2748,7 +2465,6 @@ public:
|
|||
|
||||
if (m_engine->deserialize(*m_universe, blob))
|
||||
{
|
||||
m_template_system->deserialize(blob, header.version > (int)SerializedVersion::PREFABS);
|
||||
if (header.version > (int)SerializedVersion::ENTITY_GROUPS)
|
||||
{
|
||||
m_entity_groups.deserialize(blob);
|
||||
|
|
|
@ -80,6 +80,15 @@ namespace Lumix
|
|||
}
|
||||
|
||||
|
||||
OutputBlob& OutputBlob::operator << (u64 value)
|
||||
{
|
||||
char tmp[40];
|
||||
Lumix::toCString(value, tmp, Lumix::lengthOf(tmp));
|
||||
write(tmp, stringLength(tmp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
OutputBlob& OutputBlob::operator << (i64 value)
|
||||
{
|
||||
char tmp[40];
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Lumix
|
|||
void clear();
|
||||
|
||||
OutputBlob& operator << (const char* str);
|
||||
OutputBlob& operator << (u64 value);
|
||||
OutputBlob& operator << (i64 value);
|
||||
OutputBlob& operator << (i32 value);
|
||||
OutputBlob& operator << (u32 value);
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "lumix.h"
|
||||
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
|
||||
struct Transform;
|
||||
struct Vec3;
|
||||
struct Vec4;
|
||||
|
||||
struct ISerializer
|
||||
{
|
||||
virtual void write(const char* label, Entity entity) = 0;
|
||||
virtual void write(const char* label, ComponentHandle value) = 0;
|
||||
virtual void write(const char* label, const Transform& value) = 0;
|
||||
virtual void write(const char* label, const Vec4& value) = 0;
|
||||
virtual void write(const char* label, const Vec3& value) = 0;
|
||||
virtual void write(const char* label, float value) = 0;
|
||||
virtual void write(const char* label, bool value) = 0;
|
||||
virtual void write(const char* label, i64 value) = 0;
|
||||
virtual void write(const char* label, i32 value) = 0;
|
||||
virtual void write(const char* label, u32 value) = 0;
|
||||
virtual void write(const char* label, i8 value) = 0;
|
||||
virtual void write(const char* label, u8 value) = 0;
|
||||
virtual void write(const char* label, const char* value) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct IDeserializer
|
||||
{
|
||||
virtual void read(Entity* entity) = 0;
|
||||
virtual void read(ComponentHandle* value) = 0;
|
||||
virtual void read(Transform* value) = 0;
|
||||
virtual void read(Vec4* value) = 0;
|
||||
virtual void read(Vec3* value) = 0;
|
||||
virtual void read(float* value) = 0;
|
||||
virtual void read(bool* value) = 0;
|
||||
virtual void read(i64* value) = 0;
|
||||
virtual void read(u32* value) = 0;
|
||||
virtual void read(i32* value) = 0;
|
||||
virtual void read(u8* value) = 0;
|
||||
virtual void read(i8* value) = 0;
|
||||
virtual void read(char* value, int max_size) = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
291
src/engine/serializer.cpp
Normal file
291
src/engine/serializer.cpp
Normal file
|
@ -0,0 +1,291 @@
|
|||
#include "serializer.h"
|
||||
#include "engine/blob.h"
|
||||
#include "engine/matrix.h"
|
||||
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
|
||||
|
||||
static u32 asU32(float v)
|
||||
{
|
||||
return *(u32*)&v;
|
||||
}
|
||||
|
||||
|
||||
static float asFloat(u32 v)
|
||||
{
|
||||
return *(float*)&v;
|
||||
}
|
||||
|
||||
|
||||
void TextSerializer::write(const char* label, Entity entity)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << entity.index << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, ComponentHandle value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value.index << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, const Transform& value)
|
||||
{
|
||||
blob << "#" << label << " (" << value.pos.x << ", " << value.pos.y << ", " << value.pos.z << ") "
|
||||
<< " (" << value.rot.x << ", " << value.rot.y << ", " << value.rot.z << ", " << value.rot.w << ")\n\t"
|
||||
<< asU32(value.pos.x) << "\n\t" << asU32(value.pos.y) << "\n\t" << asU32(value.pos.z) << "\n\t"
|
||||
<< asU32(value.rot.x) << "\n\t" << asU32(value.rot.y) << "\n\t" << asU32(value.rot.z) << "\n\t"
|
||||
<< asU32(value.rot.w) << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, const Vec3& value)
|
||||
{
|
||||
blob << "#" << label << " (" << value.x << ", " << value.y << ", " << value.z << ")\n\t" << asU32(value.x) << "\n\t"
|
||||
<< asU32(value.y) << "\n\t" << asU32(value.z) << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, const Vec4& value)
|
||||
{
|
||||
blob << "#" << label << " (" << value.x << ", " << value.y << ", " << value.z << ", " << value.w << ")\n\t"
|
||||
<< asU32(value.x) << "\n\t" << asU32(value.y) << "\n\t" << asU32(value.z) << "\n\t" << asU32(value.w) << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, float value)
|
||||
{
|
||||
blob << "#" << label << " " << value << "\n\t" << asU32(value) << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, bool value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << (u32)value << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, const char* value)
|
||||
{
|
||||
blob << "#" << label << "\n\t\"" << value << "\"\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, u32 value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, i64 value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, u64 value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, i32 value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, i8 value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
void TextSerializer::write(const char* label, u8 value)
|
||||
{
|
||||
blob << "#" << label << "\n\t" << value << "\n";
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(Entity* entity)
|
||||
{
|
||||
skip();
|
||||
entity->index = readU32();
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(Transform* value)
|
||||
{
|
||||
skip();
|
||||
value->pos.x = asFloat(readU32());
|
||||
skip();
|
||||
value->pos.y = asFloat(readU32());
|
||||
skip();
|
||||
value->pos.z = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.x = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.y = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.z = asFloat(readU32());
|
||||
skip();
|
||||
value->rot.w = asFloat(readU32());
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(Vec3* value)
|
||||
{
|
||||
skip();
|
||||
value->x = asFloat(readU32());
|
||||
skip();
|
||||
value->y = asFloat(readU32());
|
||||
skip();
|
||||
value->z = asFloat(readU32());
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(Vec4* value)
|
||||
{
|
||||
skip();
|
||||
value->x = asFloat(readU32());
|
||||
skip();
|
||||
value->y = asFloat(readU32());
|
||||
skip();
|
||||
value->z = asFloat(readU32());
|
||||
skip();
|
||||
value->w = asFloat(readU32());
|
||||
}
|
||||
|
||||
void TextDeserializer::read(ComponentHandle* value)
|
||||
{
|
||||
skip();
|
||||
value->index = readU32();
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(float* value)
|
||||
{
|
||||
skip();
|
||||
*value = asFloat(readU32());
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(bool* value)
|
||||
{
|
||||
skip();
|
||||
*value = readU32() != 0;
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(u32* value)
|
||||
{
|
||||
skip();
|
||||
*value = readU32();
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(u64* value)
|
||||
{
|
||||
skip();
|
||||
char tmp[40];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
fromCString(tmp, lengthOf(tmp), value);
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(i64* value)
|
||||
{
|
||||
skip();
|
||||
char tmp[40];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
if (*c == '-')
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
fromCString(tmp, lengthOf(tmp), value);
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(i32* value)
|
||||
{
|
||||
skip();
|
||||
char tmp[20];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
if (*c == '-')
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
fromCString(tmp, lengthOf(tmp), value);
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(u8* value)
|
||||
{
|
||||
skip();
|
||||
*value = (u8)readU32();
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(i8* value)
|
||||
{
|
||||
skip();
|
||||
*value = (i8)readU32();
|
||||
}
|
||||
|
||||
|
||||
void TextDeserializer::read(char* value, int max_size)
|
||||
{
|
||||
skip();
|
||||
u8 c = blob.readChar();
|
||||
ASSERT(c == '"');
|
||||
char* out = value;
|
||||
*out = blob.readChar();
|
||||
while (*out != '"' && out - value < max_size - 1)
|
||||
{
|
||||
++out;
|
||||
*out = blob.readChar();
|
||||
}
|
||||
ASSERT(*out == '"');
|
||||
*out = 0;
|
||||
}
|
||||
|
||||
|
||||
u32 TextDeserializer::readU32()
|
||||
{
|
||||
char tmp[20];
|
||||
char* c = tmp;
|
||||
*c = blob.readChar();
|
||||
while (*c >= '0' && *c <= '9' && (c - tmp) < lengthOf(tmp))
|
||||
{
|
||||
++c;
|
||||
*c = blob.readChar();
|
||||
}
|
||||
*c = 0;
|
||||
u32 v;
|
||||
fromCString(tmp, lengthOf(tmp), &v);
|
||||
return v;
|
||||
}
|
||||
|
||||
void TextDeserializer::skip()
|
||||
{
|
||||
u8 c = blob.readChar();
|
||||
if (c == '#')
|
||||
while (blob.readChar() != '\n')
|
||||
;
|
||||
if (c == '\t') return;
|
||||
while (blob.readChar() != '\t')
|
||||
;
|
||||
}
|
||||
}
|
107
src/engine/serializer.h
Normal file
107
src/engine/serializer.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "lumix.h"
|
||||
|
||||
|
||||
namespace Lumix
|
||||
{
|
||||
|
||||
class InputBlob;
|
||||
class OutputBlob;
|
||||
struct Transform;
|
||||
struct Vec3;
|
||||
struct Vec4;
|
||||
|
||||
|
||||
struct ISerializer
|
||||
{
|
||||
virtual void write(const char* label, Entity entity) = 0;
|
||||
virtual void write(const char* label, ComponentHandle value) = 0;
|
||||
virtual void write(const char* label, const Transform& value) = 0;
|
||||
virtual void write(const char* label, const Vec4& value) = 0;
|
||||
virtual void write(const char* label, const Vec3& value) = 0;
|
||||
virtual void write(const char* label, float value) = 0;
|
||||
virtual void write(const char* label, bool value) = 0;
|
||||
virtual void write(const char* label, i64 value) = 0;
|
||||
virtual void write(const char* label, u64 value) = 0;
|
||||
virtual void write(const char* label, i32 value) = 0;
|
||||
virtual void write(const char* label, u32 value) = 0;
|
||||
virtual void write(const char* label, i8 value) = 0;
|
||||
virtual void write(const char* label, u8 value) = 0;
|
||||
virtual void write(const char* label, const char* value) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct IDeserializer
|
||||
{
|
||||
virtual void read(Entity* entity) = 0;
|
||||
virtual void read(ComponentHandle* value) = 0;
|
||||
virtual void read(Transform* value) = 0;
|
||||
virtual void read(Vec4* value) = 0;
|
||||
virtual void read(Vec3* value) = 0;
|
||||
virtual void read(float* value) = 0;
|
||||
virtual void read(bool* value) = 0;
|
||||
virtual void read(u64* value) = 0;
|
||||
virtual void read(i64* value) = 0;
|
||||
virtual void read(u32* value) = 0;
|
||||
virtual void read(i32* value) = 0;
|
||||
virtual void read(u8* value) = 0;
|
||||
virtual void read(i8* value) = 0;
|
||||
virtual void read(char* value, int max_size) = 0;
|
||||
};
|
||||
|
||||
|
||||
struct TextSerializer : public ISerializer
|
||||
{
|
||||
TextSerializer(OutputBlob& _blob) : blob(_blob) {}
|
||||
|
||||
virtual void write(const char* label, Entity entity) override;
|
||||
virtual void write(const char* label, ComponentHandle value) override;
|
||||
virtual void write(const char* label, const Transform& value) override;
|
||||
virtual void write(const char* label, const Vec4& value) override;
|
||||
virtual void write(const char* label, const Vec3& value) override;
|
||||
virtual void write(const char* label, float value) override;
|
||||
virtual void write(const char* label, bool value) override;
|
||||
virtual void write(const char* label, i64 value) override;
|
||||
virtual void write(const char* label, u64 value) override;
|
||||
virtual void write(const char* label, i32 value) override;
|
||||
virtual void write(const char* label, u32 value) override;
|
||||
virtual void write(const char* label, i8 value) override;
|
||||
virtual void write(const char* label, u8 value) override;
|
||||
virtual void write(const char* label, const char* value) override;
|
||||
|
||||
OutputBlob& blob;
|
||||
};
|
||||
|
||||
|
||||
struct TextDeserializer : public IDeserializer
|
||||
{
|
||||
TextDeserializer(InputBlob& _blob)
|
||||
: blob(_blob)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void read(Entity* entity) override;
|
||||
virtual void read(ComponentHandle* value) override;
|
||||
virtual void read(Transform* value) override;
|
||||
virtual void read(Vec4* value) override;
|
||||
virtual void read(Vec3* value) override;
|
||||
virtual void read(float* value) override;
|
||||
virtual void read(bool* value) override;
|
||||
virtual void read(u64* value) override;
|
||||
virtual void read(i64* value) override;
|
||||
virtual void read(u32* value) override;
|
||||
virtual void read(i32* value) override;
|
||||
virtual void read(u8* value) override;
|
||||
virtual void read(i8* value) override;
|
||||
virtual void read(char* value, int max_size) override;
|
||||
|
||||
void skip();
|
||||
u32 readU32();
|
||||
|
||||
InputBlob& blob;
|
||||
};
|
||||
|
||||
|
||||
}
|
|
@ -298,6 +298,29 @@ const char* fromCString(const char* input, int length, u32* value)
|
|||
}
|
||||
|
||||
|
||||
const char* fromCString(const char* input, int length, u64* value)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
const char* c = input;
|
||||
*value = 0;
|
||||
if (*c == '-')
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
while (length && *c >= '0' && *c <= '9')
|
||||
{
|
||||
*value *= 10;
|
||||
*value += *c - '0';
|
||||
++c;
|
||||
--length;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool toCStringPretty(i32 value, char* output, int length)
|
||||
{
|
||||
char* c = output;
|
||||
|
|
|
@ -21,6 +21,7 @@ LUMIX_ENGINE_API bool toCString(u32 value, char* output, int length);
|
|||
LUMIX_ENGINE_API bool toCString(float value, char* output, int length, int after_point);
|
||||
LUMIX_ENGINE_API const char* reverseFind(const char* begin_haystack, const char* end_haystack, char c);
|
||||
LUMIX_ENGINE_API const char* fromCString(const char* input, int length, i32* value);
|
||||
LUMIX_ENGINE_API const char* fromCString(const char* input, int length, u64* value);
|
||||
LUMIX_ENGINE_API const char* fromCString(const char* input, int length, i64* value);
|
||||
LUMIX_ENGINE_API const char* fromCString(const char* input, int length, u32* value);
|
||||
LUMIX_ENGINE_API bool copyString(char* destination, int length, const char* source);
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
#include "engine/blob.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/hash_map.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "universe.h"
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "engine/fs/file_system.h"
|
||||
#include "engine/iallocator.h"
|
||||
#include "engine/iplugin.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/log.h"
|
||||
#include "engine/lua_wrapper.h"
|
||||
|
@ -19,6 +18,7 @@
|
|||
#include "engine/property_descriptor.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/string.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "lua_script/lua_script_manager.h"
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
#include "engine/engine.h"
|
||||
#include "engine/fs/os_file.h"
|
||||
#include "engine/iallocator.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/log.h"
|
||||
#include "engine/lua_wrapper.h"
|
||||
#include "engine/lumix.h"
|
||||
#include "engine/profiler.h"
|
||||
#include "engine/property_descriptor.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "engine/vec.h"
|
||||
#include "lua_script/lua_script_system.h"
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "engine/crc32.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/fs/file_system.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/log.h"
|
||||
#include "engine/lua_wrapper.h"
|
||||
|
@ -14,6 +13,7 @@
|
|||
#include "engine/property_register.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/resource_manager_base.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "lua_script/lua_script_system.h"
|
||||
#include "physics/physics_geometry_manager.h"
|
||||
|
|
|
@ -286,10 +286,6 @@ void SceneView::handleDrop(float x, float y)
|
|||
|
||||
if (hit.m_is_hit)
|
||||
{
|
||||
if (Lumix::PathUtils::hasExtension(path, "fab"))
|
||||
{
|
||||
m_editor->getEntityTemplateSystem().instantiatePrefab(hit.m_origin + hit.m_t * hit.m_dir, Lumix::Path(path));
|
||||
}
|
||||
if (Lumix::PathUtils::hasExtension(path, "msh"))
|
||||
{
|
||||
auto* command = LUMIX_NEW(m_editor->getAllocator(), InsertMeshCommand)(
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
#include "terrain_editor.h"
|
||||
#include "engine/blob.h"
|
||||
#include "engine/crc32.h"
|
||||
#include "engine/geometry.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/profiler.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/resource_manager_base.h"
|
||||
#include "editor/asset_browser.h"
|
||||
#include "editor/entity_template_system.h"
|
||||
#include "editor/ieditor_command.h"
|
||||
#include "editor/platform_interface.h"
|
||||
#include "editor/studio_app.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#if defined _MSC_VER && _MSC_VER == 1900
|
||||
#pragma warning(disable : 4312)
|
||||
#endif
|
||||
#include "stb/stb_image.h"
|
||||
#include "editor/utils.h"
|
||||
#include "engine/blob.h"
|
||||
#include "engine/crc32.h"
|
||||
#include "engine/engine.h"
|
||||
#include "engine/geometry.h"
|
||||
#include "engine/iproperty_descriptor.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/prefab.h"
|
||||
#include "engine/profiler.h"
|
||||
#include "engine/property_register.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/resource_manager_base.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "physics/physics_scene.h"
|
||||
#include "renderer/material.h"
|
||||
#include "renderer/model.h"
|
||||
#include "renderer/render_scene.h"
|
||||
#include "renderer/texture.h"
|
||||
#include "renderer/terrain.h"
|
||||
#include "engine/universe/universe.h"
|
||||
#include "renderer/texture.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#if defined _MSC_VER && _MSC_VER == 1900
|
||||
#pragma warning(disable : 4312)
|
||||
#endif
|
||||
#include "stb/stb_image.h"
|
||||
#include <cmath>
|
||||
|
||||
|
||||
|
@ -35,6 +37,7 @@ static const Lumix::ComponentType TERRAIN_TYPE = Lumix::PropertyRegister::getCom
|
|||
static const Lumix::ComponentType HEIGHTFIELD_TYPE = Lumix::PropertyRegister::getComponentType("physical_heightfield");
|
||||
static const Lumix::ResourceType MATERIAL_TYPE("material");
|
||||
static const Lumix::ResourceType TEXTURE_TYPE("texture");
|
||||
static const Lumix::ResourceType PREFAB_TYPE("prefab");
|
||||
static const char* HEIGHTMAP_UNIFORM = "u_texHeightmap";
|
||||
static const char* SPLATMAP_UNIFORM = "u_texSplatmap";
|
||||
static const char* COLORMAP_UNIFORM = "u_texColormap";
|
||||
|
@ -710,9 +713,10 @@ static Lumix::IEditorCommand* createPaintTerrainCommand(Lumix::WorldEditor& edit
|
|||
|
||||
TerrainEditor::TerrainEditor(Lumix::WorldEditor& editor, StudioApp& app)
|
||||
: m_world_editor(editor)
|
||||
, m_app(app)
|
||||
, m_color(1, 1, 1)
|
||||
, m_current_brush(0)
|
||||
, m_selected_entity_templates(editor.getAllocator())
|
||||
, m_selected_prefabs(editor.getAllocator())
|
||||
, m_brush_mask(editor.getAllocator())
|
||||
, m_brush_texture(nullptr)
|
||||
, m_flat_height(0)
|
||||
|
@ -965,6 +969,7 @@ bool TerrainEditor::onEntityMouseDown(const Lumix::WorldEditor::RayHit& hit, int
|
|||
|
||||
void TerrainEditor::removeEntities(const Lumix::Vec3& hit_pos)
|
||||
{
|
||||
/*
|
||||
if (m_selected_entity_templates.empty()) return;
|
||||
auto& template_system = m_world_editor.getEntityTemplateSystem();
|
||||
auto& template_names = template_system.getTemplateNames();
|
||||
|
@ -1004,7 +1009,9 @@ void TerrainEditor::removeEntities(const Lumix::Vec3& hit_pos)
|
|||
}
|
||||
}
|
||||
|
||||
m_world_editor.endCommandGroup();
|
||||
m_world_editor.endCommandGroup();*/
|
||||
// TODO
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1117,9 +1124,8 @@ static bool isOBBCollision(Lumix::RenderScene& scene,
|
|||
void TerrainEditor::paintEntities(const Lumix::Vec3& hit_pos)
|
||||
{
|
||||
PROFILE_FUNCTION();
|
||||
if (m_selected_entity_templates.empty()) return;
|
||||
if (m_selected_prefabs.empty()) return;
|
||||
auto& template_system = m_world_editor.getEntityTemplateSystem();
|
||||
auto& template_names = template_system.getTemplateNames();
|
||||
|
||||
static const Lumix::u32 PAINT_ENTITIES_HASH = Lumix::crc32("paint_entities");
|
||||
m_world_editor.beginCommandGroup(PAINT_ENTITIES_HASH);
|
||||
|
@ -1132,21 +1138,9 @@ void TerrainEditor::paintEntities(const Lumix::Vec3& hit_pos)
|
|||
struct Tpl
|
||||
{
|
||||
Lumix::ComponentHandle cmp;
|
||||
int template_idx;
|
||||
Lumix::u32 prefab;
|
||||
};
|
||||
|
||||
Lumix::Array<Tpl> tpls(m_world_editor.getAllocator());
|
||||
tpls.reserve(m_selected_entity_templates.size());
|
||||
for(int idx : m_selected_entity_templates)
|
||||
{
|
||||
Lumix::u32 hash = Lumix::crc32(template_names[idx].c_str());
|
||||
Lumix::Entity tpl = template_system.getInstances(hash)[0];
|
||||
if(!isValid(tpl)) continue;
|
||||
Lumix::ComponentUID model_instance = m_world_editor.getUniverse()->getComponent(tpl, MODEL_INSTANCE_TYPE);
|
||||
if(!model_instance.isValid()) continue;
|
||||
tpls.push({model_instance.handle, idx});
|
||||
}
|
||||
|
||||
Lumix::Frustum frustum;
|
||||
frustum.computeOrtho(hit_pos,
|
||||
Lumix::Vec3(0, 0, 1),
|
||||
|
@ -1161,10 +1155,6 @@ void TerrainEditor::paintEntities(const Lumix::Vec3& hit_pos)
|
|||
float scale = 1.0f - Lumix::Math::maximum(0.01f, m_terrain_brush_strength);
|
||||
for (int i = 0; i <= m_terrain_brush_size * m_terrain_brush_size / 1000.0f; ++i)
|
||||
{
|
||||
int model_instance_idx = Lumix::Math::rand() % tpls.size();
|
||||
Lumix::Model* model = scene->getModelInstanceModel(tpls[model_instance_idx].cmp);
|
||||
const auto* template_name = template_names[tpls[model_instance_idx].template_idx].c_str();
|
||||
|
||||
float angle = Lumix::Math::randFloat(0, Lumix::Math::PI * 2);
|
||||
float dist = Lumix::Math::randFloat(0, 1.0f) * m_terrain_brush_size;
|
||||
float y = Lumix::Math::randFloat(m_y_spread.x, m_y_spread.y);
|
||||
|
@ -1172,49 +1162,48 @@ void TerrainEditor::paintEntities(const Lumix::Vec3& hit_pos)
|
|||
Lumix::Vec3 terrain_pos = inv_terrain_matrix.transform(pos);
|
||||
if (terrain_pos.x >= 0 && terrain_pos.z >= 0 && terrain_pos.x <= size.x && terrain_pos.z <= size.y)
|
||||
{
|
||||
// TODO check obb collision with other entities, see isOBBCollision
|
||||
|
||||
pos.y = scene->getTerrainHeightAt(m_component.handle, terrain_pos.x, terrain_pos.z) + y;
|
||||
pos.y += terrain_matrix.getTranslation().y;
|
||||
if(!isOBBCollision(*scene, meshes, pos, model, scale))
|
||||
Lumix::Quat rot(0, 0, 0, 1);
|
||||
if(m_is_align_with_normal)
|
||||
{
|
||||
Lumix::Quat rot(0, 0, 0, 1);
|
||||
if(m_is_align_with_normal)
|
||||
{
|
||||
Lumix::RenderScene* scene = static_cast<Lumix::RenderScene*>(m_component.scene);
|
||||
Lumix::Vec3 normal = scene->getTerrainNormalAt(m_component.handle, pos.x, pos.z);
|
||||
Lumix::Vec3 dir = Lumix::crossProduct(normal, Lumix::Vec3(1, 0, 0)).normalized();
|
||||
Lumix::Matrix mtx = Lumix::Matrix::IDENTITY;
|
||||
mtx.setXVector(Lumix::crossProduct(normal, dir));
|
||||
mtx.setYVector(normal);
|
||||
mtx.setXVector(dir);
|
||||
rot = mtx.getRotation();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_is_rotate_x)
|
||||
{
|
||||
float angle = Lumix::Math::randFloat(m_rotate_x_spread.x, m_rotate_x_spread.y);
|
||||
Lumix::Quat q(Lumix::Vec3(1, 0, 0), angle);
|
||||
rot = q * rot;
|
||||
}
|
||||
|
||||
if (m_is_rotate_y)
|
||||
{
|
||||
float angle = Lumix::Math::randFloat(m_rotate_y_spread.x, m_rotate_y_spread.y);
|
||||
Lumix::Quat q(Lumix::Vec3(0, 1, 0), angle);
|
||||
rot = q * rot;
|
||||
}
|
||||
|
||||
if (m_is_rotate_z)
|
||||
{
|
||||
float angle = Lumix::Math::randFloat(m_rotate_z_spread.x, m_rotate_z_spread.y);
|
||||
Lumix::Quat q(rot.rotate(Lumix::Vec3(0, 0, 1)), angle);
|
||||
rot = q * rot;
|
||||
}
|
||||
}
|
||||
|
||||
float size = Lumix::Math::randFloat(m_size_spread.x, m_size_spread.y);
|
||||
auto entity = template_system.createInstance(template_name, pos, rot, size);
|
||||
Lumix::RenderScene* scene = static_cast<Lumix::RenderScene*>(m_component.scene);
|
||||
Lumix::Vec3 normal = scene->getTerrainNormalAt(m_component.handle, pos.x, pos.z);
|
||||
Lumix::Vec3 dir = Lumix::crossProduct(normal, Lumix::Vec3(1, 0, 0)).normalized();
|
||||
Lumix::Matrix mtx = Lumix::Matrix::IDENTITY;
|
||||
mtx.setXVector(Lumix::crossProduct(normal, dir));
|
||||
mtx.setYVector(normal);
|
||||
mtx.setXVector(dir);
|
||||
rot = mtx.getRotation();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_is_rotate_x)
|
||||
{
|
||||
float angle = Lumix::Math::randFloat(m_rotate_x_spread.x, m_rotate_x_spread.y);
|
||||
Lumix::Quat q(Lumix::Vec3(1, 0, 0), angle);
|
||||
rot = q * rot;
|
||||
}
|
||||
|
||||
if (m_is_rotate_y)
|
||||
{
|
||||
float angle = Lumix::Math::randFloat(m_rotate_y_spread.x, m_rotate_y_spread.y);
|
||||
Lumix::Quat q(Lumix::Vec3(0, 1, 0), angle);
|
||||
rot = q * rot;
|
||||
}
|
||||
|
||||
if (m_is_rotate_z)
|
||||
{
|
||||
float angle = Lumix::Math::randFloat(m_rotate_z_spread.x, m_rotate_z_spread.y);
|
||||
Lumix::Quat q(rot.rotate(Lumix::Vec3(0, 0, 1)), angle);
|
||||
rot = q * rot;
|
||||
}
|
||||
}
|
||||
|
||||
float size = Lumix::Math::randFloat(m_size_spread.x, m_size_spread.y);
|
||||
template_system.instantiatePrefab(*m_selected_prefabs[0], pos, rot, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1437,86 +1426,76 @@ void TerrainEditor::onGUI()
|
|||
case ENTITY:
|
||||
{
|
||||
m_action_type = TerrainEditor::ENTITY;
|
||||
auto& template_system = m_world_editor.getEntityTemplateSystem();
|
||||
auto& template_names = template_system.getTemplateNames();
|
||||
if (template_names.empty())
|
||||
Lumix::StaticString<Lumix::MAX_PATH_LENGTH> tmp;
|
||||
if (!m_selected_prefabs.empty())
|
||||
{
|
||||
ImGui::Text("No templates, please create one.");
|
||||
tmp = m_selected_prefabs[0]->getPath().c_str();
|
||||
}
|
||||
else
|
||||
if (m_app.getAssetBrowser()->resourceInput("Prefab", "prefab", tmp.data, Lumix::lengthOf(tmp.data), PREFAB_TYPE))
|
||||
{
|
||||
ImGui::BeginChild("entities", ImVec2(0, 150));
|
||||
for(int i = 0; i < template_names.size(); ++i)
|
||||
if (!m_selected_prefabs.empty())
|
||||
{
|
||||
int index_of = m_selected_entity_templates.indexOf(i);
|
||||
bool b = index_of >= 0;
|
||||
if(ImGui::Checkbox(template_names[i].c_str(), &b))
|
||||
{
|
||||
if(b)
|
||||
{
|
||||
m_selected_entity_templates.push(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_selected_entity_templates.eraseFast(index_of);
|
||||
}
|
||||
}
|
||||
m_selected_prefabs[0]->getResourceManager().unload(*m_selected_prefabs[0]);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
if(ImGui::Checkbox("Align with normal", &m_is_align_with_normal))
|
||||
else
|
||||
{
|
||||
if(m_is_align_with_normal) m_is_rotate_x = m_is_rotate_y = m_is_rotate_z = false;
|
||||
m_selected_prefabs.emplace();
|
||||
}
|
||||
if (ImGui::Checkbox("Rotate around X", &m_is_rotate_x))
|
||||
{
|
||||
if (m_is_rotate_x) m_is_align_with_normal = false;
|
||||
}
|
||||
if (m_is_rotate_x)
|
||||
{
|
||||
Lumix::Vec2 tmp = m_rotate_x_spread;
|
||||
tmp.x = Lumix::Math::radiansToDegrees(tmp.x);
|
||||
tmp.y = Lumix::Math::radiansToDegrees(tmp.y);
|
||||
if (ImGui::DragFloat2("Rotate X spread", &tmp.x))
|
||||
{
|
||||
m_rotate_x_spread.x = Lumix::Math::degreesToRadians(tmp.x);
|
||||
m_rotate_x_spread.y = Lumix::Math::degreesToRadians(tmp.y);
|
||||
}
|
||||
}
|
||||
if (ImGui::Checkbox("Rotate around Y", &m_is_rotate_y))
|
||||
{
|
||||
if (m_is_rotate_y) m_is_align_with_normal = false;
|
||||
}
|
||||
if (m_is_rotate_y)
|
||||
{
|
||||
Lumix::Vec2 tmp = m_rotate_y_spread;
|
||||
tmp.x = Lumix::Math::radiansToDegrees(tmp.x);
|
||||
tmp.y = Lumix::Math::radiansToDegrees(tmp.y);
|
||||
if (ImGui::DragFloat2("Rotate Y spread", &tmp.x))
|
||||
{
|
||||
m_rotate_y_spread.x = Lumix::Math::degreesToRadians(tmp.x);
|
||||
m_rotate_y_spread.y = Lumix::Math::degreesToRadians(tmp.y);
|
||||
}
|
||||
}
|
||||
if(ImGui::Checkbox("Rotate around Z", &m_is_rotate_z))
|
||||
{
|
||||
if(m_is_rotate_z) m_is_align_with_normal = false;
|
||||
}
|
||||
if (m_is_rotate_z)
|
||||
{
|
||||
Lumix::Vec2 tmp = m_rotate_z_spread;
|
||||
tmp.x = Lumix::Math::radiansToDegrees(tmp.x);
|
||||
tmp.y = Lumix::Math::radiansToDegrees(tmp.y);
|
||||
if (ImGui::DragFloat2("Rotate Z spread", &tmp.x))
|
||||
{
|
||||
m_rotate_z_spread.x = Lumix::Math::degreesToRadians(tmp.x);
|
||||
m_rotate_z_spread.y = Lumix::Math::degreesToRadians(tmp.y);
|
||||
}
|
||||
}
|
||||
ImGui::DragFloat2("Size spread", &m_size_spread.x, 0.01f);
|
||||
m_size_spread.x = Lumix::Math::minimum(m_size_spread.x, m_size_spread.y);
|
||||
ImGui::DragFloat2("Y spread", &m_y_spread.x, 0.01f);
|
||||
m_y_spread.x = Lumix::Math::minimum(m_y_spread.x, m_y_spread.y);
|
||||
m_selected_prefabs[0] = (Lumix::PrefabResource*)m_world_editor.getEngine().getResourceManager().get(PREFAB_TYPE)->load(Lumix::Path(tmp));
|
||||
}
|
||||
if(ImGui::Checkbox("Align with normal", &m_is_align_with_normal))
|
||||
{
|
||||
if(m_is_align_with_normal) m_is_rotate_x = m_is_rotate_y = m_is_rotate_z = false;
|
||||
}
|
||||
if (ImGui::Checkbox("Rotate around X", &m_is_rotate_x))
|
||||
{
|
||||
if (m_is_rotate_x) m_is_align_with_normal = false;
|
||||
}
|
||||
if (m_is_rotate_x)
|
||||
{
|
||||
Lumix::Vec2 tmp = m_rotate_x_spread;
|
||||
tmp.x = Lumix::Math::radiansToDegrees(tmp.x);
|
||||
tmp.y = Lumix::Math::radiansToDegrees(tmp.y);
|
||||
if (ImGui::DragFloat2("Rotate X spread", &tmp.x))
|
||||
{
|
||||
m_rotate_x_spread.x = Lumix::Math::degreesToRadians(tmp.x);
|
||||
m_rotate_x_spread.y = Lumix::Math::degreesToRadians(tmp.y);
|
||||
}
|
||||
}
|
||||
if (ImGui::Checkbox("Rotate around Y", &m_is_rotate_y))
|
||||
{
|
||||
if (m_is_rotate_y) m_is_align_with_normal = false;
|
||||
}
|
||||
if (m_is_rotate_y)
|
||||
{
|
||||
Lumix::Vec2 tmp = m_rotate_y_spread;
|
||||
tmp.x = Lumix::Math::radiansToDegrees(tmp.x);
|
||||
tmp.y = Lumix::Math::radiansToDegrees(tmp.y);
|
||||
if (ImGui::DragFloat2("Rotate Y spread", &tmp.x))
|
||||
{
|
||||
m_rotate_y_spread.x = Lumix::Math::degreesToRadians(tmp.x);
|
||||
m_rotate_y_spread.y = Lumix::Math::degreesToRadians(tmp.y);
|
||||
}
|
||||
}
|
||||
if(ImGui::Checkbox("Rotate around Z", &m_is_rotate_z))
|
||||
{
|
||||
if(m_is_rotate_z) m_is_align_with_normal = false;
|
||||
}
|
||||
if (m_is_rotate_z)
|
||||
{
|
||||
Lumix::Vec2 tmp = m_rotate_z_spread;
|
||||
tmp.x = Lumix::Math::radiansToDegrees(tmp.x);
|
||||
tmp.y = Lumix::Math::radiansToDegrees(tmp.y);
|
||||
if (ImGui::DragFloat2("Rotate Z spread", &tmp.x))
|
||||
{
|
||||
m_rotate_z_spread.x = Lumix::Math::degreesToRadians(tmp.x);
|
||||
m_rotate_z_spread.y = Lumix::Math::degreesToRadians(tmp.y);
|
||||
}
|
||||
}
|
||||
ImGui::DragFloat2("Size spread", &m_size_spread.x, 0.01f);
|
||||
m_size_spread.x = Lumix::Math::minimum(m_size_spread.x, m_size_spread.y);
|
||||
ImGui::DragFloat2("Y spread", &m_y_spread.x, 0.01f);
|
||||
m_y_spread.x = Lumix::Math::minimum(m_y_spread.x, m_y_spread.y);
|
||||
}
|
||||
break;
|
||||
default: ASSERT(false); break;
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Lumix
|
|||
{
|
||||
class Material;
|
||||
class Model;
|
||||
struct PrefabResource;
|
||||
class RenderScene;
|
||||
class Texture;
|
||||
}
|
||||
|
@ -66,6 +67,7 @@ private:
|
|||
|
||||
private:
|
||||
Lumix::WorldEditor& m_world_editor;
|
||||
StudioApp& m_app;
|
||||
ActionType m_action_type;
|
||||
Lumix::ComponentUID m_component;
|
||||
float m_terrain_brush_strength;
|
||||
|
@ -75,7 +77,7 @@ private:
|
|||
Lumix::u16 m_flat_height;
|
||||
Lumix::Vec3 m_color;
|
||||
int m_current_brush;
|
||||
Lumix::Array<int> m_selected_entity_templates;
|
||||
Lumix::Array<Lumix::PrefabResource*> m_selected_prefabs;
|
||||
Action* m_increase_brush_size;
|
||||
Action* m_decrease_brush_size;
|
||||
Action* m_increase_texture_idx;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "engine/crc32.h"
|
||||
#include "engine/fs/file_system.h"
|
||||
#include "engine/geometry.h"
|
||||
#include "engine/iserializer.h"
|
||||
#include "engine/json_serializer.h"
|
||||
#include "engine/lifo_allocator.h"
|
||||
#include "engine/log.h"
|
||||
|
@ -20,6 +19,7 @@
|
|||
#include "engine/property_register.h"
|
||||
#include "engine/resource_manager.h"
|
||||
#include "engine/resource_manager_base.h"
|
||||
#include "engine/serializer.h"
|
||||
#include "engine/timer.h"
|
||||
|
||||
#include "engine/engine.h"
|
||||
|
|
Loading…
Reference in a new issue