271 lines
6.5 KiB
C++
271 lines
6.5 KiB
C++
#include "editor_icon.h"
|
|
#include "editor/world_editor.h"
|
|
#include "engine/crt.h"
|
|
#include "engine/engine.h"
|
|
#include "engine/geometry.h"
|
|
#include "engine/math.h"
|
|
#include "engine/os.h"
|
|
#include "engine/reflection.h"
|
|
#include "engine/resource_manager.h"
|
|
#include "engine/universe.h"
|
|
#include "renderer/model.h"
|
|
#include "renderer/render_scene.h"
|
|
|
|
|
|
namespace Lumix
|
|
{
|
|
|
|
|
|
static const ComponentType MODEL_INSTANCE_TYPE = Reflection::getComponentType("model_instance");
|
|
static const ComponentType PHYSICAL_CONTROLLER_TYPE = Reflection::getComponentType("physical_controller");
|
|
static const ComponentType CAMERA_TYPE = Reflection::getComponentType("camera");
|
|
static const ComponentType ENVIRONMENT_TYPE = Reflection::getComponentType("environment");
|
|
static const ComponentType POINT_LIGHT_TYPE = Reflection::getComponentType("point_light");
|
|
static const ComponentType TERRAIN_TYPE = Reflection::getComponentType("terrain");
|
|
|
|
|
|
enum class IconType
|
|
{
|
|
PHYSICAL_CONTROLLER,
|
|
CAMERA,
|
|
LIGHT,
|
|
TERRAIN,
|
|
ENTITY,
|
|
|
|
COUNT
|
|
};
|
|
|
|
|
|
const char* ICONS[(int)IconType::COUNT] =
|
|
{
|
|
"phy_controller_icon",
|
|
"camera_icon",
|
|
"directional_light_icon",
|
|
"terrain_icon",
|
|
"icon"
|
|
};
|
|
|
|
|
|
static const float ORTHO_SIZE_SCALE = 1 / 20.0f;
|
|
|
|
|
|
struct EditorIconsImpl final : EditorIcons
|
|
{
|
|
struct Icon
|
|
{
|
|
EntityRef entity;
|
|
IconType type;
|
|
float scale;
|
|
};
|
|
|
|
|
|
explicit EditorIconsImpl(WorldEditor& editor, RenderScene& scene)
|
|
: m_editor(editor)
|
|
, m_icons(editor.getAllocator())
|
|
, m_scene(scene)
|
|
{
|
|
m_icons.reserve(200);
|
|
|
|
auto& universe = scene.getUniverse();
|
|
universe.entityDestroyed().bind<&EditorIconsImpl::destroyIcon>(this);
|
|
universe.componentAdded().bind<&EditorIconsImpl::refreshIcon>(this);
|
|
universe.componentDestroyed().bind<&EditorIconsImpl::refreshIcon>(this);
|
|
|
|
Engine& engine = m_editor.getEngine();
|
|
FileSystem& fs = engine.getFileSystem();
|
|
ResourceManagerHub& rm = engine.getResourceManager();
|
|
for (u32 i = 0; i < lengthOf(ICONS); ++i)
|
|
{
|
|
StaticString<MAX_PATH_LENGTH> tmp("editor/models/", ICONS[i], "_3d.fbx");
|
|
m_is_3d[i] = fs.fileExists(tmp);
|
|
if (m_is_3d[i])
|
|
{
|
|
Path path(tmp);
|
|
m_models[i] = rm.load<Model>(path);
|
|
}
|
|
else
|
|
{
|
|
tmp.data[0] = '\0';
|
|
tmp << "editor/models/" << ICONS[i] << ".fbx";
|
|
Path path(tmp);
|
|
m_models[i] = rm.load<Model>(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
~EditorIconsImpl()
|
|
{
|
|
for (auto& model : m_models) model->getResourceManager().unload(*model);
|
|
|
|
auto& universe = m_scene.getUniverse();
|
|
universe.entityDestroyed().bind<&EditorIconsImpl::destroyIcon>(this);
|
|
universe.componentAdded().bind<&EditorIconsImpl::refreshIcon>(this);
|
|
universe.componentDestroyed().bind<&EditorIconsImpl::refreshIcon>(this);
|
|
}
|
|
|
|
|
|
void destroyIcon(EntityRef entity)
|
|
{
|
|
for(int i = 0, c = m_icons.size(); i < c; ++i)
|
|
{
|
|
if(m_icons[i].entity == entity)
|
|
{
|
|
m_icons.swapAndPop(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void refreshIcon(const ComponentUID& cmp)
|
|
{
|
|
ASSERT(cmp.isValid());
|
|
destroyIcon((EntityRef)cmp.entity);
|
|
createIcon((EntityRef)cmp.entity);
|
|
}
|
|
|
|
|
|
void createIcon(EntityRef entity)
|
|
{
|
|
Universe& universe = *m_editor.getUniverse();
|
|
|
|
if (universe.getComponent(entity, MODEL_INSTANCE_TYPE).isValid()) return;
|
|
|
|
auto& icon = m_icons.emplace();
|
|
icon.entity = entity;
|
|
icon.type = IconType::ENTITY;
|
|
for (ComponentUID cmp = universe.getFirstComponent(entity); cmp.isValid(); cmp = universe.getNextComponent(cmp))
|
|
{
|
|
if(cmp.type == PHYSICAL_CONTROLLER_TYPE)
|
|
{
|
|
icon.type = IconType::PHYSICAL_CONTROLLER;
|
|
break;
|
|
}
|
|
if(cmp.type == CAMERA_TYPE)
|
|
{
|
|
icon.type = IconType::CAMERA;
|
|
break;
|
|
}
|
|
if(cmp.type == ENVIRONMENT_TYPE || cmp.type == POINT_LIGHT_TYPE)
|
|
{
|
|
icon.type = IconType::LIGHT;
|
|
break;
|
|
}
|
|
if(cmp.type == TERRAIN_TYPE)
|
|
{
|
|
icon.type = IconType::TERRAIN;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Hit raycast(const DVec3& origin, const Vec3& dir) override
|
|
{
|
|
Hit res;
|
|
res.t = -1;
|
|
res.entity = INVALID_ENTITY;
|
|
|
|
const Viewport& vp = m_editor.getView().getViewport();
|
|
|
|
for(auto& icon : m_icons) {
|
|
const Transform icon_tr = getIconTransform(icon, vp.rot, vp.is_ortho, vp.ortho_size);
|
|
|
|
const Vec3 rel_origin = icon_tr.rot.conjugated() * (origin - icon_tr.pos).toFloat();
|
|
const Vec3 rel_dir = icon_tr.rot.conjugated() * dir;
|
|
const RayCastModelHit hit = m_models[(int)icon.type]->castRay(rel_origin, rel_dir, nullptr);
|
|
if (hit.t >= 0 && (hit.t < res.t || res.t < 0)) {
|
|
res.t = hit.t;
|
|
res.entity = icon.entity;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
Transform getIconTransform(const Icon& icon, const Quat& camera_rot, bool is_ortho, float ortho_size)
|
|
{
|
|
Transform ret = m_editor.getUniverse()->getTransform(icon.entity);
|
|
if (!m_is_3d[(int)icon.type]) {
|
|
ret.rot = camera_rot;
|
|
}
|
|
if (is_ortho) {
|
|
ret.scale = ortho_size * ORTHO_SIZE_SCALE;
|
|
}
|
|
else {
|
|
ret.scale = icon.scale > 0 ? icon.scale : 1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
Matrix getIconMatrix(const Icon& icon, const Matrix& camera_matrix, const DVec3& vp_pos, bool is_ortho, float ortho_size) const
|
|
{
|
|
Matrix ret;
|
|
if (m_is_3d[(int)icon.type])
|
|
{
|
|
ret = m_editor.getUniverse()->getRelativeMatrix(icon.entity, vp_pos);
|
|
}
|
|
else
|
|
{
|
|
ret = camera_matrix;
|
|
ret.setTranslation((m_editor.getUniverse()->getPosition(icon.entity) - vp_pos).toFloat());
|
|
}
|
|
if (is_ortho)
|
|
{
|
|
ret.multiply3x3(ortho_size * ORTHO_SIZE_SCALE);
|
|
}
|
|
else
|
|
{
|
|
ret.multiply3x3(icon.scale > 0 ? icon.scale : 1);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
void getRenderData(Array<RenderData>* data) override
|
|
{
|
|
static const float MIN_SCALE_FACTOR = 10;
|
|
static const float MAX_SCALE_FACTOR = 60;
|
|
|
|
const Universe& universe = *m_editor.getUniverse();
|
|
const Viewport& vp = m_editor.getView().getViewport();
|
|
Matrix camera_mtx({0, 0, 0}, vp.rot);
|
|
|
|
for(auto& icon : m_icons) {
|
|
const DVec3 position = universe.getPosition(icon.entity);
|
|
const float distance = (position - vp.pos).toFloat().length();
|
|
float scale_factor = MIN_SCALE_FACTOR + distance;
|
|
scale_factor = clamp(scale_factor, MIN_SCALE_FACTOR, MAX_SCALE_FACTOR);
|
|
icon.scale = tanf(vp.fov * 0.5f) * distance / scale_factor;
|
|
|
|
Matrix icon_mtx = getIconMatrix(icon, camera_mtx, vp.pos, vp.is_ortho, vp.ortho_size);
|
|
data->push({icon_mtx, m_models[(int)icon.type]});
|
|
}
|
|
}
|
|
|
|
Array<Icon> m_icons;
|
|
Model* m_models[(int)IconType::COUNT];
|
|
bool m_is_3d[(int)IconType::COUNT];
|
|
WorldEditor& m_editor;
|
|
RenderScene& m_scene;
|
|
};
|
|
|
|
|
|
EditorIcons* EditorIcons::create(WorldEditor& editor, RenderScene& scene)
|
|
{
|
|
return LUMIX_NEW(editor.getAllocator(), EditorIconsImpl)(editor, scene);
|
|
}
|
|
|
|
|
|
void EditorIcons::destroy(EditorIcons& icons)
|
|
{
|
|
auto& i = static_cast<EditorIconsImpl&>(icons);
|
|
LUMIX_DELETE(i.m_editor.getAllocator(), &icons);
|
|
}
|
|
|
|
|
|
} // namespace Lumix
|