LumixEngine/src/renderer/editor/scene_view.cpp

723 lines
22 KiB
C++
Raw Normal View History

#include <imgui/imgui.h>
2015-09-20 17:30:37 +02:00
#include "scene_view.h"
#include "editor/asset_browser.h"
2018-09-09 17:58:25 +02:00
#include "editor/asset_compiler.h"
2018-07-14 16:24:17 +02:00
#include "editor/editor_icon.h"
2016-05-24 21:14:34 +02:00
#include "editor/gizmo.h"
#include "editor/log_ui.h"
2016-12-12 18:00:43 +01:00
#include "editor/prefab_system.h"
#include "editor/render_interface.h"
2016-06-08 15:35:35 +02:00
#include "editor/studio_app.h"
#include "editor/utils.h"
2016-05-10 08:24:31 +02:00
#include "engine/crc32.h"
2018-09-09 17:58:25 +02:00
#include "engine/delegate_list.h"
2016-06-08 15:35:35 +02:00
#include "engine/engine.h"
2019-06-21 17:14:06 +02:00
#include "engine/geometry.h"
2016-05-10 08:24:31 +02:00
#include "engine/path.h"
2016-06-08 15:35:35 +02:00
#include "engine/path_utils.h"
2016-02-05 14:32:21 +01:00
#include "engine/plugin_manager.h"
#include "engine/prefab.h"
#include "engine/profiler.h"
2017-11-19 14:04:10 +01:00
#include "engine/reflection.h"
#include "engine/resource_manager.h"
#include "engine/string.h"
2016-06-08 15:35:35 +02:00
#include "engine/universe/component.h"
#include "engine/universe/universe.h"
2019-10-24 21:53:19 +02:00
#include "renderer/gpu/gpu.h"
2018-10-27 21:05:52 +02:00
#include "renderer/material.h"
2016-06-08 15:35:35 +02:00
#include "renderer/model.h"
2015-09-20 17:30:37 +02:00
#include "renderer/pipeline.h"
2015-10-24 14:28:03 +02:00
#include "renderer/render_scene.h"
2016-01-12 13:52:14 +01:00
#include "renderer/renderer.h"
2018-10-27 13:13:51 +02:00
#include "renderer/shader.h"
2015-09-20 17:30:37 +02:00
2017-05-23 19:57:11 +02:00
namespace Lumix
{
2018-07-29 10:53:13 +02:00
static const ComponentType MODEL_INSTANCE_TYPE = Reflection::getComponentType("model_instance");
static const ComponentType MESH_ACTOR_TYPE = Reflection::getComponentType("mesh_rigid_actor");
2016-06-08 15:35:35 +02:00
SceneView::SceneView(StudioApp& app)
: m_app(app)
2017-09-28 13:56:10 +02:00
, m_drop_handlers(app.getWorldEditor().getAllocator())
, m_log_ui(app.getLogUI())
, m_editor(m_app.getWorldEditor())
2015-09-20 17:30:37 +02:00
{
m_camera_speed = 0.1f;
m_is_mouse_captured = false;
2016-01-28 15:19:56 +01:00
m_show_stats = false;
2016-06-12 12:04:41 +02:00
2017-09-28 13:56:10 +02:00
Engine& engine = m_editor.getEngine();
IAllocator& allocator = engine.getAllocator();
2017-05-23 19:57:11 +02:00
auto* renderer = static_cast<Renderer*>(engine.getPluginManager().getPlugin("renderer"));
2018-09-09 17:58:25 +02:00
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
m_pipeline = Pipeline::create(*renderer, pres, "SCENE_VIEW", engine.getAllocator());
2020-01-07 19:17:48 +01:00
m_pipeline->addCustomCommandHandler("renderSelection").callback.bind<&SceneView::renderSelection>(this);
m_pipeline->addCustomCommandHandler("renderGizmos").callback.bind<&SceneView::renderGizmos>(this);
m_pipeline->addCustomCommandHandler("renderIcons").callback.bind<&SceneView::renderIcons>(this);
2016-06-12 12:04:41 +02:00
2018-10-27 13:13:51 +02:00
ResourceManagerHub& rm = engine.getResourceManager();
m_debug_shape_shader = rm.load<Shader>(Path("pipelines/debug_shape.shd"));
2020-01-07 19:17:48 +01:00
m_editor.universeCreated().bind<&SceneView::onUniverseCreated>(this);
m_editor.universeDestroyed().bind<&SceneView::onUniverseDestroyed>(this);
2016-06-12 12:04:41 +02:00
m_toggle_gizmo_step_action =
LUMIX_NEW(allocator, Action)("Enable/disable gizmo step", "Enable/disable gizmo step", "toggleGizmoStep");
2016-06-12 12:04:41 +02:00
m_toggle_gizmo_step_action->is_global = false;
m_app.addAction(m_toggle_gizmo_step_action);
m_move_forward_action = LUMIX_NEW(allocator, Action)("Move forward", "Move camera forward", "moveForward");
2016-06-12 12:04:41 +02:00
m_move_forward_action->is_global = false;
m_app.addAction(m_move_forward_action);
m_move_back_action = LUMIX_NEW(allocator, Action)("Move back", "Move camera back", "moveBack");
2016-06-12 12:04:41 +02:00
m_move_back_action->is_global = false;
m_app.addAction(m_move_back_action);
m_move_left_action = LUMIX_NEW(allocator, Action)("Move left", "Move camera left", "moveLeft");
2016-06-12 12:04:41 +02:00
m_move_left_action->is_global = false;
m_app.addAction(m_move_left_action);
m_move_right_action = LUMIX_NEW(allocator, Action)("Move right", "Move camera right", "moveRight");
2016-06-12 12:04:41 +02:00
m_move_right_action->is_global = false;
m_app.addAction(m_move_right_action);
m_move_up_action = LUMIX_NEW(allocator, Action)("Move up", "Move camera up", "moveUp");
2016-06-12 12:04:41 +02:00
m_move_up_action->is_global = false;
m_app.addAction(m_move_up_action);
m_move_down_action = LUMIX_NEW(allocator, Action)("Move down", "Move camera down", "moveDown");
2016-06-12 12:04:41 +02:00
m_move_down_action->is_global = false;
m_app.addAction(m_move_down_action);
m_camera_speed_action = LUMIX_NEW(allocator, Action)("Camera speed", "Reset camera speed", "cameraSpeed");
m_camera_speed_action->is_global = false;
2020-01-07 19:17:48 +01:00
m_camera_speed_action->func.bind<&SceneView::resetCameraSpeed>(this);
m_app.addAction(m_camera_speed_action);
2018-07-01 18:13:44 +02:00
const ResourceType pipeline_type("pipeline");
2018-10-14 17:46:42 +02:00
m_app.getAssetCompiler().registerExtension("pln", pipeline_type);
}
void SceneView::resetCameraSpeed()
{
m_camera_speed = 0.1f;
2015-09-20 17:30:37 +02:00
}
SceneView::~SceneView()
{
2020-01-07 19:17:48 +01:00
m_editor.universeCreated().unbind<&SceneView::onUniverseCreated>(this);
m_editor.universeDestroyed().unbind<&SceneView::onUniverseDestroyed>(this);
2017-07-16 17:58:38 +02:00
Pipeline::destroy(m_pipeline);
2018-10-27 13:13:51 +02:00
m_debug_shape_shader->getResourceManager().unload(*m_debug_shape_shader);
2017-07-16 17:58:38 +02:00
m_pipeline = nullptr;
2015-09-20 17:30:37 +02:00
}
2017-05-23 19:57:11 +02:00
void SceneView::setScene(RenderScene* scene)
2015-09-20 17:30:37 +02:00
{
2016-02-26 17:09:19 +01:00
m_pipeline->setScene(scene);
2015-09-20 17:30:37 +02:00
}
2015-10-24 14:28:03 +02:00
void SceneView::onUniverseCreated()
{
2017-09-28 13:56:10 +02:00
IScene* scene = m_editor.getUniverse()->getScene(crc32("renderer"));
m_pipeline->setScene((RenderScene*)scene);
2015-10-24 14:28:03 +02:00
}
void SceneView::onUniverseDestroyed()
{
2016-02-26 17:09:19 +01:00
m_pipeline->setScene(nullptr);
2015-10-24 14:28:03 +02:00
}
2019-10-18 18:31:12 +02:00
void SceneView::update(float time_delta)
2015-09-20 17:30:37 +02:00
{
PROFILE_FUNCTION();
2015-10-16 21:19:27 +02:00
if (ImGui::IsAnyItemActive()) return;
2020-01-20 18:29:02 +01:00
if (!m_is_mouse_captured) return;
2015-10-24 14:34:57 +02:00
if (ImGui::GetIO().KeyCtrl) return;
2015-09-20 17:30:37 +02:00
int screen_x = int(ImGui::GetIO().MousePos.x);
int screen_y = int(ImGui::GetIO().MousePos.y);
bool is_inside = screen_x >= m_screen_x && screen_y >= m_screen_y && screen_x <= m_screen_x + m_width &&
screen_y <= m_screen_y + m_height;
2015-09-20 17:30:37 +02:00
if (!is_inside) return;
2019-06-13 17:26:52 +02:00
m_camera_speed = maximum(0.01f, m_camera_speed + ImGui::GetIO().MouseWheel / 20.0f);
2016-05-24 21:14:34 +02:00
2019-10-18 18:31:12 +02:00
float speed = m_camera_speed * time_delta * 60.f;
if (ImGui::GetIO().KeyShift) speed *= 10;
2017-11-12 15:05:35 +01:00
m_editor.getGizmo().enableStep(m_toggle_gizmo_step_action->isActive());
2017-09-28 13:56:10 +02:00
if (m_move_forward_action->isActive()) m_editor.navigate(1.0f, 0, 0, speed);
if (m_move_back_action->isActive()) m_editor.navigate(-1.0f, 0, 0, speed);
if (m_move_left_action->isActive()) m_editor.navigate(0.0f, -1.0f, 0, speed);
if (m_move_right_action->isActive()) m_editor.navigate(0.0f, 1.0f, 0, speed);
if (m_move_down_action->isActive()) m_editor.navigate(0, 0, -1.0f, speed);
if (m_move_up_action->isActive()) m_editor.navigate(0, 0, 1.0f, speed);
2015-09-20 17:30:37 +02:00
}
void SceneView::renderIcons()
2015-09-20 17:30:37 +02:00
{
struct RenderJob : Renderer::RenderJob
2018-07-14 16:24:17 +02:00
{
RenderJob(IAllocator& allocator)
: m_allocator(allocator)
, m_items(allocator)
2018-07-14 16:24:17 +02:00
{}
void setup() override
{
2019-06-07 01:26:09 +02:00
PROFILE_FUNCTION();
Array<EditorIcons::RenderData> data(m_allocator);
m_view->m_editor.getIcons().getRenderData(&data);
RenderInterfaceBase* ri = (RenderInterfaceBase*)m_view->m_editor.getRenderInterface();
for (EditorIcons::RenderData& rd : data) {
const Model* model = (Model*)ri->getModel(rd.model);
if (!model || !model->isReady()) continue;
for (int i = 0; i <= model->getLODs()[0].to_mesh; ++i) {
const Mesh& mesh = model->getMesh(i);
Item& item = m_items.emplace();
item.mesh = mesh.render_data;
item.mtx = rd.mtx;
item.material = mesh.material->getRenderData();
item.program = mesh.material->getShader()->getProgram(mesh.vertex_decl, item.material->define_mask);
}
}
2018-07-14 16:24:17 +02:00
}
void execute() override
{
2019-06-07 01:26:09 +02:00
PROFILE_FUNCTION();
2019-10-24 21:53:19 +02:00
const gpu::BufferHandle drawcall_ub = m_view->m_pipeline->getDrawcallUniformBuffer();
for (const Item& item : m_items) {
const Mesh::RenderData* rd = item.mesh;
2018-08-09 22:35:00 +02:00
2019-10-24 21:53:19 +02:00
gpu::update(drawcall_ub, &item.mtx.m11, sizeof(item.mtx));
gpu::bindTextures(item.material->textures, 0, item.material->textures_count);
gpu::useProgram(item.program);
gpu::bindIndexBuffer(rd->index_buffer_handle);
gpu::bindVertexBuffer(0, rd->vertex_buffer_handle, 0, rd->vb_stride);
gpu::bindVertexBuffer(1, gpu::INVALID_BUFFER, 0, 0);
gpu::setState(item.material->render_states);
gpu::drawTriangles(rd->indices_count, rd->index_type);
2018-07-14 16:24:17 +02:00
}
}
struct Item {
2019-10-24 21:53:19 +02:00
gpu::ProgramHandle program;
Mesh::RenderData* mesh;
Material::RenderData* material;
Matrix mtx;
};
IAllocator& m_allocator;
Array<Item> m_items;
SceneView* m_view;
2018-07-14 16:24:17 +02:00
};
Engine& engine = m_editor.getEngine();
Renderer* renderer = static_cast<Renderer*>(engine.getPluginManager().getPlugin("renderer"));
IAllocator& allocator = renderer->getAllocator();
RenderJob* cmd = LUMIX_NEW(allocator, RenderJob)(allocator);
cmd->m_view = this;
2019-07-04 13:31:48 +02:00
renderer->queue(cmd, 0);
}
2017-11-08 17:49:23 +01:00
void SceneView::renderSelection()
{
2018-10-20 20:04:08 +02:00
struct RenderJob : Renderer::RenderJob
2017-11-08 17:49:23 +01:00
{
2018-10-20 20:04:08 +02:00
RenderJob(IAllocator& allocator) : m_items(allocator) {}
2018-01-12 17:01:26 +01:00
2018-10-20 20:04:08 +02:00
void setup() override
{
2019-06-07 01:26:09 +02:00
PROFILE_FUNCTION();
2018-10-20 20:04:08 +02:00
const Array<EntityRef>& entities = m_editor->getSelectedEntities();
RenderScene* scene = m_pipeline->getScene();
const Universe& universe = scene->getUniverse();
for (EntityRef e : entities) {
if (!scene->getUniverse().hasComponent(e, MODEL_INSTANCE_TYPE)) continue;
2018-10-27 21:05:52 +02:00
const Model* model = scene->getModelInstanceModel(e);
if (!model || !model->isReady()) continue;
2019-10-05 14:26:26 +02:00
for (int i = 0; i <= model->getLODs()[0].to_mesh; ++i) {
2018-10-27 21:05:52 +02:00
const Mesh& mesh = model->getMesh(i);
2019-07-02 23:17:45 +02:00
Item& item = m_items.emplace();
2018-10-27 21:05:52 +02:00
item.mesh = mesh.render_data;
item.mtx = universe.getRelativeMatrix(e, m_editor->getViewport().pos);
2019-09-23 23:33:43 +02:00
item.material = mesh.material->getRenderData();
item.program = mesh.material->getShader()->getProgram(mesh.vertex_decl, m_define_mask | item.material->define_mask);
2018-10-27 21:05:52 +02:00
}
2018-10-20 20:04:08 +02:00
}
}
void execute() override
{
2019-06-07 01:26:09 +02:00
PROFILE_FUNCTION();
2019-10-24 21:53:19 +02:00
const gpu::BufferHandle drawcall_ub = m_pipeline->getDrawcallUniformBuffer();
2019-08-11 20:32:21 +02:00
2018-10-20 20:04:08 +02:00
for (const Item& item : m_items) {
2018-10-27 21:05:52 +02:00
const Mesh::RenderData* rd = item.mesh;
2019-10-24 21:53:19 +02:00
gpu::update(drawcall_ub, &item.mtx.m11, sizeof(item.mtx));
gpu::bindTextures(item.material->textures, 0, item.material->textures_count);
gpu::useProgram(item.program);
gpu::bindIndexBuffer(rd->index_buffer_handle);
gpu::bindVertexBuffer(0, rd->vertex_buffer_handle, 0, rd->vb_stride);
gpu::bindVertexBuffer(1, gpu::INVALID_BUFFER, 0, 0);
gpu::setState(item.material->render_states);
gpu::drawTriangles(rd->indices_count, rd->index_type);
2018-10-20 20:04:08 +02:00
}
}
2018-10-20 20:04:08 +02:00
struct Item {
2019-10-24 21:53:19 +02:00
gpu::ProgramHandle program;
2018-10-27 21:05:52 +02:00
Mesh::RenderData* mesh;
2019-09-23 23:33:43 +02:00
Material::RenderData* material;
2018-10-20 20:04:08 +02:00
Matrix mtx;
};
Array<Item> m_items;
Pipeline* m_pipeline;
WorldEditor* m_editor;
2019-08-11 20:32:21 +02:00
u32 m_define_mask;
2018-10-20 20:04:08 +02:00
};
Engine& engine = m_editor.getEngine();
Renderer* renderer = static_cast<Renderer*>(engine.getPluginManager().getPlugin("renderer"));
IAllocator& allocator = renderer->getAllocator();
RenderJob* job = LUMIX_NEW(allocator, RenderJob)(allocator);
2019-08-11 20:32:21 +02:00
job->m_define_mask = 1 << renderer->getShaderDefineIdx("DEPTH");
2018-10-20 20:04:08 +02:00
job->m_pipeline = m_pipeline;
job->m_editor = &m_editor;
2019-07-04 13:31:48 +02:00
renderer->queue(job, 0);
2017-11-08 17:49:23 +01:00
}
void SceneView::renderGizmos()
{
2018-10-12 00:12:44 +02:00
struct Cmd : Renderer::RenderJob
2018-07-14 16:24:17 +02:00
{
Cmd(IAllocator& allocator)
: data(allocator)
{}
void setup() override
{
2019-06-07 01:26:09 +02:00
PROFILE_FUNCTION();
2018-07-14 16:24:17 +02:00
viewport = view->m_editor.getViewport();
2018-10-27 13:13:51 +02:00
view->m_editor.getGizmo().getRenderData(&data, viewport);
Engine& engine = view->m_editor.getEngine();
renderer = static_cast<Renderer*>(engine.getPluginManager().getPlugin("renderer"));
2019-07-04 13:56:05 +02:00
ib = renderer->allocTransient(data.indices.byte_size());
vb = renderer->allocTransient(data.vertices.byte_size());
2020-01-06 17:25:22 +01:00
memcpy(ib.ptr, data.indices.begin(), data.indices.byte_size());
memcpy(vb.ptr, data.vertices.begin(), data.vertices.byte_size());
2018-07-14 16:24:17 +02:00
}
void execute() override
{
2019-07-04 13:56:05 +02:00
PROFILE_FUNCTION();
2020-01-06 17:25:22 +01:00
if (data.cmds.empty()) return;
2018-10-27 13:13:51 +02:00
renderer->beginProfileBlock("gizmos", 0);
2019-10-24 21:53:19 +02:00
gpu::pushDebugGroup("gizmos");
gpu::setState(u64(gpu::StateFlags::DEPTH_TEST) | u64(gpu::StateFlags::DEPTH_WRITE));
2019-07-04 13:56:05 +02:00
u32 vb_offset = 0;
u32 ib_offset = 0;
2019-10-24 21:53:19 +02:00
const gpu::BufferHandle drawcall_ub = view->getPipeline()->getDrawcallUniformBuffer();
for (Gizmo::RenderData::Cmd& cmd : data.cmds) {
2019-10-24 21:53:19 +02:00
gpu::update(drawcall_ub, &cmd.mtx.m11, sizeof(cmd.mtx));
gpu::useProgram(program);
gpu::bindIndexBuffer(ib.buffer);
gpu::bindVertexBuffer(0, vb.buffer, vb.offset + vb_offset, 16);
gpu::bindVertexBuffer(1, gpu::INVALID_BUFFER, 0, 0);
const gpu::PrimitiveType primitive_type = cmd.lines ? gpu::PrimitiveType::LINES : gpu::PrimitiveType::TRIANGLES;
gpu::drawElements(ib.offset + ib_offset, cmd.indices_count, primitive_type, gpu::DataType::U16);
2019-07-04 13:56:05 +02:00
vb_offset += cmd.vertices_count * sizeof(Gizmo::RenderData::Vertex);
ib_offset += cmd.indices_count * sizeof(u16);
2018-10-27 13:13:51 +02:00
}
2019-10-24 21:53:19 +02:00
gpu::popDebugGroup();
2019-07-07 11:13:33 +02:00
2019-07-04 13:56:05 +02:00
renderer->endProfileBlock();
2018-07-14 16:24:17 +02:00
}
2018-10-27 13:13:51 +02:00
Renderer* renderer;
2019-07-04 13:56:05 +02:00
Renderer::TransientSlice ib;
Renderer::TransientSlice vb;
2018-10-27 13:13:51 +02:00
Gizmo::RenderData data;
2018-07-14 16:24:17 +02:00
Viewport viewport;
SceneView* view;
2019-10-24 21:53:19 +02:00
gpu::ProgramHandle program;
2018-07-14 16:24:17 +02:00
};
2018-10-27 13:13:51 +02:00
if (!m_debug_shape_shader || !m_debug_shape_shader->isReady()) return;
2018-07-14 16:24:17 +02:00
Engine& engine = m_editor.getEngine();
Renderer* renderer = static_cast<Renderer*>(engine.getPluginManager().getPlugin("renderer"));
IAllocator& allocator = renderer->getAllocator();
Cmd* cmd = LUMIX_NEW(allocator, Cmd)(allocator);
2019-10-24 21:53:19 +02:00
gpu::VertexDecl decl;
decl.addAttribute(0, 0, 3, gpu::AttributeType::FLOAT, 0);
decl.addAttribute(1, 12, 4, gpu::AttributeType::U8, gpu::Attribute::NORMALIZED);
cmd->program = m_debug_shape_shader->getProgram(decl, 0);
2018-07-14 16:24:17 +02:00
cmd->view = this;
2019-07-04 13:31:48 +02:00
renderer->queue(cmd, 0);
2015-09-20 17:30:37 +02:00
}
void SceneView::captureMouse(bool capture)
{
if(m_is_mouse_captured == capture) return;
m_is_mouse_captured = capture;
2018-12-09 11:36:31 +01:00
OS::showCursor(!m_is_mouse_captured);
2018-12-08 15:11:14 +01:00
if (capture) {
2018-12-09 11:36:31 +01:00
const OS::Point p = OS::getMouseScreenPos();
2018-12-08 15:11:14 +01:00
m_captured_mouse_x = p.x;
m_captured_mouse_y = p.y;
}
else {
2018-12-09 11:36:31 +01:00
OS::setMouseScreenPos(m_captured_mouse_x, m_captured_mouse_y);
OS::unclipCursor();
2018-12-08 15:11:14 +01:00
}
}
2017-05-23 19:57:11 +02:00
RayCastModelHit SceneView::castRay(float x, float y)
2016-06-08 15:35:35 +02:00
{
auto* scene = m_pipeline->getScene();
ASSERT(scene);
2018-07-07 15:20:25 +02:00
const Viewport& vp = m_editor.getViewport();
2018-09-16 18:35:57 +02:00
DVec3 origin;
2017-05-23 19:57:11 +02:00
Vec3 dir;
2018-07-07 15:20:25 +02:00
vp.getRay({x * vp.w, y * vp.h}, origin, dir);
2018-01-12 17:01:26 +01:00
return scene->castRay(origin, dir, INVALID_ENTITY);
2016-06-08 15:35:35 +02:00
}
void SceneView::addDropHandler(DropHandler handler)
{
m_drop_handlers.push(handler);
}
void SceneView::removeDropHandler(DropHandler handler)
{
2019-08-22 19:25:15 +02:00
m_drop_handlers.swapAndPopItem(handler);
}
2017-11-08 10:50:45 +01:00
void SceneView::handleDrop(const char* path, float x, float y)
2016-06-08 15:35:35 +02:00
{
auto hit = castRay(x, y);
for (DropHandler handler : m_drop_handlers)
{
if (handler.invoke(m_app, x, y, hit)) return;
}
2019-06-15 22:42:15 +02:00
if (PathUtils::hasExtension(path, "fbx"))
2016-06-08 15:35:35 +02:00
{
2018-09-20 23:17:45 +02:00
const DVec3 pos = hit.origin + (hit.is_hit ? hit.t : 1) * hit.dir;
m_editor.beginCommandGroup(crc32("insert_mesh"));
2018-08-19 17:35:37 +02:00
EntityRef entity = m_editor.addEntity();
m_editor.setEntitiesPositions(&entity, &pos, 1);
2020-01-06 17:25:22 +01:00
m_editor.addComponent(Span(&entity, 1), MODEL_INSTANCE_TYPE);
auto* prop = Reflection::getProperty(MODEL_INSTANCE_TYPE, "Source");
m_editor.setProperty(MODEL_INSTANCE_TYPE, -1, *prop, &entity, 1, path, stringLength(path) + 1);
m_editor.endCommandGroup();
}
2017-11-25 02:52:46 +01:00
else if (PathUtils::hasExtension(path, "fab"))
{
ResourceManagerHub& manager = m_editor.getEngine().getResourceManager();
2019-06-27 14:05:05 +02:00
PrefabResource* prefab = manager.load<PrefabResource>(Path(path));
const DVec3 pos = hit.origin + (hit.is_hit ? hit.t : 1) * hit.dir;
m_editor.getPrefabSystem().instantiatePrefab(*prefab, pos, Quat::IDENTITY, 1);
2017-11-25 02:52:46 +01:00
}
else if (PathUtils::hasExtension(path, "phy"))
{
2018-09-20 23:17:45 +02:00
if (hit.is_hit && hit.entity.isValid())
{
m_editor.beginCommandGroup(crc32("insert_phy_component"));
2018-09-20 23:17:45 +02:00
const EntityRef e = (EntityRef)hit.entity;
2018-08-19 17:35:37 +02:00
m_editor.selectEntities(&e, 1, false);
2020-01-06 17:25:22 +01:00
m_editor.addComponent(Span(&e, 1), MESH_ACTOR_TYPE);
auto* prop = Reflection::getProperty(MESH_ACTOR_TYPE, "Source");
2018-08-19 17:35:37 +02:00
m_editor.setProperty(MESH_ACTOR_TYPE, -1, *prop, &e, 1, path, stringLength(path) + 1);
m_editor.endCommandGroup();
}
else
{
2018-09-20 23:17:45 +02:00
const DVec3 pos = hit.origin + (hit.is_hit ? hit.t : 1) * hit.dir;
m_editor.beginCommandGroup(crc32("insert_phy"));
2018-08-19 17:35:37 +02:00
EntityRef entity = m_editor.addEntity();
m_editor.setEntitiesPositions(&entity, &pos, 1);
m_editor.selectEntities(&entity, 1, false);
2020-01-06 17:25:22 +01:00
m_editor.addComponent(Span(&entity, 1), MESH_ACTOR_TYPE);
auto* prop = Reflection::getProperty(MESH_ACTOR_TYPE, "Source");
m_editor.setProperty(MESH_ACTOR_TYPE, -1, *prop, &entity, 1, path, stringLength(path) + 1);
m_editor.endCommandGroup();
}
}
2018-09-20 23:17:45 +02:00
else if (hit.is_hit && PathUtils::hasExtension(path, "mat") && hit.mesh)
{
2018-09-20 23:17:45 +02:00
const EntityRef e = (EntityRef)hit.entity;
2018-08-19 17:35:37 +02:00
m_editor.selectEntities(&e, 1, false);
2018-01-12 17:01:26 +01:00
RenderScene* scene = m_pipeline->getScene();
2018-08-19 17:35:37 +02:00
Model* model = scene->getModelInstanceModel(e);
int mesh_index = 0;
for (int i = 0; i < model->getMeshCount(); ++i)
2016-06-08 15:35:35 +02:00
{
2018-09-20 23:17:45 +02:00
if (&model->getMesh(i) == hit.mesh)
2016-06-08 15:35:35 +02:00
{
mesh_index = i;
break;
2016-06-08 15:35:35 +02:00
}
}
auto* prop= Reflection::getProperty(MODEL_INSTANCE_TYPE, "Materials", "Source");
2018-08-19 17:35:37 +02:00
m_editor.setProperty(MODEL_INSTANCE_TYPE, mesh_index, *prop, &e, 1, path, stringLength(path) + 1);
2016-06-08 15:35:35 +02:00
}
}
2016-06-09 20:44:02 +02:00
void SceneView::onToolbar()
{
static const char* actions_names[] = { "setTranslateGizmoMode",
"setRotateGizmoMode",
"setLocalCoordSystem",
"setGlobalCoordSystem",
"setPivotCenter",
2016-06-15 22:19:45 +02:00
"setPivotOrigin",
"viewTop",
"viewFront",
"viewSide" };
2016-06-09 20:44:02 +02:00
auto pos = ImGui::GetCursorScreenPos();
2016-06-16 22:32:30 +02:00
if (ImGui::BeginToolbar("scene_view_toolbar", pos, ImVec2(0, 24)))
2016-06-09 20:44:02 +02:00
{
2016-06-12 17:44:22 +02:00
for (auto* action_name : actions_names)
{
auto* action = m_app.getAction(action_name);
action->toolbarButton();
2016-06-12 17:44:22 +02:00
}
}
m_app.getAction("cameraSpeed")->toolbarButton();
2016-06-12 17:44:22 +02:00
ImGui::PushItemWidth(50);
ImGui::SameLine();
float offset = (24 - ImGui::GetTextLineHeightWithSpacing()) / 2;
2016-06-12 17:44:22 +02:00
pos = ImGui::GetCursorPos();
pos.y += offset;
2016-06-12 17:44:22 +02:00
ImGui::SetCursorPos(pos);
ImGui::DragFloat("##camera_speed", &m_camera_speed, 0.1f, 0.01f, 999.0f, "%.2f");
2016-06-12 17:44:22 +02:00
2017-09-28 13:56:10 +02:00
int step = m_editor.getGizmo().getStep();
Action* mode_action;
2017-09-28 13:56:10 +02:00
if (m_editor.getGizmo().isTranslateMode())
2016-06-12 17:44:22 +02:00
{
mode_action = m_app.getAction("setTranslateGizmoMode");
}
else
{
mode_action = m_app.getAction("setRotateGizmoMode");
2016-06-12 17:44:22 +02:00
}
ImGui::SameLine();
pos = ImGui::GetCursorPos();
pos.y -= offset;
ImGui::SetCursorPos(pos);
ImVec4 tint_color = ImGui::GetStyle().Colors[ImGuiCol_Text];
2019-10-24 21:53:19 +02:00
const gpu::TextureHandle t = *(gpu::TextureHandle*)mode_action->icon;
ImGui::Image((void*)(uintptr)t.value, ImVec2(24, 24), ImVec2(0, 0), ImVec2(1, 1), tint_color);
if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", "Snap amount");
2016-06-12 17:44:22 +02:00
ImGui::SameLine();
pos = ImGui::GetCursorPos();
pos.y += offset;
ImGui::SetCursorPos(pos);
if (ImGui::DragInt("##gizmoStep", &step, 1.0f, 0, 200))
{
2017-09-28 13:56:10 +02:00
m_editor.getGizmo().setStep(step);
}
ImGui::SameLine(0, 20);
2016-06-12 17:44:22 +02:00
ImGui::Checkbox("Stats", &m_show_stats);
ImGui::SameLine(0, 20);
2016-06-12 17:44:22 +02:00
m_pipeline->callLuaFunction("onGUI");
2017-09-28 13:56:10 +02:00
if (m_editor.isMeasureToolActive())
2016-06-12 17:44:22 +02:00
{
ImGui::SameLine(0, 20);
2017-09-28 13:56:10 +02:00
ImGui::Text(" | Measured distance: %f", m_editor.getMeasuredDistance());
2016-06-09 20:44:02 +02:00
}
2016-06-12 17:44:22 +02:00
ImGui::PopItemWidth();
2016-06-09 20:44:02 +02:00
ImGui::EndToolbar();
}
2020-01-06 17:25:22 +01:00
void SceneView::handleEvents() {
const bool handle_input = ImGui::IsItemHovered() && OS::getFocused() == ImGui::GetWindowViewport()->PlatformHandle;
const OS::Event* events = m_app.getEvents();
for (int i = 0, c = m_app.getEventsCount(); i < c; ++i) {
const OS::Event& event = events[i];
switch (event.type) {
case OS::Event::Type::MOUSE_BUTTON: {
2020-01-20 18:29:02 +01:00
const OS::Point cp = OS::getMousePos(event.window);
Vec2 rel_mp = { (float)cp.x, (float)cp.y };
rel_mp.x -= m_screen_x;
rel_mp.y -= m_screen_y;
2020-01-06 17:25:22 +01:00
if (handle_input) {
2020-01-20 18:29:02 +01:00
if (event.mouse_button.button == OS::MouseButton::RIGHT) {
ImGui::SetWindowFocus();
captureMouse(event.mouse_button.down);
}
2020-01-06 17:25:22 +01:00
ImGui::ResetActiveID();
if (event.mouse_button.down) {
m_editor.onMouseDown((int)rel_mp.x, (int)rel_mp.y, event.mouse_button.button);
}
else {
m_editor.onMouseUp((int)rel_mp.x, (int)rel_mp.y, event.mouse_button.button);
}
}
2020-01-20 18:29:02 +01:00
else if (!event.mouse_button.down) {
m_editor.onMouseUp((int)rel_mp.x, (int)rel_mp.y, event.mouse_button.button);
}
2020-01-06 17:25:22 +01:00
break;
}
case OS::Event::Type::MOUSE_MOVE:
if (handle_input) {
const OS::Point cp = OS::getMousePos(event.window);
Vec2 rel_mp = {(float)cp.x, (float)cp.y};
rel_mp.x -= m_screen_x;
rel_mp.y -= m_screen_y;
m_editor.onMouseMove((int)rel_mp.x, (int)rel_mp.y, (int)event.mouse_move.xrel, (int)event.mouse_move.yrel);
}
break;
}
}
}
void SceneView::statsUI(float x, float y) {
2020-01-20 18:29:02 +01:00
if (!m_show_stats) return;
2020-01-06 17:25:22 +01:00
float toolbar_height = 24 + ImGui::GetStyle().FramePadding.y * 2;
ImVec2 view_pos(x, y);
view_pos.x += ImGui::GetStyle().FramePadding.x;
view_pos.y += ImGui::GetStyle().FramePadding.y + toolbar_height;
ImGui::SetNextWindowPos(view_pos);
auto col = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
col.w = 0.3f;
ImGui::PushStyleColor(ImGuiCol_WindowBg, col);
if (ImGui::Begin("###stats_overlay",
nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings))
{
const auto& stats = m_pipeline->getStats();
ImGui::LabelText("Draw calls (scene view only)", "%d", stats.draw_call_count);
ImGui::LabelText("Instances (scene view only)", "%d", stats.instance_count);
char buf[30];
toCStringPretty(stats.triangle_count, Span(buf));
ImGui::LabelText("Triangles (scene view only)", "%s", buf);
ImGui::LabelText("Resolution", "%dx%d", m_width, m_height);
}
ImGui::End();
ImGui::PopStyleColor();
}
2016-06-09 20:44:02 +02:00
void SceneView::onWindowGUI()
2015-09-20 17:30:37 +02:00
{
2015-09-27 12:56:01 +02:00
PROFILE_FUNCTION();
2020-01-20 18:29:02 +01:00
bool is_open = false;
2016-01-28 15:19:56 +01:00
ImVec2 view_pos;
2016-02-12 23:49:56 +01:00
const char* title = "Scene View###Scene View";
2020-01-06 17:25:22 +01:00
if (m_log_ui.getUnreadErrorCount() > 0) title = "Scene View | errors in log###Scene View";
2016-02-12 23:49:56 +01:00
2020-01-06 17:25:22 +01:00
if (ImGui::Begin(title, nullptr, ImGuiWindowFlags_NoScrollWithMouse)) {
2020-01-20 18:29:02 +01:00
is_open = true;
2016-06-09 20:44:02 +02:00
onToolbar();
2020-01-06 17:25:22 +01:00
const ImVec2 size = ImGui::GetContentRegionAvail();
2018-08-19 22:01:20 +02:00
Viewport vp = m_editor.getViewport();
vp.w = (int)size.x;
vp.h = (int)size.y;
m_editor.setViewport(vp);
m_pipeline->setViewport(vp);
2019-06-23 20:16:01 +02:00
m_pipeline->render(false);
2018-09-08 14:41:18 +02:00
m_editor.inputFrame();
2020-01-06 17:25:22 +01:00
const gpu::TextureHandle texture_handle = m_pipeline->getOutput();
if (size.x > 0 && size.y > 0) {
const ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
m_screen_x = int(cursor_pos.x);
m_screen_y = int(cursor_pos.y);
m_width = int(size.x);
m_height = int(size.y);
2020-01-06 17:25:22 +01:00
view_pos = ImGui::GetCursorScreenPos();
if (texture_handle.isValid()) {
void* t = (void*)(uintptr)texture_handle.value;
2019-10-24 21:53:19 +02:00
if (gpu::isOriginBottomLeft()) {
2018-08-19 22:01:20 +02:00
ImGui::Image(t, size, ImVec2(0, 1), ImVec2(1, 0));
}
else {
ImGui::Image(t, size);
2018-06-30 15:18:27 +02:00
}
}
if (m_is_mouse_captured) {
2020-01-06 17:25:22 +01:00
const ImVec2 pos = ImGui::GetItemRectMin();
const ImVec2 size = ImGui::GetItemRectSize();
2020-01-20 18:29:02 +01:00
OS::clipCursor((int)pos.x, (int)pos.y, (int)size.x, (int)size.y);
}
2020-01-06 17:25:22 +01:00
if (ImGui::BeginDragDropTarget()) {
if (auto* payload = ImGui::AcceptDragDropPayload("path")) {
const ImVec2 drop_pos = ImGui::GetMousePos() - view_pos / size;
handleDrop((const char*)payload->Data, drop_pos.x, drop_pos.y);
2016-06-08 15:35:35 +02:00
}
2017-11-08 10:50:45 +01:00
ImGui::EndDragDropTarget();
2016-06-08 15:35:35 +02:00
}
2020-01-06 17:25:22 +01:00
handleEvents();
}
2015-11-10 22:25:36 +01:00
}
2018-09-08 14:41:18 +02:00
else {
m_editor.inputFrame();
}
2015-11-10 22:25:36 +01:00
2020-01-20 18:29:02 +01:00
if (m_is_mouse_captured && OS::getFocused() != ImGui::GetWindowViewport()->PlatformHandle) {
captureMouse(false);
}
2018-10-06 12:44:38 +02:00
ImGui::End();
2020-01-20 18:29:02 +01:00
if (is_open) statsUI(view_pos.x, view_pos.y);
2016-04-28 10:14:47 +02:00
}
2017-05-23 19:57:11 +02:00
} // namespace Lumix