From 5b35a5a47de57ef9918c359a0f083c4141f3b2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Tue, 12 Jul 2022 13:24:35 +0200 Subject: [PATCH] Transform tool updates (#486) * translator tool upgrades, renderpath2D hdr improvement * fix * rewritten rotation tool * visual update * screen aligned rotation mode * rotation snap mode fix * non uniform scaling fix * improvements to transform undo/redo * added snap mode configuration * mirroring transform tool based on camera relative position; axis text display; * origin drag visualizer * minor refactor --- Editor/Editor.cpp | 936 +++++++++++----------- Editor/Editor.h | 3 + Editor/TransformWindow.cpp | 37 + Editor/TransformWindow.h | 5 + Editor/Translator.cpp | 1325 +++++++++++++++++++++++-------- Editor/Translator.h | 19 +- WickedEngine/wiGUI.cpp | 5 +- WickedEngine/wiMath.cpp | 14 + WickedEngine/wiMath.h | 1 + WickedEngine/wiRenderPath2D.cpp | 38 +- WickedEngine/wiRenderPath2D.h | 7 +- WickedEngine/wiVersion.cpp | 2 +- 12 files changed, 1550 insertions(+), 842 deletions(-) diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index 0a8115a92..858d05446 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -181,6 +181,36 @@ void EditorComponent::ResizeBuffers() } } + { + TextureDesc desc; + desc.width = renderPath->GetRenderResult().GetDesc().width; + desc.height = renderPath->GetRenderResult().GetDesc().height; + desc.format = Format::D32_FLOAT; + desc.bind_flags = BindFlag::DEPTH_STENCIL; + desc.layout = ResourceState::DEPTHSTENCIL; + desc.misc_flags = ResourceMiscFlag::TRANSIENT_ATTACHMENT; + device->CreateTexture(&desc, nullptr, &editor_depthbuffer); + device->SetName(&editor_depthbuffer, "editor_depthbuffer"); + + { + RenderPassDesc desc; + desc.attachments.push_back( + RenderPassAttachment::DepthStencil( + &editor_depthbuffer, + RenderPassAttachment::LoadOp::CLEAR, + RenderPassAttachment::StoreOp::DONTCARE + ) + ); + desc.attachments.push_back( + RenderPassAttachment::RenderTarget( + &renderPath->GetRenderResult(), + RenderPassAttachment::LoadOp::CLEAR, + RenderPassAttachment::StoreOp::STORE + ) + ); + device->CreateRenderPass(&desc, &renderpass_editor); + } + } } void EditorComponent::ResizeLayout() { @@ -345,9 +375,6 @@ void EditorComponent::Load() wi::jobsystem::Execute(ctx, [this](wi::jobsystem::JobArgs args) { soundTex = wi::resourcemanager::Load("images/sound.dds"); }); // wait for ctx is at the end of this function! - translator.Create(); - translator.enabled = false; - rendererWnd_Toggle.Create("Renderer"); @@ -681,7 +708,7 @@ void EditorComponent::Load() translatorCheckBox.Create("Transform: "); - translatorCheckBox.SetTooltip("Enable the transform tool"); + translatorCheckBox.SetTooltip("Enable the transform tool.\nTip: hold Left Ctrl to enable snap transform.\nYou can configure snap mode units in the Transform settings."); translatorCheckBox.OnClick([&](wi::gui::EventArgs args) { translator.enabled = args.bValue; }); @@ -930,7 +957,8 @@ void EditorComponent::Load() ss += "Look: Middle mouse button / arrow keys / controller right stick\n"; ss += "Select: Right mouse button\n"; ss += "Interact with water: Left mouse button when nothing is selected\n"; - ss += "Camera speed: SHIFT button or controller R2/RT\n"; + ss += "Camera speed: Left Shift button or controller R2/RT\n"; + ss += "Snap transform: Left Ctrl (hold while transforming)\n"; ss += "Camera up: E, down: Q\n"; ss += "Duplicate entity: Ctrl + D\n"; ss += "Select All: Ctrl + A\n"; @@ -1885,9 +1913,13 @@ void EditorComponent::Update(float dt) if (translator.IsDragEnded()) { + EntitySerializer seri; wi::Archive& archive = AdvanceHistory(); archive << HISTORYOP_TRANSLATOR; - archive << translator.GetDragDeltaMatrix(); + translator.transform_start.Serialize(archive, seri); + translator.transform.Serialize(archive, seri); + archive << translator.matrices_start; + archive << translator.matrices_current; } emitterWnd.UpdateData(); @@ -2074,45 +2106,455 @@ void EditorComponent::Render() const renderPath->Render(); - // Selection outline: - if(renderPath->GetDepthStencil() != nullptr && !translator.selected.empty()) + // Editor custom render: + if (!cinemaModeCheckBox.GetCheck()) { GraphicsDevice* device = wi::graphics::GetDevice(); CommandList cmd = device->BeginCommandList(); + device->EventBegin("Editor", cmd); - device->EventBegin("Editor - Selection Outline Mask", cmd); - - Viewport vp; - vp.width = (float)rt_selectionOutline[0].GetDesc().width; - vp.height = (float)rt_selectionOutline[0].GetDesc().height; - device->BindViewports(1, &vp, cmd); - - wi::image::Params fx; - fx.enableFullScreen(); - fx.stencilComp = wi::image::STENCILMODE::STENCILMODE_EQUAL; - - // We will specify the stencil ref in user-space, don't care about engine stencil refs here: - // Otherwise would need to take into account engine ref and draw multiple permutations of stencil refs. - fx.stencilRefMode = wi::image::STENCILREFMODE_USER; - - // Materials outline: + // Selection outline: + if (renderPath->GetDepthStencil() != nullptr && !translator.selected.empty()) { - device->RenderPassBegin(&renderpass_selectionOutline[0], cmd); + device->EventBegin("Selection Outline Mask", cmd); - // Draw solid blocks of selected materials - fx.stencilRef = EDITORSTENCILREF_HIGHLIGHT_MATERIAL; - wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); + Viewport vp; + vp.width = (float)rt_selectionOutline[0].GetDesc().width; + vp.height = (float)rt_selectionOutline[0].GetDesc().height; + device->BindViewports(1, &vp, cmd); - device->RenderPassEnd(cmd); + wi::image::Params fx; + fx.enableFullScreen(); + fx.stencilComp = wi::image::STENCILMODE::STENCILMODE_EQUAL; + + // We will specify the stencil ref in user-space, don't care about engine stencil refs here: + // Otherwise would need to take into account engine ref and draw multiple permutations of stencil refs. + fx.stencilRefMode = wi::image::STENCILREFMODE_USER; + + // Materials outline: + { + device->RenderPassBegin(&renderpass_selectionOutline[0], cmd); + + // Draw solid blocks of selected materials + fx.stencilRef = EDITORSTENCILREF_HIGHLIGHT_MATERIAL; + wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); + + device->RenderPassEnd(cmd); + } + + // Objects outline: + { + device->RenderPassBegin(&renderpass_selectionOutline[1], cmd); + + // Draw solid blocks of selected objects + fx.stencilRef = EDITORSTENCILREF_HIGHLIGHT_OBJECT; + wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); + + device->RenderPassEnd(cmd); + } + + device->EventEnd(cmd); } - // Objects outline: + // Full resolution: { - device->RenderPassBegin(&renderpass_selectionOutline[1], cmd); + device->RenderPassBegin(&renderpass_editor, cmd); - // Draw solid blocks of selected objects - fx.stencilRef = EDITORSTENCILREF_HIGHLIGHT_OBJECT; - wi::image::Draw(wi::texturehelper::getWhite(), fx, cmd); + Viewport vp; + vp.width = (float)editor_depthbuffer.GetDesc().width; + vp.height = (float)editor_depthbuffer.GetDesc().height; + device->BindViewports(1, &vp, cmd); + + // Draw selection outline to the screen: + const float selectionColorIntensity = std::sin(selectionOutlineTimer * XM_2PI * 0.8f) * 0.5f + 0.5f; + if (renderPath->GetDepthStencil() != nullptr && !translator.selected.empty()) + { + device->EventBegin("Selection Outline Edge", cmd); + wi::renderer::BindCommonResources(cmd); + float opacity = wi::math::Lerp(0.4f, 1.0f, selectionColorIntensity); + XMFLOAT4 col = selectionColor2; + col.w *= opacity; + wi::renderer::Postprocess_Outline(rt_selectionOutline[0], cmd, 0.1f, 1, col); + col = selectionColor; + col.w *= opacity; + wi::renderer::Postprocess_Outline(rt_selectionOutline[1], cmd, 0.1f, 1, col); + device->EventEnd(cmd); + } + + + const wi::Color inactiveEntityColor = wi::Color::fromFloat4(XMFLOAT4(1, 1, 1, 0.5f)); + const wi::Color hoveredEntityColor = wi::Color::fromFloat4(XMFLOAT4(1, 1, 1, 1)); + const XMFLOAT4 glow = wi::math::Lerp(wi::math::Lerp(XMFLOAT4(1, 1, 1, 1), selectionColor, 0.4f), selectionColor, selectionColorIntensity); + const wi::Color selectedEntityColor = wi::Color::fromFloat4(glow); + + const CameraComponent& camera = wi::scene::GetCamera(); + + Scene& scene = wi::scene::GetScene(); + + // remove camera jittering + CameraComponent cam = *renderPath->camera; + cam.jitter = XMFLOAT2(0, 0); + cam.UpdateCamera(); + const XMMATRIX VP = cam.GetViewProjection(); + + const XMMATRIX R = XMLoadFloat3x3(&cam.rotationMatrix); + + wi::image::Params fx; + fx.customRotation = &R; + fx.customProjection = &VP; + + if (rendererWnd.GetPickType() & PICK_LIGHT) + { + for (size_t i = 0; i < scene.lights.GetCount(); ++i) + { + const LightComponent& light = scene.lights[i]; + Entity entity = scene.lights.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + switch (light.GetType()) + { + case LightComponent::POINT: + wi::image::Draw(&pointLightTex.GetTexture(), fx, cmd); + break; + case LightComponent::SPOT: + wi::image::Draw(&spotLightTex.GetTexture(), fx, cmd); + break; + case LightComponent::DIRECTIONAL: + wi::image::Draw(&dirLightTex.GetTexture(), fx, cmd); + break; + default: + wi::image::Draw(&areaLightTex.GetTexture(), fx, cmd); + break; + } + } + } + + if (rendererWnd.GetPickType() & PICK_DECAL) + { + for (size_t i = 0; i < scene.decals.GetCount(); ++i) + { + Entity entity = scene.decals.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&decalTex.GetTexture(), fx, cmd); + + } + } + + if (rendererWnd.GetPickType() & PICK_FORCEFIELD) + { + for (size_t i = 0; i < scene.forces.GetCount(); ++i) + { + Entity entity = scene.forces.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&forceFieldTex.GetTexture(), fx, cmd); + } + } + + if (rendererWnd.GetPickType() & PICK_CAMERA) + { + for (size_t i = 0; i < scene.cameras.GetCount(); ++i) + { + Entity entity = scene.cameras.GetEntity(i); + + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&cameraTex.GetTexture(), fx, cmd); + } + } + + if (rendererWnd.GetPickType() & PICK_ARMATURE) + { + for (size_t i = 0; i < scene.armatures.GetCount(); ++i) + { + Entity entity = scene.armatures.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&armatureTex.GetTexture(), fx, cmd); + } + } + + if (rendererWnd.GetPickType() & PICK_EMITTER) + { + for (size_t i = 0; i < scene.emitters.GetCount(); ++i) + { + Entity entity = scene.emitters.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&emitterTex.GetTexture(), fx, cmd); + } + } + + if (rendererWnd.GetPickType() & PICK_HAIR) + { + for (size_t i = 0; i < scene.hairs.GetCount(); ++i) + { + Entity entity = scene.hairs.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&hairTex.GetTexture(), fx, cmd); + } + } + + if (rendererWnd.GetPickType() & PICK_SOUND) + { + for (size_t i = 0; i < scene.sounds.GetCount(); ++i) + { + Entity entity = scene.sounds.GetEntity(i); + const TransformComponent& transform = *scene.transforms.GetComponent(entity); + + float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; + + fx.pos = transform.GetPosition(); + fx.siz = XMFLOAT2(dist, dist); + fx.pivot = XMFLOAT2(0.5f, 0.5f); + fx.color = inactiveEntityColor; + + if (hovered.entity == entity) + { + fx.color = hoveredEntityColor; + } + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + fx.color = selectedEntityColor; + break; + } + } + + + wi::image::Draw(&soundTex.GetTexture(), fx, cmd); + } + } + + if (rendererWnd.nameDebugCheckBox.GetCheck()) + { + device->EventBegin("Debug Names", cmd); + struct DebugNameEntitySorter + { + size_t name_index; + float distance; + XMFLOAT3 position; + }; + static wi::vector debugNameEntitiesSorted; + debugNameEntitiesSorted.clear(); + for (size_t i = 0; i < scene.names.GetCount(); ++i) + { + Entity entity = scene.names.GetEntity(i); + const TransformComponent* transform = scene.transforms.GetComponent(entity); + if (transform != nullptr) + { + auto& x = debugNameEntitiesSorted.emplace_back(); + x.name_index = i; + x.position = transform->GetPosition(); + const ObjectComponent* object = scene.objects.GetComponent(entity); + if (object != nullptr) + { + x.position = object->center; + } + x.distance = wi::math::Distance(x.position, camera.Eye); + } + } + std::sort(debugNameEntitiesSorted.begin(), debugNameEntitiesSorted.end(), [](const DebugNameEntitySorter& a, const DebugNameEntitySorter& b) + { + return a.distance > b.distance; + }); + for (auto& x : debugNameEntitiesSorted) + { + Entity entity = scene.names.GetEntity(x.name_index); + wi::font::Params params; + params.position = x.position; + params.size = wi::font::WIFONTSIZE_DEFAULT; + params.scaling = 1.0f / params.size * x.distance * 0.03f; + params.color = wi::Color::White(); + for (auto& picked : translator.selected) + { + if (picked.entity == entity) + { + params.color = selectedEntityColor; + break; + } + } + params.h_align = wi::font::WIFALIGN_CENTER; + params.v_align = wi::font::WIFALIGN_CENTER; + params.softness = 0.1f; + params.shadowColor = wi::Color::Black(); + params.shadow_softness = 0.5f; + params.customProjection = &VP; + params.customRotation = &R; + wi::font::Draw(scene.names[x.name_index].name, params, cmd); + } + device->EventEnd(cmd); + } + + if (inspector_mode) + { + std::string str; + str += "Entity: " + std::to_string(hovered.entity); + const NameComponent* name = scene.names.GetComponent(hovered.entity); + if (name != nullptr) + { + str += "\nName: " + name->name; + } + XMFLOAT4 pointer = wi::input::GetPointer(); + wi::font::Params params; + params.position = XMFLOAT3(pointer.x - 10, pointer.y, 0); + params.shadowColor = wi::Color::Black(); + params.h_align = wi::font::WIFALIGN_RIGHT; + params.v_align = wi::font::WIFALIGN_CENTER; + wi::font::Draw(str, params, cmd); + } + + + translator.Draw(wi::scene::GetCamera(), cmd); device->RenderPassEnd(cmd); } @@ -2127,409 +2569,6 @@ void EditorComponent::Compose(CommandList cmd) const { renderPath->Compose(cmd); - if (cinemaModeCheckBox.GetCheck()) - { - return; - } - GraphicsDevice* device = wi::graphics::GetDevice(); - - // Draw selection outline to the screen: - const float selectionColorIntensity = std::sin(selectionOutlineTimer * XM_2PI * 0.8f) * 0.5f + 0.5f; - if (renderPath->GetDepthStencil() != nullptr && !translator.selected.empty()) - { - device->EventBegin("Editor - Selection Outline", cmd); - wi::renderer::BindCommonResources(cmd); - float opacity = wi::math::Lerp(0.4f, 1.0f, selectionColorIntensity); - XMFLOAT4 col = selectionColor2; - col.w *= opacity; - wi::renderer::Postprocess_Outline(rt_selectionOutline[0], cmd, 0.1f, 1, col); - col = selectionColor; - col.w *= opacity; - wi::renderer::Postprocess_Outline(rt_selectionOutline[1], cmd, 0.1f, 1, col); - device->EventEnd(cmd); - } - - const CameraComponent& camera = wi::scene::GetCamera(); - - Scene& scene = wi::scene::GetScene(); - - const wi::Color inactiveEntityColor = wi::Color::fromFloat4(XMFLOAT4(1, 1, 1, 0.5f)); - const wi::Color hoveredEntityColor = wi::Color::fromFloat4(XMFLOAT4(1, 1, 1, 1)); - const XMFLOAT4 glow = wi::math::Lerp(wi::math::Lerp(XMFLOAT4(1, 1, 1, 1), selectionColor, 0.4f), selectionColor, selectionColorIntensity); - const wi::Color selectedEntityColor = wi::Color::fromFloat4(glow); - - // remove camera jittering - CameraComponent cam = *renderPath->camera; - cam.jitter = XMFLOAT2(0, 0); - cam.UpdateCamera(); - const XMMATRIX VP = cam.GetViewProjection(); - - const XMMATRIX R = XMLoadFloat3x3(&cam.rotationMatrix); - - wi::image::Params fx; - fx.customRotation = &R; - fx.customProjection = &VP; - if (colorspace != ColorSpace::SRGB) - { - fx.enableLinearOutputMapping(GetHDRScaling()); - } - - if (rendererWnd.GetPickType() & PICK_LIGHT) - { - for (size_t i = 0; i < scene.lights.GetCount(); ++i) - { - const LightComponent& light = scene.lights[i]; - Entity entity = scene.lights.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - switch (light.GetType()) - { - case LightComponent::POINT: - wi::image::Draw(&pointLightTex.GetTexture(), fx, cmd); - break; - case LightComponent::SPOT: - wi::image::Draw(&spotLightTex.GetTexture(), fx, cmd); - break; - case LightComponent::DIRECTIONAL: - wi::image::Draw(&dirLightTex.GetTexture(), fx, cmd); - break; - default: - wi::image::Draw(&areaLightTex.GetTexture(), fx, cmd); - break; - } - } - } - - - if (rendererWnd.GetPickType() & PICK_DECAL) - { - for (size_t i = 0; i < scene.decals.GetCount(); ++i) - { - Entity entity = scene.decals.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&decalTex.GetTexture(), fx, cmd); - - } - } - - if (rendererWnd.GetPickType() & PICK_FORCEFIELD) - { - for (size_t i = 0; i < scene.forces.GetCount(); ++i) - { - Entity entity = scene.forces.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&forceFieldTex.GetTexture(), fx, cmd); - } - } - - if (rendererWnd.GetPickType() & PICK_CAMERA) - { - for (size_t i = 0; i < scene.cameras.GetCount(); ++i) - { - Entity entity = scene.cameras.GetEntity(i); - - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&cameraTex.GetTexture(), fx, cmd); - } - } - - if (rendererWnd.GetPickType() & PICK_ARMATURE) - { - for (size_t i = 0; i < scene.armatures.GetCount(); ++i) - { - Entity entity = scene.armatures.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&armatureTex.GetTexture(), fx, cmd); - } - } - - if (rendererWnd.GetPickType() & PICK_EMITTER) - { - for (size_t i = 0; i < scene.emitters.GetCount(); ++i) - { - Entity entity = scene.emitters.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&emitterTex.GetTexture(), fx, cmd); - } - } - - if (rendererWnd.GetPickType() & PICK_HAIR) - { - for (size_t i = 0; i < scene.hairs.GetCount(); ++i) - { - Entity entity = scene.hairs.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&hairTex.GetTexture(), fx, cmd); - } - } - - if (rendererWnd.GetPickType() & PICK_SOUND) - { - for (size_t i = 0; i < scene.sounds.GetCount(); ++i) - { - Entity entity = scene.sounds.GetEntity(i); - const TransformComponent& transform = *scene.transforms.GetComponent(entity); - - float dist = wi::math::Distance(transform.GetPosition(), camera.Eye) * 0.08f; - - fx.pos = transform.GetPosition(); - fx.siz = XMFLOAT2(dist, dist); - fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.color = inactiveEntityColor; - - if (hovered.entity == entity) - { - fx.color = hoveredEntityColor; - } - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - fx.color = selectedEntityColor; - break; - } - } - - - wi::image::Draw(&soundTex.GetTexture(), fx, cmd); - } - } - - if (rendererWnd.nameDebugCheckBox.GetCheck()) - { - device->EventBegin("Debug Names", cmd); - struct DebugNameEntitySorter - { - size_t name_index; - float distance; - XMFLOAT3 position; - }; - static wi::vector debugNameEntitiesSorted; - debugNameEntitiesSorted.clear(); - for (size_t i = 0; i < scene.names.GetCount(); ++i) - { - Entity entity = scene.names.GetEntity(i); - const TransformComponent* transform = scene.transforms.GetComponent(entity); - if (transform != nullptr) - { - auto& x = debugNameEntitiesSorted.emplace_back(); - x.name_index = i; - x.position = transform->GetPosition(); - const ObjectComponent* object = scene.objects.GetComponent(entity); - if (object != nullptr) - { - x.position = object->center; - } - x.distance = wi::math::Distance(x.position, camera.Eye); - } - } - std::sort(debugNameEntitiesSorted.begin(), debugNameEntitiesSorted.end(), [](const DebugNameEntitySorter& a, const DebugNameEntitySorter& b) - { - return a.distance > b.distance; - }); - for (auto& x : debugNameEntitiesSorted) - { - Entity entity = scene.names.GetEntity(x.name_index); - wi::font::Params params; - params.position = x.position; - params.size = wi::font::WIFONTSIZE_DEFAULT; - params.scaling = 1.0f / params.size * x.distance * 0.03f; - params.color = wi::Color::White(); - for (auto& picked : translator.selected) - { - if (picked.entity == entity) - { - params.color = selectedEntityColor; - break; - } - } - params.h_align = wi::font::WIFALIGN_CENTER; - params.v_align = wi::font::WIFALIGN_CENTER; - params.softness = 0.1f; - params.shadowColor = wi::Color::Black(); - params.shadow_softness = 0.5f; - params.customProjection = &VP; - params.customRotation = &R; - wi::font::Draw(scene.names[x.name_index].name, params, cmd); - } - device->EventEnd(cmd); - } - - if (translator.enabled) - { - translator.Draw(camera, cmd); - } - - if (inspector_mode) - { - std::string str; - str += "Entity: " + std::to_string(hovered.entity); - const NameComponent* name = scene.names.GetComponent(hovered.entity); - if (name != nullptr) - { - str += "\nName: " + name->name; - } - XMFLOAT4 pointer = wi::input::GetPointer(); - wi::font::Params params; - params.position = XMFLOAT3(pointer.x - 10, pointer.y, 0); - params.shadowColor = wi::Color::Black(); - params.h_align = wi::font::WIFALIGN_RIGHT; - params.v_align = wi::font::WIFALIGN_CENTER; - wi::font::Draw(str, params, cmd); - } - RenderPath2D::Compose(cmd); } @@ -2754,18 +2793,29 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) { case HISTORYOP_TRANSLATOR: { - XMFLOAT4X4 delta; - archive >> delta; + EntitySerializer seri; + wi::scene::TransformComponent start; + wi::scene::TransformComponent end; + start.Serialize(archive, seri); + end.Serialize(archive, seri); + wi::vector matrices_start; + wi::vector matrices_end; + archive >> matrices_start; + archive >> matrices_end; translator.enabled = true; translator.PreTranslate(); - XMMATRIX W = XMLoadFloat4x4(&delta); if (undo) { - W = XMMatrixInverse(nullptr, W); + translator.transform = start; + translator.matrices_current = matrices_start; } - W = W * XMLoadFloat4x4(&translator.transform.world); - XMStoreFloat4x4(&translator.transform.world, W); + else + { + translator.transform = end; + translator.matrices_current = matrices_end; + } + translator.transform.UpdateTransform(); translator.PostTranslate(); } break; diff --git a/Editor/Editor.h b/Editor/Editor.h index d9d266cc9..1803110de 100644 --- a/Editor/Editor.h +++ b/Editor/Editor.h @@ -149,6 +149,9 @@ public: const XMFLOAT4 selectionColor = XMFLOAT4(1, 0.6f, 0, 1); const XMFLOAT4 selectionColor2 = XMFLOAT4(0, 1, 0.6f, 0.35f); + wi::graphics::RenderPass renderpass_editor; + wi::graphics::Texture editor_depthbuffer; + Translator translator; wi::scene::PickResult hovered; bool inspector_mode = false; diff --git a/Editor/TransformWindow.cpp b/Editor/TransformWindow.cpp index d64a2713a..2c1dd6831 100644 --- a/Editor/TransformWindow.cpp +++ b/Editor/TransformWindow.cpp @@ -310,6 +310,43 @@ void TransformWindow::Create(EditorComponent* editor) }); AddWidget(&szInput); + + x = 400; + y += step * 5; + + snapScaleInput.Create(""); + snapScaleInput.SetValue(1); + snapScaleInput.SetDescription("Snap mode unit for Scale: "); + snapScaleInput.SetPos(XMFLOAT2(x, y += step)); + snapScaleInput.SetSize(XMFLOAT2(siz, hei)); + snapScaleInput.SetValue(editor->translator.scale_snap); + snapScaleInput.OnInputAccepted([=](wi::gui::EventArgs args) { + editor->translator.scale_snap = args.fValue; + }); + AddWidget(&snapScaleInput); + + snapRotateInput.Create(""); + snapRotateInput.SetValue(1); + snapRotateInput.SetDescription("Snap mode angle for Rotate (in degrees): "); + snapRotateInput.SetPos(XMFLOAT2(x, y += step)); + snapRotateInput.SetSize(XMFLOAT2(siz, hei)); + snapRotateInput.SetValue(editor->translator.rotate_snap / XM_PI * 180); + snapRotateInput.OnInputAccepted([=](wi::gui::EventArgs args) { + editor->translator.rotate_snap = args.fValue / 180.0f * XM_PI; + }); + AddWidget(&snapRotateInput); + + snapTranslateInput.Create(""); + snapTranslateInput.SetValue(1); + snapTranslateInput.SetDescription("Snap mode unit for Translate: "); + snapTranslateInput.SetPos(XMFLOAT2(x, y += step)); + snapTranslateInput.SetSize(XMFLOAT2(siz, hei)); + snapTranslateInput.SetValue(editor->translator.translate_snap); + snapTranslateInput.OnInputAccepted([=](wi::gui::EventArgs args) { + editor->translator.translate_snap = args.fValue; + }); + AddWidget(&snapTranslateInput); + Translate(XMFLOAT3((float)editor->GetLogicalWidth() - 750, 100, 0)); SetVisible(false); diff --git a/Editor/TransformWindow.h b/Editor/TransformWindow.h index 5678ee58b..bf4cc7054 100644 --- a/Editor/TransformWindow.h +++ b/Editor/TransformWindow.h @@ -32,5 +32,10 @@ public: wi::gui::TextInputField sxInput; wi::gui::TextInputField syInput; wi::gui::TextInputField szInput; + + wi::gui::TextInputField snapScaleInput; + wi::gui::TextInputField snapRotateInput; + wi::gui::TextInputField snapTranslateInput; + }; diff --git a/Editor/Translator.cpp b/Editor/Translator.cpp index fbabecdbd..c180d36fe 100644 --- a/Editor/Translator.cpp +++ b/Editor/Translator.cpp @@ -11,18 +11,19 @@ using namespace wi::scene; using namespace wi::graphics; using namespace wi::primitive; -PipelineState pso_solidpart; -PipelineState pso_wirepart; -GPUBuffer vertexBuffer_Axis; -GPUBuffer vertexBuffer_Plane; -GPUBuffer vertexBuffer_Origin; -uint32_t vertexCount_Axis = 0; -uint32_t vertexCount_Plane = 0; -uint32_t vertexCount_Origin = 0; -float origin_size = 0.2f; - namespace Translator_Internal { + PipelineState pso_solidpart; + PipelineState pso_wirepart; + const float origin_size = 0.2f; + const float axis_length = 3.5f; + const float plane_min = 0.5f; + const float plane_max = 1.5f; + const float circle_radius = axis_length; + const float circle_width = 1; + const float circle2_radius = circle_radius + 0.7f; + const float circle2_width = 0.3f; + void LoadShaders() { GraphicsDevice* device = wi::graphics::GetDevice(); @@ -33,9 +34,9 @@ namespace Translator_Internal desc.vs = wi::renderer::GetShader(wi::enums::VSTYPE_VERTEXCOLOR); desc.ps = wi::renderer::GetShader(wi::enums::PSTYPE_VERTEXCOLOR); desc.il = wi::renderer::GetInputLayout(wi::enums::ILTYPE_VERTEXCOLOR); - desc.dss = wi::renderer::GetDepthStencilState(wi::enums::DSSTYPE_DEPTHDISABLED); + desc.dss = wi::renderer::GetDepthStencilState(wi::enums::DSSTYPE_DEFAULT); desc.rs = wi::renderer::GetRasterizerState(wi::enums::RSTYPE_DOUBLESIDED); - desc.bs = wi::renderer::GetBlendState(wi::enums::BSTYPE_ADDITIVE); + desc.bs = wi::renderer::GetBlendState(wi::enums::BSTYPE_TRANSPARENT); desc.pt = PrimitiveTopology::TRIANGLELIST; device->CreatePipelineState(&desc, &pso_solidpart); @@ -47,7 +48,7 @@ namespace Translator_Internal desc.vs = wi::renderer::GetShader(wi::enums::VSTYPE_VERTEXCOLOR); desc.ps = wi::renderer::GetShader(wi::enums::PSTYPE_VERTEXCOLOR); desc.il = wi::renderer::GetInputLayout(wi::enums::ILTYPE_VERTEXCOLOR); - desc.dss = wi::renderer::GetDepthStencilState(wi::enums::DSSTYPE_DEPTHDISABLED); + desc.dss = wi::renderer::GetDepthStencilState(wi::enums::DSSTYPE_DEFAULT); desc.rs = wi::renderer::GetRasterizerState(wi::enums::RSTYPE_WIRE_DOUBLESIDED_SMOOTH); desc.bs = wi::renderer::GetBlendState(wi::enums::BSTYPE_TRANSPARENT); desc.pt = PrimitiveTopology::LINELIST; @@ -55,111 +56,60 @@ namespace Translator_Internal device->CreatePipelineState(&desc, &pso_wirepart); } } + + + struct Vertex + { + XMFLOAT4 position; + XMFLOAT4 color; + }; + const Vertex cubeVerts[] = { + {XMFLOAT4(-1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,-1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,-1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,-1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(1,1,1,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(-1,1,-1,1), XMFLOAT4(1,1,1,1)}, + }; } - -void Translator::Create() -{ - GraphicsDevice* device = wi::graphics::GetDevice(); - - if (!vertexBuffer_Axis.IsValid()) - { - { - XMFLOAT4 verts[] = { - XMFLOAT4(0,0,0,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(3,0,0,1), XMFLOAT4(1,1,1,1), - }; - vertexCount_Axis = arraysize(verts) / 2; - - GPUBufferDesc bd; - bd.usage = Usage::DEFAULT; - bd.size = sizeof(verts); - bd.bind_flags = BindFlag::VERTEX_BUFFER; - - device->CreateBuffer(&bd, verts, &vertexBuffer_Axis); - } - } - - if (!vertexBuffer_Plane.IsValid()) - { - { - XMFLOAT4 verts[] = { - XMFLOAT4(0,0,0,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(1,0,0,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(1,1,0,1), XMFLOAT4(1,1,1,1), - - XMFLOAT4(0,0,0,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(1,1,0,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(0,1,0,1), XMFLOAT4(1,1,1,1), - }; - vertexCount_Plane = arraysize(verts) / 2; - - GPUBufferDesc bd; - bd.usage = Usage::DEFAULT; - bd.size = sizeof(verts); - bd.bind_flags = BindFlag::VERTEX_BUFFER; - - device->CreateBuffer(&bd, verts, &vertexBuffer_Plane); - } - } - - if (!vertexBuffer_Origin.IsValid()) - { - { - float edge = origin_size; - XMFLOAT4 verts[] = { - XMFLOAT4(-edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,-edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,-edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(edge,edge,edge,1), XMFLOAT4(1,1,1,1), - XMFLOAT4(-edge,edge,-edge,1), XMFLOAT4(1,1,1,1), - }; - vertexCount_Origin = arraysize(verts) / 2; - - GPUBufferDesc bd; - bd.usage = Usage::DEFAULT; - bd.size = sizeof(verts); - bd.bind_flags = BindFlag::VERTEX_BUFFER; - - device->CreateBuffer(&bd, verts, &vertexBuffer_Origin); - } - } -} +using namespace Translator_Internal; void Translator::Update(const wi::Canvas& canvas) { if (selected.empty()) { + transform.ClearTransform(); + transform.UpdateTransform(); return; } @@ -193,217 +143,331 @@ void Translator::Update(const wi::Canvas& canvas) { PreTranslate(); + const Ray ray = wi::renderer::GetPickRay((long)pointer.x, (long)pointer.y, canvas, cam); + const XMVECTOR rayOrigin = XMLoadFloat3(&ray.origin); + const XMVECTOR rayDir = XMLoadFloat3(&ray.direction); + if (!dragging) { + state = TRANSLATOR_IDLE; + + // Decide which state to enter for dragging: XMMATRIX P = cam.GetProjection(); XMMATRIX V = cam.GetView(); XMMATRIX W = XMMatrixIdentity(); XMFLOAT3 p = transform.GetPosition(); - dist = wi::math::Distance(p, cam.Eye) * 0.05f; + dist = std::max(wi::math::Distance(p, cam.Eye) * 0.05f, 0.0001f); - Ray ray = wi::renderer::GetPickRay((long)pointer.x, (long)pointer.y, canvas); - - XMVECTOR x, y, z, xy, xz, yz; - - x = pos + XMVectorSet(3, 0, 0, 0) * dist; - y = pos + XMVectorSet(0, 3, 0, 0) * dist; - z = pos + XMVectorSet(0, 0, 3, 0) * dist; - xy = pos + XMVectorSet(1, 1, 0, 0) * dist; - xz = pos + XMVectorSet(1, 0, 1, 0) * dist; - yz = pos + XMVectorSet(0, 1, 1, 0) * dist; - - AABB aabb_origin; - aabb_origin.createFromHalfWidth(p, XMFLOAT3(origin_size * dist, origin_size * dist, origin_size * dist)); - - XMFLOAT3 maxp; - XMStoreFloat3(&maxp, x); - AABB aabb_x = AABB::Merge(AABB(p, maxp), aabb_origin); - - XMStoreFloat3(&maxp, y); - AABB aabb_y = AABB::Merge(AABB(p, maxp), aabb_origin); - - XMStoreFloat3(&maxp, z); - AABB aabb_z = AABB::Merge(AABB(p, maxp), aabb_origin); - - XMStoreFloat3(&maxp, xy); - AABB aabb_xy = AABB(p, maxp); - - XMStoreFloat3(&maxp, xz); - AABB aabb_xz = AABB(p, maxp); - - XMStoreFloat3(&maxp, yz); - AABB aabb_yz = AABB(p, maxp); - - if (aabb_origin.intersects(ray)) + if (isRotator) { - state = TRANSLATOR_XYZ; - } - else if (aabb_x.intersects(ray)) - { - state = TRANSLATOR_X; - } - else if (aabb_y.intersects(ray)) - { - state = TRANSLATOR_Y; - } - else if (aabb_z.intersects(ray)) - { - state = TRANSLATOR_Z; - } - else if (!dragging) - { - state = TRANSLATOR_IDLE; - } + XMVECTOR plane_zy = XMPlaneFromPointNormal(pos, XMVectorSet(1, 0, 0, 0)); + XMVECTOR plane_xz = XMPlaneFromPointNormal(pos, XMVectorSet(0, 1, 0, 0)); + XMVECTOR plane_xy = XMPlaneFromPointNormal(pos, XMVectorSet(0, 0, 1, 0)); - if (state != TRANSLATOR_XYZ) - { - // these can overlap, so take closest one (by checking plane ray trace distance): - XMVECTOR origin = XMLoadFloat3(&ray.origin); - XMVECTOR direction = XMLoadFloat3(&ray.direction); - XMVECTOR N = XMVectorSet(0, 0, 1, 0); + XMVECTOR intersection = XMPlaneIntersectLine(plane_zy, rayOrigin, rayOrigin + rayDir * cam.zFarP); + float dist_x = XMVectorGetX(XMVector3LengthSq(intersection - rayOrigin)); + float len_x = XMVectorGetX(XMVector3Length(intersection - pos)) / dist; + intersection = XMPlaneIntersectLine(plane_xz, rayOrigin, rayOrigin + rayDir * cam.zFarP); + float dist_y = XMVectorGetX(XMVector3LengthSq(intersection - rayOrigin)); + float len_y = XMVectorGetX(XMVector3Length(intersection - pos)) / dist; + intersection = XMPlaneIntersectLine(plane_xy, rayOrigin, rayOrigin + rayDir * cam.zFarP); + float dist_z = XMVectorGetX(XMVector3LengthSq(intersection - rayOrigin)); + float len_z = XMVectorGetX(XMVector3Length(intersection - pos)) / dist; - float prio = FLT_MAX; - if (aabb_xy.intersects(ray)) + float range = circle_width * 0.5f; + float perimeter = circle_radius - range; + float best_dist = std::numeric_limits::max(); + if (std::abs(perimeter - len_x) <= range && dist_x < best_dist) { - state = TRANSLATOR_XY; - prio = XMVectorGetX(XMVector3Dot(N, (origin - pos) / XMVectorAbs(XMVector3Dot(N, direction)))); + state = TRANSLATOR_X; + axis = XMFLOAT3(1, 0, 0); + best_dist = dist_x; + } + if (std::abs(perimeter - len_y) <= range && dist_y < best_dist) + { + state = TRANSLATOR_Y; + axis = XMFLOAT3(0, 1, 0); + best_dist = dist_y; + } + if (std::abs(perimeter - len_z) <= range && dist_z < best_dist) + { + state = TRANSLATOR_Z; + axis = XMFLOAT3(0, 0, 1); + best_dist = dist_z; } - N = XMVectorSet(0, 1, 0, 0); - float d = XMVectorGetX(XMVector3Dot(N, (origin - pos) / XMVectorAbs(XMVector3Dot(N, direction)))); - if (d < prio && aabb_xz.intersects(ray)) + XMVECTOR screen_normal = XMVector3Normalize(cam.GetEye() - pos); + XMVECTOR plane_screen = XMPlaneFromPointNormal(pos, screen_normal); + intersection = XMPlaneIntersectLine(plane_screen, rayOrigin, rayOrigin + rayDir * cam.zFarP); + float len_screen = XMVectorGetX(XMVector3Length(intersection - pos)) / dist; + range = circle2_width * 0.5f; + perimeter = circle2_radius - range; + if (std::abs(perimeter - len_screen) <= range) { - state = TRANSLATOR_XZ; - prio = d; + state = TRANSLATOR_XYZ; + XMStoreFloat3(&axis, screen_normal); + } + + } + else + { + AABB aabb_origin; + aabb_origin.createFromHalfWidth(p, XMFLOAT3(origin_size * dist, origin_size * dist, origin_size * dist)); + + XMFLOAT3 maxp; + XMStoreFloat3(&maxp, pos + XMVector3Transform(XMVectorSet(axis_length, 0, 0, 0) * dist, GetMirrorMatrix(TRANSLATOR_X, cam))); + AABB aabb_x = AABB::Merge(AABB(wi::math::Min(p, maxp), wi::math::Max(p, maxp)), aabb_origin); + + XMStoreFloat3(&maxp, pos + XMVector3Transform(XMVectorSet(0, axis_length, 0, 0) * dist, GetMirrorMatrix(TRANSLATOR_Y, cam))); + AABB aabb_y = AABB::Merge(AABB(wi::math::Min(p, maxp), wi::math::Max(p, maxp)), aabb_origin); + + XMStoreFloat3(&maxp, pos + XMVector3Transform(XMVectorSet(0, 0, axis_length, 0) * dist, GetMirrorMatrix(TRANSLATOR_Z, cam))); + AABB aabb_z = AABB::Merge(AABB(wi::math::Min(p, maxp), wi::math::Max(p, maxp)), aabb_origin); + + XMFLOAT3 minp; + XMStoreFloat3(&minp, pos + XMVector3Transform(XMVectorSet(plane_min, plane_min, 0, 0) * dist, GetMirrorMatrix(TRANSLATOR_XY, cam))); + XMStoreFloat3(&maxp, pos + XMVector3Transform(XMVectorSet(plane_max, plane_max, 0, 0) * dist, GetMirrorMatrix(TRANSLATOR_XY, cam))); + AABB aabb_xy = AABB(wi::math::Min(minp, maxp), wi::math::Max(minp, maxp)); + + XMStoreFloat3(&minp, pos + XMVector3Transform(XMVectorSet(plane_min, 0, plane_min, 0) * dist, GetMirrorMatrix(TRANSLATOR_XZ, cam))); + XMStoreFloat3(&maxp, pos + XMVector3Transform(XMVectorSet(plane_max, 0, plane_max, 0) * dist, GetMirrorMatrix(TRANSLATOR_XZ, cam))); + AABB aabb_xz = AABB(wi::math::Min(minp, maxp), wi::math::Max(minp, maxp)); + + XMStoreFloat3(&minp, pos + XMVector3Transform(XMVectorSet(0, plane_min, plane_min, 0) * dist, GetMirrorMatrix(TRANSLATOR_YZ, cam))); + XMStoreFloat3(&maxp, pos + XMVector3Transform(XMVectorSet(0, plane_max, plane_max, 0) * dist, GetMirrorMatrix(TRANSLATOR_YZ, cam))); + AABB aabb_yz = AABB(wi::math::Min(minp, maxp), wi::math::Max(minp, maxp)); + + if (aabb_origin.intersects(ray)) + { + state = TRANSLATOR_XYZ; + } + else if (aabb_x.intersects(ray)) + { + state = TRANSLATOR_X; + } + else if (aabb_y.intersects(ray)) + { + state = TRANSLATOR_Y; + } + else if (aabb_z.intersects(ray)) + { + state = TRANSLATOR_Z; } - N = XMVectorSet(1, 0, 0, 0); - d = XMVectorGetX(XMVector3Dot(N, (origin - pos) / XMVectorAbs(XMVector3Dot(N, direction)))); - if (d < prio && aabb_yz.intersects(ray)) + if (isTranslator && state != TRANSLATOR_XYZ) { - state = TRANSLATOR_YZ; + // these can overlap, so take closest one (by checking plane ray trace distance): + XMVECTOR N = XMVectorSet(0, 0, 1, 0); + + float prio = FLT_MAX; + if (aabb_xy.intersects(ray)) + { + state = TRANSLATOR_XY; + prio = XMVectorGetX(XMVector3Dot(N, (rayOrigin - pos) / XMVectorAbs(XMVector3Dot(N, rayDir)))); + } + + N = XMVectorSet(0, 1, 0, 0); + float d = XMVectorGetX(XMVector3Dot(N, (rayOrigin - pos) / XMVectorAbs(XMVector3Dot(N, rayDir)))); + if (d < prio && aabb_xz.intersects(ray)) + { + state = TRANSLATOR_XZ; + prio = d; + } + + N = XMVectorSet(1, 0, 0, 0); + d = XMVectorGetX(XMVector3Dot(N, (rayOrigin - pos) / XMVectorAbs(XMVector3Dot(N, rayDir)))); + if (d < prio && aabb_yz.intersects(ray)) + { + state = TRANSLATOR_YZ; + } } } } if (dragging || (state != TRANSLATOR_IDLE && wi::input::Press(wi::input::MOUSE_BUTTON_LEFT))) { - if (!dragging) + // Dragging operation: + if (isRotator) { - dragStarted = true; - dragDeltaMatrix = wi::math::IDENTITY_MATRIX; - } + XMVECTOR intersection = XMPlaneIntersectLine(XMPlaneFromPointNormal(pos, XMLoadFloat3(&axis)), rayOrigin, rayOrigin + rayDir * cam.zFarP); - XMVECTOR plane, planeNormal; - if (state == TRANSLATOR_X) - { - XMVECTOR axis = XMVectorSet(1, 0, 0, 0); - XMVECTOR wrong = XMVector3Cross(cam.GetAt(), axis); - planeNormal = XMVector3Cross(wrong, axis); - } - else if (state == TRANSLATOR_Y) - { - XMVECTOR axis = XMVectorSet(0, 1, 0, 0); - XMVECTOR wrong = XMVector3Cross(cam.GetAt(), axis); - planeNormal = XMVector3Cross(wrong, axis); - } - else if (state == TRANSLATOR_Z) - { - XMVECTOR axis = XMVectorSet(0, 0, 1, 0); - XMVECTOR wrong = XMVector3Cross(cam.GetAt(), axis); - planeNormal = XMVector3Cross(wrong, axis); - } - else if (state == TRANSLATOR_XY) - { - planeNormal = XMVectorSet(0, 0, 1, 0); - } - else if (state == TRANSLATOR_XZ) - { - planeNormal = XMVectorSet(0, 1, 0, 0); - } - else if (state == TRANSLATOR_YZ) - { - planeNormal = XMVectorSet(1, 0, 0, 0); + if (!dragging) + { + dragStarted = true; + transform_start = transform; + XMStoreFloat3(&intersection_start, intersection); + matrices_start = matrices_current; + } + XMVECTOR intersectionPrev = XMLoadFloat3(&intersection_start); + + XMVECTOR o = XMVector3Normalize(intersectionPrev - pos); + XMVECTOR c = XMVector3Normalize(intersection - pos); + XMFLOAT3 original, current; + XMStoreFloat3(&original, o); + XMStoreFloat3(¤t, c); + angle = wi::math::GetAngle(original, current, axis); + + switch (state) + { + case Translator::TRANSLATOR_X: + angle_start = wi::math::GetAngle(XMFLOAT3(0, 1, 0), original, axis); + break; + case Translator::TRANSLATOR_Y: + angle_start = wi::math::GetAngle(XMFLOAT3(0, 0, 1), original, axis); + break; + case Translator::TRANSLATOR_Z: + angle_start = wi::math::GetAngle(XMFLOAT3(1, 0, 0), original, axis); + break; + case Translator::TRANSLATOR_XYZ: + { + XMMATRIX M = XMMatrixInverse(nullptr, XMMatrixLookToLH(XMVectorZero(), XMVector3Normalize(transform.GetPositionV() - cam.GetEye()), cam.GetUp())); + XMFLOAT3 ref; + XMStoreFloat3(&ref, XMVector3TransformNormal(XMVectorSet(0, 1, 0, 0), M)); + angle_start = wi::math::GetAngle(ref, original, axis); + } + break; + default: + break; + } + + if (wi::input::Down(wi::input::BUTTON::KEYBOARD_BUTTON_LCONTROL)) + { + // Snap mode: + angle = std::round(angle / rotate_snap) * rotate_snap; + } + angle = std::fmod(angle, XM_2PI); + + transform = transform_start; + transform.Rotate(XMQuaternionRotationAxis(XMLoadFloat3(&axis), angle)); } else { - // xyz - planeNormal = cam.GetAt(); - } - plane = XMPlaneFromPointNormal(pos, XMVector3Normalize(planeNormal)); + XMVECTOR plane, planeNormal; + if (state == TRANSLATOR_X) + { + XMVECTOR axis = XMVectorSet(1, 0, 0, 0); + XMVECTOR wrong = XMVector3Cross(cam.GetAt(), axis); + planeNormal = XMVector3Cross(wrong, axis); + this->axis = XMFLOAT3(1, 0, 0); + } + else if (state == TRANSLATOR_Y) + { + XMVECTOR axis = XMVectorSet(0, 1, 0, 0); + XMVECTOR wrong = XMVector3Cross(cam.GetAt(), axis); + planeNormal = XMVector3Cross(wrong, axis); + this->axis = XMFLOAT3(0, 1, 0); + } + else if (state == TRANSLATOR_Z) + { + XMVECTOR axis = XMVectorSet(0, 0, 1, 0); + XMVECTOR wrong = XMVector3Cross(cam.GetUp(), axis); + planeNormal = XMVector3Cross(wrong, axis); + this->axis = XMFLOAT3(0, 0, 1); + } + else if (state == TRANSLATOR_XY) + { + planeNormal = XMVectorSet(0, 0, 1, 0); + } + else if (state == TRANSLATOR_XZ) + { + planeNormal = XMVectorSet(0, 1, 0, 0); + } + else if (state == TRANSLATOR_YZ) + { + planeNormal = XMVectorSet(1, 0, 0, 0); + } + else + { + // xyz + planeNormal = cam.GetAt(); + } + plane = XMPlaneFromPointNormal(pos, XMVector3Normalize(planeNormal)); - Ray ray = wi::renderer::GetPickRay((long)pointer.x, (long)pointer.y, canvas); - XMVECTOR rayOrigin = XMLoadFloat3(&ray.origin); - XMVECTOR rayDir = XMLoadFloat3(&ray.direction); - XMVECTOR intersection = XMPlaneIntersectLine(plane, rayOrigin, rayOrigin + rayDir*cam.zFarP); + if (XMVectorGetX(XMVectorAbs(XMVector3Dot(planeNormal, rayDir))) < 0.001f) + return; + XMVECTOR intersection = XMPlaneIntersectLine(plane, rayOrigin, rayOrigin + rayDir * cam.zFarP); - ray = wi::renderer::GetPickRay((long)prevPointer.x, (long)prevPointer.y, canvas); - rayOrigin = XMLoadFloat3(&ray.origin); - rayDir = XMLoadFloat3(&ray.direction); - XMVECTOR intersectionPrev = XMPlaneIntersectLine(plane, rayOrigin, rayOrigin + rayDir*cam.zFarP); + if (!dragging) + { + dragStarted = true; + transform_start = transform; + XMStoreFloat3(&intersection_start, intersection); + matrices_start = matrices_current; + } + XMVECTOR intersectionPrev = XMLoadFloat3(&intersection_start); - XMVECTOR deltaV; - if (state == TRANSLATOR_X) - { - XMVECTOR A = pos, B = pos + XMVectorSet(1, 0, 0, 0); - XMVECTOR P = wi::math::GetClosestPointToLine(A, B, intersection); - XMVECTOR PPrev = wi::math::GetClosestPointToLine(A, B, intersectionPrev); - deltaV = P - PPrev; - } - else if (state == TRANSLATOR_Y) - { - XMVECTOR A = pos, B = pos + XMVectorSet(0, 1, 0, 0); - XMVECTOR P = wi::math::GetClosestPointToLine(A, B, intersection); - XMVECTOR PPrev = wi::math::GetClosestPointToLine(A, B, intersectionPrev); - deltaV = P - PPrev; - } - else if (state == TRANSLATOR_Z) - { - XMVECTOR A = pos, B = pos + XMVectorSet(0, 0, 1, 0); - XMVECTOR P = wi::math::GetClosestPointToLine(A, B, intersection); - XMVECTOR PPrev = wi::math::GetClosestPointToLine(A, B, intersectionPrev); - deltaV = P - PPrev; - } - else - { - deltaV = intersection - intersectionPrev; + XMVECTOR deltaV; + if (state == TRANSLATOR_X) + { + XMVECTOR A = pos, B = pos + XMVectorSet(1, 0, 0, 0); + XMVECTOR P = wi::math::GetClosestPointToLine(A, B, intersection); + XMVECTOR PPrev = wi::math::GetClosestPointToLine(A, B, intersectionPrev); + deltaV = P - PPrev; + } + else if (state == TRANSLATOR_Y) + { + XMVECTOR A = pos, B = pos + XMVectorSet(0, 1, 0, 0); + XMVECTOR P = wi::math::GetClosestPointToLine(A, B, intersection); + XMVECTOR PPrev = wi::math::GetClosestPointToLine(A, B, intersectionPrev); + deltaV = P - PPrev; + } + else if (state == TRANSLATOR_Z) + { + XMVECTOR A = pos, B = pos + XMVectorSet(0, 0, 1, 0); + XMVECTOR P = wi::math::GetClosestPointToLine(A, B, intersection); + XMVECTOR PPrev = wi::math::GetClosestPointToLine(A, B, intersectionPrev); + deltaV = P - PPrev; + } + else + { + deltaV = intersection - intersectionPrev; + + if (isScalator) + { + deltaV = XMVectorReplicate(XMVectorGetY(deltaV)); + } + } + + transform = transform_start; + if (isTranslator) + { + transform.Translate(deltaV); + } + if (isScalator) + { + XMFLOAT3 delta; + XMStoreFloat3(&delta, deltaV); + XMFLOAT3 scale = transform.GetScale(); + scale = XMFLOAT3((1.0f / scale.x) * (scale.x + delta.x), (1.0f / scale.y) * (scale.y + delta.y), (1.0f / scale.z) * (scale.z + delta.z)); + transform.Scale(scale); + } + + if (wi::input::Down(wi::input::BUTTON::KEYBOARD_BUTTON_LCONTROL)) + { + // Snap mode: + if (isTranslator) + { + transform.translation_local.x = std::round(transform.translation_local.x / translate_snap) * translate_snap; + transform.translation_local.y = std::round(transform.translation_local.y / translate_snap) * translate_snap; + transform.translation_local.z = std::round(transform.translation_local.z / translate_snap) * translate_snap; + } + if (isScalator) + { + transform.scale_local.x = std::max(0.1f, std::round(transform.scale_local.x / scale_snap) * scale_snap); + transform.scale_local.y = std::max(0.1f, std::round(transform.scale_local.y / scale_snap) * scale_snap); + transform.scale_local.z = std::max(0.1f, std::round(transform.scale_local.z / scale_snap) * scale_snap); + } + } if (isScalator) { - deltaV = XMVectorSplatY(deltaV); + transform.scale_local.x = std::max(0.001f, transform.scale_local.x); + transform.scale_local.y = std::max(0.001f, transform.scale_local.y); + transform.scale_local.z = std::max(0.001f, transform.scale_local.z); } } - XMFLOAT3 delta; - if (isRotator) - { - deltaV /= XMVector3Length(intersection - rayOrigin); - deltaV *= XM_2PI; - } - XMStoreFloat3(&delta, deltaV); - - if (isTranslator) - { - XMStoreFloat4x4(&dragDeltaMatrix, XMMatrixTranslation(delta.x, delta.y, delta.z) * XMLoadFloat4x4(&dragDeltaMatrix)); - transform.Translate(delta); - } - if (isRotator) - { - XMMATRIX R = XMMatrixRotationRollPitchYaw(delta.x, delta.y, delta.z); - XMStoreFloat4x4(&dragDeltaMatrix, R * XMLoadFloat4x4(&dragDeltaMatrix)); - XMVECTOR Q = XMQuaternionRotationMatrix(R); - XMFLOAT4 quat; - XMStoreFloat4(&quat, Q); - transform.Rotate(quat); - } - if (isScalator) - { - XMFLOAT3 scale = transform.GetScale(); - scale = XMFLOAT3((1.0f / scale.x) * (scale.x + delta.x), (1.0f / scale.y) * (scale.y + delta.y), (1.0f / scale.z) * (scale.z + delta.z)); - XMStoreFloat4x4(&dragDeltaMatrix, XMMatrixScaling(scale.x, scale.y, scale.z) * XMLoadFloat4x4(&dragDeltaMatrix)); - transform.Scale(scale); - } transform.UpdateTransform(); dragging = true; @@ -429,12 +493,10 @@ void Translator::Update(const wi::Canvas& canvas) } dragging = false; } - - prevPointer = pointer; } void Translator::Draw(const CameraComponent& camera, CommandList cmd) const { - if (selected.empty()) + if (!enabled || selected.empty()) { return; } @@ -451,7 +513,7 @@ void Translator::Draw(const CameraComponent& camera, CommandList cmd) const GraphicsDevice* device = wi::graphics::GetDevice(); - device->EventBegin("Editor - Translator", cmd); + device->EventBegin("Translator", cmd); CameraComponent cam_tmp = camera; cam_tmp.jitter = XMFLOAT2(0, 0); // remove temporal jitter @@ -461,84 +523,536 @@ void Translator::Draw(const CameraComponent& camera, CommandList cmd) const MiscCB sb; XMMATRIX mat = XMMatrixScaling(dist, dist, dist)*XMMatrixTranslationFromVector(transform.GetPositionV()) * VP; - XMMATRIX matX = mat; - XMMATRIX matY = XMMatrixRotationZ(XM_PIDIV2)*XMMatrixRotationY(XM_PIDIV2)*mat; - XMMATRIX matZ = XMMatrixRotationY(-XM_PIDIV2)*XMMatrixRotationZ(-XM_PIDIV2)*mat; + XMMATRIX matX = XMMatrixIdentity(); + XMMATRIX matY = XMMatrixRotationZ(XM_PIDIV2)*XMMatrixRotationY(XM_PIDIV2); + XMMATRIX matZ = XMMatrixRotationY(-XM_PIDIV2)*XMMatrixRotationZ(-XM_PIDIV2); - // Planes: + const float channel_min = 0.25f; // min color channel, to avoid pure red/green/blue + const XMFLOAT4 highlight_color = XMFLOAT4(1, 0.6f, 0, 1); + + // Axes: { device->BindPipelineState(&pso_solidpart, cmd); + + uint32_t vertexCount = 0; + GraphicsDevice::GPUAllocation mem; + + if (isRotator) + { + const uint32_t segmentCount = 90; + const uint32_t circle_triangleCount = segmentCount * 2; + vertexCount = circle_triangleCount * 3; + mem = device->AllocateGPU(sizeof(Vertex) * vertexCount, cmd); + uint8_t* dst = (uint8_t*)mem.data; + for (uint32_t i = 0; i < segmentCount; ++i) + { + const float angle0 = (float)i / (float)segmentCount * XM_2PI; + const float angle1 = (float)(i + 1) / (float)segmentCount * XM_2PI; + + // circle: + const float circle_radius_inner = circle_radius - circle_width; + const float circle_halfway = circle_radius - circle_width * 0.5f; + const Vertex verts[] = { + {XMFLOAT4(0, std::sin(angle0) * circle_radius_inner, std::cos(angle0) * circle_radius_inner, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle1) * circle_radius_inner, std::cos(angle1) * circle_radius_inner, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle0) * circle_radius, std::cos(angle0) * circle_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle0) * circle_radius, std::cos(angle0) * circle_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle1) * circle_radius, std::cos(angle1) * circle_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle1) * circle_radius_inner, std::cos(angle1) * circle_radius_inner, 1), XMFLOAT4(1,1,1,1)}, + }; + std::memcpy(dst, verts, sizeof(verts)); + dst += sizeof(verts); + } + } + else + { + const uint32_t segmentCount = 18; + const uint32_t cylinder_triangleCount = segmentCount * 2; + const uint32_t cone_triangleCount = cylinder_triangleCount; + if (isTranslator) + { + vertexCount = (cylinder_triangleCount + cone_triangleCount) * 3; + } + else if (isScalator) + { + vertexCount = cylinder_triangleCount * 3 + arraysize(cubeVerts); + } + mem = device->AllocateGPU(sizeof(Vertex) * vertexCount, cmd); + + const float cone_length = 0.75f; + float cylinder_length = axis_length; + if (isTranslator) + { + cylinder_length -= cone_length; + } + uint8_t* dst = (uint8_t*)mem.data; + for (uint32_t i = 0; i < segmentCount; ++i) + { + const float angle0 = (float)i / (float)segmentCount * XM_2PI; + const float angle1 = (float)(i + 1) / (float)segmentCount * XM_2PI; + // cylinder base: + { + const float cylinder_radius = 0.075f; + const Vertex verts[] = { + {XMFLOAT4(origin_size, std::sin(angle0) * cylinder_radius, std::cos(angle0) * cylinder_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(origin_size, std::sin(angle1) * cylinder_radius, std::cos(angle1) * cylinder_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle0) * cylinder_radius, std::cos(angle0) * cylinder_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle0) * cylinder_radius, std::cos(angle0) * cylinder_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle1) * cylinder_radius, std::cos(angle1) * cylinder_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(origin_size, std::sin(angle1) * cylinder_radius, std::cos(angle1) * cylinder_radius, 1), XMFLOAT4(1,1,1,1)}, + }; + std::memcpy(dst, verts, sizeof(verts)); + dst += sizeof(verts); + } + if (isTranslator) + { + // cone cap: + const float cone_radius = origin_size; + const Vertex verts[] = { + {XMFLOAT4(cylinder_length, 0, 0, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle0) * cone_radius, std::cos(angle0) * cone_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle1) * cone_radius, std::cos(angle1) * cone_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(axis_length, 0, 0, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle0) * cone_radius, std::cos(angle0) * cone_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(cylinder_length, std::sin(angle1) * cone_radius, std::cos(angle1) * cone_radius, 1), XMFLOAT4(1,1,1,1)}, + }; + std::memcpy(dst, verts, sizeof(verts)); + dst += sizeof(verts); + } + } + + if (isScalator) + { + // cube cap: + for (uint32_t i = 0; i < arraysize(cubeVerts); ++i) + { + Vertex vert = cubeVerts[i]; + vert.position.x = vert.position.x * origin_size + cylinder_length - origin_size; + vert.position.y = vert.position.y * origin_size; + vert.position.z = vert.position.z * origin_size; + std::memcpy(dst, &vert, sizeof(vert)); + dst += sizeof(vert); + } + } + } + const GPUBuffer* vbs[] = { - &vertexBuffer_Plane, + &mem.buffer, }; const uint32_t strides[] = { - sizeof(XMFLOAT4) + sizeof(XMFLOAT4), + sizeof(Vertex), }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + // x + XMStoreFloat4x4(&sb.g_xTransform, matX * GetMirrorMatrix(TRANSLATOR_X, camera) * mat); + sb.g_xColor = state == TRANSLATOR_X ? highlight_color : XMFLOAT4(1, channel_min, channel_min, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(vertexCount, 0, cmd); + + // y + XMStoreFloat4x4(&sb.g_xTransform, matY * GetMirrorMatrix(TRANSLATOR_Y, camera)* mat); + sb.g_xColor = state == TRANSLATOR_Y ? highlight_color : XMFLOAT4(channel_min, 1, channel_min, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(vertexCount, 0, cmd); + + // z + XMStoreFloat4x4(&sb.g_xTransform, matZ * GetMirrorMatrix(TRANSLATOR_Z, camera)* mat); + sb.g_xColor = state == TRANSLATOR_Z ? highlight_color : XMFLOAT4(channel_min, channel_min, 1, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(vertexCount, 0, cmd); + } - // xy - XMStoreFloat4x4(&sb.g_xTransform, matX); - sb.g_xColor = state == TRANSLATOR_XY ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(0.4f, 0.4f, 0, 0.4f); - device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Plane, 0, cmd); - - // xz - XMStoreFloat4x4(&sb.g_xTransform, matZ); - sb.g_xColor = state == TRANSLATOR_XZ ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(0.4f, 0.4f, 0, 0.4f); - device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Plane, 0, cmd); - - // yz - XMStoreFloat4x4(&sb.g_xTransform, matY); - sb.g_xColor = state == TRANSLATOR_YZ ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(0.4f, 0.4f, 0, 0.4f); - device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Plane, 0, cmd); - - // Lines: + if (isRotator) { - device->BindPipelineState(&pso_wirepart, cmd); + // An other circle for rotator, a bit thinner and screen facing, so new geo: + const uint32_t segmentCount = 90; + const uint32_t circle2_triangleCount = segmentCount * 2; + uint32_t vertexCount = circle2_triangleCount * 3; + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(Vertex) * vertexCount, cmd); + uint8_t* dst = (uint8_t*)mem.data; + for (uint32_t i = 0; i < segmentCount; ++i) + { + const float angle0 = (float)i / (float)segmentCount * XM_2PI; + const float angle1 = (float)(i + 1) / (float)segmentCount * XM_2PI; + + // circle: + const float circle2_radius_inner = circle2_radius - circle2_width; + const float circle2_halfway = circle2_radius - circle2_width * 0.5f; + const Vertex verts[] = { + {XMFLOAT4(0, std::sin(angle0) * circle2_radius_inner, std::cos(angle0) * circle2_radius_inner, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle1) * circle2_radius_inner, std::cos(angle1) * circle2_radius_inner, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle0) * circle2_radius, std::cos(angle0) * circle2_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle0) * circle2_radius, std::cos(angle0) * circle2_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle1) * circle2_radius, std::cos(angle1) * circle2_radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::sin(angle1) * circle2_radius_inner, std::cos(angle1) * circle2_radius_inner, 1), XMFLOAT4(1,1,1,1)}, + }; + std::memcpy(dst, verts, sizeof(verts)); + dst += sizeof(verts); + } + const GPUBuffer* vbs[] = { - &vertexBuffer_Axis, + &mem.buffer, }; const uint32_t strides[] = { - sizeof(XMFLOAT4) + sizeof(XMFLOAT4), + sizeof(Vertex), }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + XMStoreFloat4x4(&sb.g_xTransform, + XMMatrixRotationY(XM_PIDIV2) * + XMMatrixInverse(nullptr, XMMatrixLookToLH(XMVectorZero(), XMVector3Normalize(transform.GetPositionV() - camera.GetEye()), camera.GetUp())) * + mat + ); + sb.g_xColor = state == TRANSLATOR_XYZ ? highlight_color : XMFLOAT4(1, 1, 1, 0.5f); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(vertexCount, 0, cmd); } - // x - XMStoreFloat4x4(&sb.g_xTransform, matX); - sb.g_xColor = state == TRANSLATOR_X ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(1, 0, 0, 1); - device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Axis, 0, cmd); - - // y - XMStoreFloat4x4(&sb.g_xTransform, matY); - sb.g_xColor = state == TRANSLATOR_Y ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(0, 1, 0, 1); - device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Axis, 0, cmd); - - // z - XMStoreFloat4x4(&sb.g_xTransform, matZ); - sb.g_xColor = state == TRANSLATOR_Z ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(0, 0, 1, 1); - device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Axis, 0, cmd); - // Origin: + if(!isRotator) { device->BindPipelineState(&pso_solidpart, cmd); + + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(cubeVerts), cmd); + std::memcpy(mem.data, cubeVerts, sizeof(cubeVerts)); const GPUBuffer* vbs[] = { - &vertexBuffer_Origin, + &mem.buffer, }; const uint32_t strides[] = { - sizeof(XMFLOAT4) + sizeof(XMFLOAT4), + sizeof(Vertex), }; - device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, nullptr, cmd); - XMStoreFloat4x4(&sb.g_xTransform, mat); - sb.g_xColor = state == TRANSLATOR_XYZ ? XMFLOAT4(1, 1, 1, 1) : XMFLOAT4(0.25f, 0.25f, 0.25f, 1); + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + XMStoreFloat4x4(&sb.g_xTransform, XMMatrixScaling(origin_size, origin_size, origin_size) * mat); + sb.g_xColor = state == TRANSLATOR_XYZ ? highlight_color : XMFLOAT4(0.5f, 0.5f, 0.5f, 1); device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); - device->Draw(vertexCount_Origin, 0, cmd); + device->Draw(arraysize(cubeVerts), 0, cmd); + } + + // Planes: + if (isTranslator) + { + // Wire part: + { + device->BindPipelineState(&pso_wirepart, cmd); + + const Vertex verts[] = { + {XMFLOAT4(plane_min,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_min,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + + {XMFLOAT4(plane_min,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_max,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + + {XMFLOAT4(plane_max,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_max,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + + {XMFLOAT4(plane_max,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_min,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + }; + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(verts), cmd); + std::memcpy(mem.data, verts, sizeof(verts)); + const GPUBuffer* vbs[] = { + &mem.buffer, + }; + const uint32_t strides[] = { + sizeof(Vertex), + }; + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + // xy + XMStoreFloat4x4(&sb.g_xTransform, matX * GetMirrorMatrix(TRANSLATOR_XY, camera) * mat); + sb.g_xColor = state == TRANSLATOR_XY ? highlight_color : XMFLOAT4(channel_min, channel_min, 1, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + + // xz + XMStoreFloat4x4(&sb.g_xTransform, matZ * GetMirrorMatrix(TRANSLATOR_XZ, camera) * mat); + sb.g_xColor = state == TRANSLATOR_XZ ? highlight_color : XMFLOAT4(channel_min, 1, channel_min, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + + // yz + XMStoreFloat4x4(&sb.g_xTransform, matY * GetMirrorMatrix(TRANSLATOR_YZ, camera) * mat); + sb.g_xColor = state == TRANSLATOR_YZ ? highlight_color : XMFLOAT4(1, channel_min, channel_min, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + } + + // Quad part: + { + device->BindPipelineState(&pso_solidpart, cmd); + + const Vertex verts[] = { + {XMFLOAT4(plane_min,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_max,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_max,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + + {XMFLOAT4(plane_min,plane_min,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_max,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(plane_min,plane_max,0,1), XMFLOAT4(1,1,1,1)}, + }; + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(verts), cmd); + std::memcpy(mem.data, verts, sizeof(verts)); + const GPUBuffer* vbs[] = { + &mem.buffer, + }; + const uint32_t strides[] = { + sizeof(Vertex), + }; + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + // xy + XMStoreFloat4x4(&sb.g_xTransform, matX * GetMirrorMatrix(TRANSLATOR_XY, camera) * mat); + sb.g_xColor = state == TRANSLATOR_XY ? highlight_color : XMFLOAT4(channel_min, channel_min, 1, 0.4f); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + + // xz + XMStoreFloat4x4(&sb.g_xTransform, matZ * GetMirrorMatrix(TRANSLATOR_XZ, camera) * mat); + sb.g_xColor = state == TRANSLATOR_XZ ? highlight_color : XMFLOAT4(channel_min, 1, channel_min, 0.4f); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + + // yz + XMStoreFloat4x4(&sb.g_xTransform, matY * GetMirrorMatrix(TRANSLATOR_YZ, camera) * mat); + sb.g_xColor = state == TRANSLATOR_YZ ? highlight_color : XMFLOAT4(1, channel_min, channel_min, 0.4f); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + } + } + + + // Axis texts: + if(!isRotator) + { + char TEXT[3]; + XMMATRIX R = XMLoadFloat3x3(&camera.rotationMatrix); + + wi::font::Params params; + params.v_align = wi::font::WIFALIGN_CENTER; + params.h_align = wi::font::WIFALIGN_CENTER; + params.scaling = 0.04f * dist; + params.customProjection = &VP; + params.customRotation = &R; + params.shadowColor = wi::Color(0, 0, 0, 127); + params.shadow_softness = 0.8f; + XMVECTOR pos = transform.GetPositionV(); + + params.color = wi::Color::fromFloat4(XMFLOAT4(1, channel_min, channel_min, 1)); + XMStoreFloat3(¶ms.position, pos + XMVector3Transform(XMVectorSet(axis_length + 0.5f, 0, 0, 0) * dist, GetMirrorMatrix(TRANSLATOR_X, camera))); + std::memset(TEXT, 0, sizeof(TEXT)); + WriteAxisText(TRANSLATOR_X, camera, TEXT); + wi::font::Draw(TEXT, strlen(TEXT), params, cmd); + + params.color = wi::Color::fromFloat4(XMFLOAT4(channel_min, 1, channel_min, 1)); + XMStoreFloat3(¶ms.position, pos + XMVector3Transform(XMVectorSet(0, axis_length + 0.5f, 0, 0) * dist, GetMirrorMatrix(TRANSLATOR_Y, camera))); + std::memset(TEXT, 0, sizeof(TEXT)); + WriteAxisText(TRANSLATOR_Y, camera, TEXT); + wi::font::Draw(TEXT, strlen(TEXT), params, cmd); + + params.color = wi::Color::fromFloat4(XMFLOAT4(channel_min, channel_min, 1, 1)); + XMStoreFloat3(¶ms.position, pos + XMVector3Transform(XMVectorSet(0, 0, axis_length + 0.5f, 0) * dist, GetMirrorMatrix(TRANSLATOR_Z, camera))); + std::memset(TEXT, 0, sizeof(TEXT)); + WriteAxisText(TRANSLATOR_Z, camera, TEXT); + wi::font::Draw(TEXT, strlen(TEXT), params, cmd); + } + + + // Dragging visualizer: + if (dragging) + { + if (isTranslator) + { + // Origin circle: + { + device->BindPipelineState(&pso_solidpart, cmd); + + const uint32_t segmentCount = 36; + const uint32_t vertexCount = segmentCount * 3; + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(Vertex) * vertexCount, cmd); + + uint8_t* dst = (uint8_t*)mem.data; + for (uint32_t i = 0; i < segmentCount; ++i) + { + const float angle0 = (float)i / (float)segmentCount * XM_2PI; + const float angle1 = (float)(i + 1) / (float)segmentCount * XM_2PI; + + const float radius = 0.2f * dist; + const Vertex verts[] = { + {XMFLOAT4(0, 0, 0, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::cos(angle0) * radius, std::sin(angle0) * radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::cos(angle1) * radius, std::sin(angle1) * radius, 1), XMFLOAT4(1,1,1,1)}, + }; + std::memcpy(dst, verts, sizeof(verts)); + dst += sizeof(verts); + } + + const GPUBuffer* vbs[] = { + &mem.buffer, + }; + const uint32_t strides[] = { + sizeof(Vertex), + }; + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + XMStoreFloat4x4(&sb.g_xTransform, + XMMatrixRotationY(XM_PIDIV2)* + XMMatrixInverse(nullptr, XMMatrixLookToLH(XMVectorZero(), XMVector3Normalize(transform_start.GetPositionV() - camera.GetEye()), camera.GetUp()))* + XMMatrixTranslationFromVector(transform_start.GetPositionV())* + VP + ); + sb.g_xColor = XMFLOAT4(1, 1, 1, 0.5f); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(vertexCount, 0, cmd); + } + + // Line: + { + device->BindPipelineState(&pso_wirepart, cmd); + const Vertex verts[] = { + {XMFLOAT4(transform_start.translation_local.x, transform_start.translation_local.y, transform_start.translation_local.z, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(transform.translation_local.x, transform.translation_local.y, transform.translation_local.z, 1), XMFLOAT4(1,1,1,1)}, + }; + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(verts), cmd); + std::memcpy(mem.data, verts, sizeof(verts)); + const GPUBuffer* vbs[] = { + &mem.buffer, + }; + const uint32_t strides[] = { + sizeof(Vertex), + }; + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + XMStoreFloat4x4(&sb.g_xTransform, VP); + sb.g_xColor = XMFLOAT4(1, 1, 1, 1); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(arraysize(verts), 0, cmd); + } + } + else if (isRotator) + { + device->BindPipelineState(&pso_solidpart, cmd); + + const uint32_t segmentCount = 90; + const uint32_t vertexCount = segmentCount * 3; + GraphicsDevice::GPUAllocation mem = device->AllocateGPU(sizeof(Vertex) * vertexCount, cmd); + + switch (state) + { + case Translator::TRANSLATOR_X: + XMStoreFloat4x4(&sb.g_xTransform, matX * mat); + break; + case Translator::TRANSLATOR_Y: + XMStoreFloat4x4(&sb.g_xTransform, matY * mat); + break; + case Translator::TRANSLATOR_Z: + XMStoreFloat4x4(&sb.g_xTransform, matZ * mat); + break; + case Translator::TRANSLATOR_XYZ: + XMStoreFloat4x4(&sb.g_xTransform, + XMMatrixRotationY(XM_PIDIV2) * + XMMatrixInverse(nullptr, XMMatrixLookToLH(XMVectorZero(), XMVector3Normalize(transform.GetPositionV() - camera.GetEye()), camera.GetUp())) * + mat + ); + break; + default: + break; + } + + uint8_t* dst = (uint8_t*)mem.data; + for (uint32_t i = 0; i < segmentCount; ++i) + { + const float angle0 = (float)i / (float)segmentCount * angle + angle_start; + const float angle1 = (float)(i + 1) / (float)segmentCount * angle + angle_start; + + const float radius = state == TRANSLATOR_XYZ ? (circle2_radius - circle2_width) : (circle_radius - circle_width); + const Vertex verts[] = { + {XMFLOAT4(0, 0, 0, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::cos(angle0) * radius, std::sin(angle0) * radius, 1), XMFLOAT4(1,1,1,1)}, + {XMFLOAT4(0, std::cos(angle1) * radius, std::sin(angle1) * radius, 1), XMFLOAT4(1,1,1,1)}, + }; + std::memcpy(dst, verts, sizeof(verts)); + dst += sizeof(verts); + } + + const GPUBuffer* vbs[] = { + &mem.buffer, + }; + const uint32_t strides[] = { + sizeof(Vertex), + }; + const uint64_t offsets[] = { + mem.offset, + }; + device->BindVertexBuffers(vbs, 0, arraysize(vbs), strides, offsets, cmd); + + sb.g_xColor = XMFLOAT4(1, 1, 1, 0.5f); + device->BindDynamicConstantBuffer(sb, CBSLOT_RENDERER_MISC, cmd); + device->Draw(vertexCount, 0, cmd); + } + + XMFLOAT4 pointer = wi::input::GetPointer(); + wi::font::Params params; + params.posX = pointer.x - 20; + params.posY = pointer.y + 20; + params.v_align = wi::font::WIFALIGN_TOP; + params.h_align = wi::font::WIFALIGN_RIGHT; + params.scaling = 0.8f; + params.shadowColor = wi::Color::Black(); + std::string str; + if (isTranslator) + { + str += "Offset = " + std::to_string(transform.translation_local.x - transform_start.translation_local.x) + ", " + std::to_string(transform.translation_local.y - transform_start.translation_local.y) + ", " + std::to_string(transform.translation_local.z - transform_start.translation_local.z); + } + if (isRotator) + { + switch (state) + { + case Translator::TRANSLATOR_X: + str += "Axis = X"; + break; + case Translator::TRANSLATOR_Y: + str += "Axis = Y"; + break; + case Translator::TRANSLATOR_Z: + str += "Axis = Z"; + break; + case Translator::TRANSLATOR_XYZ: + str += "Axis = Screen"; + break; + default: + break; + } + str += "\nAngle = " + std::to_string(int(angle / XM_PI * 180)) + " degrees"; + } + if (isScalator) + { + str += "Scaling = " + std::to_string(transform.scale_local.x / transform_start.scale_local.x) + ", " + std::to_string(transform.scale_local.y / transform_start.scale_local.y) + ", " + std::to_string(transform.scale_local.z / transform_start.scale_local.z); + } + wi::font::Draw(str, params, cmd); } device->EventEnd(cmd); @@ -565,26 +1079,23 @@ void Translator::PreTranslate() if (count > 0) { centerV /= count; - XMFLOAT3 center; - XMStoreFloat3(¢er, centerV); - transform.ClearTransform(); - transform.Translate(center); + XMStoreFloat3(&transform.translation_local, centerV); + transform.SetDirty(); transform.UpdateTransform(); } // translator "bind matrix" XMMATRIX B = XMMatrixInverse(nullptr, XMLoadFloat4x4(&transform.world)); + matrices_current.clear(); for (auto& x : selectedEntitiesNonRecursive) { TransformComponent* transform_selected = scene.transforms.GetComponent(x); if (transform_selected != nullptr) { - // selected to world space: - transform_selected->ApplyTransform(); - - // selected to translator local space: - transform_selected->MatrixTransform(B); + XMFLOAT4X4 m; + XMStoreFloat4x4(&m, XMLoadFloat4x4(&transform_selected->world) * B); + matrices_current.push_back(m); } } } @@ -592,12 +1103,18 @@ void Translator::PostTranslate() { Scene& scene = wi::scene::GetScene(); + int i = 0; for (auto& x : selectedEntitiesNonRecursive) { TransformComponent* transform_selected = scene.transforms.GetComponent(x); if (transform_selected != nullptr) { - transform_selected->UpdateTransform_Parented(transform); + const XMFLOAT4X4& m = matrices_current[i++]; + + XMMATRIX W = XMLoadFloat4x4(&m); + XMMATRIX W_parent = XMLoadFloat4x4(&transform.world); + W = W * W_parent; + XMStoreFloat4x4(&transform_selected->world, W); // selected to world space: transform_selected->ApplyTransform(); @@ -616,3 +1133,105 @@ void Translator::PostTranslate() } } +XMMATRIX Translator::GetMirrorMatrix(TRANSLATOR_STATE state, const CameraComponent& camera) const +{ + XMMATRIX mirror = XMMatrixIdentity(); + + if (isRotator) + return mirror; + + switch (state) + { + case Translator::TRANSLATOR_X: + if (camera.Eye.x < transform.translation_local.x) + { + mirror *= XMMatrixScaling(-1, 1, 1); + } + break; + case Translator::TRANSLATOR_Y: + if (camera.Eye.y < transform.translation_local.y) + { + mirror *= XMMatrixScaling(1, -1, 1); + } + break; + case Translator::TRANSLATOR_Z: + if (camera.Eye.z < transform.translation_local.z) + { + mirror *= XMMatrixScaling(1, 1, -1); + } + break; + case Translator::TRANSLATOR_XY: + if (camera.Eye.x < transform.translation_local.x) + { + mirror *= XMMatrixScaling(-1, 1, 1); + } + if (camera.Eye.y < transform.translation_local.y) + { + mirror *= XMMatrixScaling(1, -1, 1); + } + break; + case Translator::TRANSLATOR_XZ: + if (camera.Eye.x < transform.translation_local.x) + { + mirror *= XMMatrixScaling(-1, 1, 1); + } + if (camera.Eye.z < transform.translation_local.z) + { + mirror *= XMMatrixScaling(1, 1, -1); + } + break; + case Translator::TRANSLATOR_YZ: + if (camera.Eye.y < transform.translation_local.y) + { + mirror *= XMMatrixScaling(1, -1, 1); + } + if (camera.Eye.z < transform.translation_local.z) + { + mirror *= XMMatrixScaling(1, 1, -1); + } + break; + default: + break; + } + + return mirror; +} +void Translator::WriteAxisText(TRANSLATOR_STATE axis, const wi::scene::CameraComponent& camera, char* text) const +{ + switch (axis) + { + case Translator::TRANSLATOR_X: + if (camera.Eye.x < transform.translation_local.x) + { + std::memcpy(text, "-X", 2); + } + else + { + std::memcpy(text, "X", 1); + } + break; + case Translator::TRANSLATOR_Y: + if (camera.Eye.y < transform.translation_local.y) + { + std::memcpy(text, "-Y", 2); + } + else + { + std::memcpy(text, "Y", 1); + } + break; + case Translator::TRANSLATOR_Z: + if (camera.Eye.z < transform.translation_local.z) + { + std::memcpy(text, "-Z", 2); + } + else + { + std::memcpy(text, "Z", 1); + } + break; + default: + break; + } +} + diff --git a/Editor/Translator.h b/Editor/Translator.h index c443fed5e..89bf0f2f3 100644 --- a/Editor/Translator.h +++ b/Editor/Translator.h @@ -7,13 +7,14 @@ class Translator { private: - XMFLOAT4 prevPointer = XMFLOAT4(0, 0, 0, 0); - XMFLOAT4X4 dragDeltaMatrix = wi::math::IDENTITY_MATRIX; bool dragging = false; bool dragStarted = false; bool dragEnded = false; + XMFLOAT3 intersection_start = XMFLOAT3(0, 0, 0); + XMFLOAT3 axis = XMFLOAT3(1, 0, 0); + float angle = 0; + float angle_start = 0; public: - void Create(); void Update(const wi::Canvas& canvas); void Draw(const wi::scene::CameraComponent& camera, wi::graphics::CommandList cmd) const; @@ -29,6 +30,9 @@ public: wi::vector selectedEntitiesNonRecursive; // selected entities that don't contain entities that would be included in recursive iterations bool enabled = false; + float scale_snap = 1; + float rotate_snap = XM_PIDIV4; + float translate_snap = 1; enum TRANSLATOR_STATE { @@ -42,6 +46,9 @@ public: TRANSLATOR_XYZ, } state = TRANSLATOR_IDLE; + XMMATRIX GetMirrorMatrix(TRANSLATOR_STATE state, const wi::scene::CameraComponent& camera) const; + void WriteAxisText(TRANSLATOR_STATE axis, const wi::scene::CameraComponent& camera, char* text) const; + float dist = 1; bool isTranslator = true, isScalator = false, isRotator = false; @@ -51,7 +58,9 @@ public: bool IsDragStarted() const { return dragStarted; }; // Check if the drag ended in this exact frame bool IsDragEnded() const { return dragEnded; }; - // Delta matrix from beginning to end of drag operation - XMFLOAT4X4 GetDragDeltaMatrix() const { return dragDeltaMatrix; } + + wi::scene::TransformComponent transform_start; + wi::vector matrices_start; + wi::vector matrices_current; }; diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 2186445e0..e7fe39745 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -284,8 +284,9 @@ namespace wi::gui } static const float _border = 2; - float textWidth = tooltipFont.TextWidth() + _border * 2; - float textHeight = tooltipFont.TextHeight() + _border * 2; + XMFLOAT2 textSize = tooltipFont.TextSize(); + float textWidth = textSize.x + _border * 2; + float textHeight = textSize.y + _border * 2; XMFLOAT2 pointer = GetPointerHitbox().pos; tooltipFont.params.posX = pointer.x; diff --git a/WickedEngine/wiMath.cpp b/WickedEngine/wiMath.cpp index 110d753cc..48dc754d0 100644 --- a/WickedEngine/wiMath.cpp +++ b/WickedEngine/wiMath.cpp @@ -99,6 +99,20 @@ namespace wi::math } return angle; } + float GetAngle(const XMFLOAT3& a, const XMFLOAT3& b, const XMFLOAT3& axis) + { + XMVECTOR A = XMLoadFloat3(&a); + XMVECTOR B = XMLoadFloat3(&b); + float dp = XMVectorGetX(XMVector3Dot(A, B)); + dp = wi::math::Clamp(dp, -1, 1); + float angle = std::acos(dp); + XMVECTOR CROSS = XMVector3Cross(A, B); + if (XMVectorGetX(XMVector3Dot(CROSS, XMLoadFloat3(&axis))) < 0) + { + angle = XM_2PI - angle; + } + return angle; + } void ConstructTriangleEquilateral(float radius, XMFLOAT4& A, XMFLOAT4& B, XMFLOAT4& C) { float deg = 0; diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index a0d5b5ddf..9551940b8 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -240,6 +240,7 @@ namespace wi::math float GetPointSegmentDistance(const XMVECTOR& point, const XMVECTOR& segmentA, const XMVECTOR& segmentB); float GetAngle(const XMFLOAT2& a, const XMFLOAT2& b); + float GetAngle(const XMFLOAT3& a, const XMFLOAT3& b, const XMFLOAT3& axis); void ConstructTriangleEquilateral(float radius, XMFLOAT4& A, XMFLOAT4& B, XMFLOAT4& C); void GetBarycentric(const XMVECTOR& p, const XMVECTOR& a, const XMVECTOR& b, const XMVECTOR& c, float &u, float &v, float &w, bool clamp = false); diff --git a/WickedEngine/wiRenderPath2D.cpp b/WickedEngine/wiRenderPath2D.cpp index 57741e487..5852e7617 100644 --- a/WickedEngine/wiRenderPath2D.cpp +++ b/WickedEngine/wiRenderPath2D.cpp @@ -92,7 +92,6 @@ namespace wi device->CreateRenderPass(&desc, &renderpass_final); } - } void RenderPath2D::ResizeLayout() { @@ -137,20 +136,6 @@ namespace wi } } - if (colorspace != ColorSpace::SRGB && (rtLinearColorSpace.desc.width != rtFinal.desc.width || rtLinearColorSpace.desc.height != rtFinal.desc.height)) - { - TextureDesc desc = rtFinal.desc; - desc.format = Format::R16G16B16A16_FLOAT; - bool success = wi::graphics::GetDevice()->CreateTexture(&desc, nullptr, &rtLinearColorSpace); - assert(success); - wi::graphics::GetDevice()->SetName(&rtLinearColorSpace, "rtLinearColorSpace"); - - RenderPassDesc renderpassdesc; - renderpassdesc.attachments.push_back(RenderPassAttachment::RenderTarget(&rtLinearColorSpace, RenderPassAttachment::LoadOp::CLEAR)); - success = wi::graphics::GetDevice()->CreateRenderPass(&renderpassdesc, &renderpass_linearize); - assert(success); - } - RenderPath::Update(dt); } void RenderPath2D::FixedUpdate() @@ -295,22 +280,6 @@ namespace wi device->RenderPassEnd(cmd); - if (colorspace != ColorSpace::SRGB) - { - // Convert the regular SRGB result of the render path to linear space for HDR compositing: - device->RenderPassBegin(&renderpass_linearize, cmd); - wi::image::Params fx; - fx.enableFullScreen(); - fx.enableLinearOutputMapping(hdr_scaling); - wi::image::Draw(&rtFinal, fx, cmd); - device->RenderPassEnd(cmd); - render_result = rtLinearColorSpace; - } - else - { - render_result = rtFinal; - } - RenderPath::Render(); } void RenderPath2D::Compose(CommandList cmd) const @@ -318,7 +287,12 @@ namespace wi wi::image::Params fx; fx.enableFullScreen(); fx.blendFlag = wi::enums::BLENDMODE_PREMULTIPLIED; - wi::image::Draw(&render_result, fx, cmd); + if (colorspace != ColorSpace::SRGB) + { + // Convert the regular SRGB result of the render path to linear space for HDR compositing: + fx.enableLinearOutputMapping(hdr_scaling); + } + wi::image::Draw(&GetRenderResult(), fx, cmd); RenderPath::Compose(cmd); } diff --git a/WickedEngine/wiRenderPath2D.h b/WickedEngine/wiRenderPath2D.h index 2541546de..f2be31ec5 100644 --- a/WickedEngine/wiRenderPath2D.h +++ b/WickedEngine/wiRenderPath2D.h @@ -21,16 +21,11 @@ namespace wi wi::graphics::RenderPass renderpass_stenciled; wi::graphics::RenderPass renderpass_final; - wi::graphics::Texture rtLinearColorSpace; - wi::graphics::RenderPass renderpass_linearize; - wi::gui::GUI GUI; XMUINT2 current_buffersize{}; float current_layoutscale{}; - mutable wi::graphics::Texture render_result = rtFinal; - float hdr_scaling = 9.0f; public: @@ -44,7 +39,7 @@ namespace wi void Render() const override; void Compose(wi::graphics::CommandList cmd) const override; - const wi::graphics::Texture& GetRenderResult() const { return render_result; } + const wi::graphics::Texture& GetRenderResult() const { return rtFinal; } virtual const wi::graphics::Texture* GetDepthStencil() const { return nullptr; } virtual const wi::graphics::Texture* GetGUIBlurredBackground() const { return nullptr; } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index ac4374c67..7b89c0218 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 70; // minor bug fixes, alterations, refactors, updates - const int revision = 9; + const int revision = 10; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);