text format - prefabs

This commit is contained in:
Mikulas Florek 2016-12-11 21:44:47 +01:00
parent 1e6b082087
commit 0247b351a0
21 changed files with 696 additions and 1292 deletions

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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;
};

View file

@ -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;
};

View file

@ -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);

View file

@ -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];

View file

@ -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);

View file

@ -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
View 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
View 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;
};
}

View file

@ -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;

View file

@ -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);

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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)(

View file

@ -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;

View file

@ -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;

View file

@ -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"