refactor(editor): multi-object move support + more handle jank refactor
This commit is contained in:
parent
49f29b6af1
commit
18b12ea1ad
6 changed files with 229 additions and 55 deletions
|
@ -5,6 +5,7 @@ uniform vec3 scale;
|
||||||
in vec3 vPos;
|
in vec3 vPos;
|
||||||
|
|
||||||
out vec4 fColor;
|
out vec4 fColor;
|
||||||
|
uniform vec3 color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// float thickness = 0.2;
|
// float thickness = 0.2;
|
||||||
|
@ -20,5 +21,6 @@ void main() {
|
||||||
// else
|
// else
|
||||||
// fColor = vec4(0);
|
// fColor = vec4(0);
|
||||||
|
|
||||||
fColor = vec4(0.204, 0.584, 0.922, 1);
|
// fColor = vec4(0.204, 0.584, 0.922, 1);
|
||||||
|
fColor = vec4(color, 1);
|
||||||
}
|
}
|
86
core/src/partassembly.cpp
Normal file
86
core/src/partassembly.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#include "partassembly.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "datatypes/cframe.h"
|
||||||
|
#include "datatypes/vector.h"
|
||||||
|
#include "math_helper.h"
|
||||||
|
#include "objects/base/instance.h"
|
||||||
|
#include "objects/part.h"
|
||||||
|
#include <glm/common.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
PartAssembly::PartAssembly(std::vector<std::shared_ptr<Part>> parts, bool worldMode) : parts(parts) {
|
||||||
|
if (parts.size() == 0) return;
|
||||||
|
if (parts.size() == 1 && !worldMode) {
|
||||||
|
_assemblyOrigin = parts[0]->cframe;
|
||||||
|
_bounds = parts[0]->size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 min = parts[0]->position(), max = parts[0]->position();
|
||||||
|
|
||||||
|
for (auto part : parts) {
|
||||||
|
Vector3 aabbSize = part->GetAABB();
|
||||||
|
expandAABB(min, max, part->position() - aabbSize / 2.f);
|
||||||
|
expandAABB(min, max, part->position() + aabbSize / 2.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 pos, size;
|
||||||
|
getAABBCoords(pos, size, min, max);
|
||||||
|
|
||||||
|
_assemblyOrigin = CFrame() + pos;
|
||||||
|
_bounds = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartAssembly PartAssembly::FromSelection(std::vector<std::weak_ptr<Instance>> newSelection) {
|
||||||
|
std::vector<std::shared_ptr<Part>> selection;
|
||||||
|
|
||||||
|
for (std::weak_ptr<Instance> obj : newSelection) {
|
||||||
|
if (obj.expired() || !obj.lock()->IsA<Part>()) continue;
|
||||||
|
|
||||||
|
selection.push_back(obj.lock()->CastTo<Part>().expect());
|
||||||
|
}
|
||||||
|
|
||||||
|
return PartAssembly(selection, editorToolHandles.worldMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PartAssembly::SetOrigin(CFrame newOrigin) {
|
||||||
|
for (auto part : parts) {
|
||||||
|
part->cframe = newOrigin * (_assemblyOrigin.Inverse() * part->cframe);
|
||||||
|
part->UpdateProperty("CFrame");
|
||||||
|
}
|
||||||
|
|
||||||
|
_assemblyOrigin = newOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PartAssembly::TransformBy(CFrame transform) {
|
||||||
|
for (auto part : parts) {
|
||||||
|
part->cframe = transform * part->cframe;
|
||||||
|
part->UpdateProperty("CFrame");
|
||||||
|
}
|
||||||
|
|
||||||
|
_assemblyOrigin = transform * _assemblyOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PartAssembly::Scale(Vector3 newSize, bool scaleUp) {
|
||||||
|
if (parts.size() == 1) {
|
||||||
|
parts[0]->size = newSize;
|
||||||
|
parts[0]->UpdateProperty("Size");
|
||||||
|
_bounds = newSize;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sx = newSize.X() / _bounds.X(), sy = newSize.Y() / _bounds.Y(), sz = newSize.Z() / _bounds.Z();
|
||||||
|
float factor = scaleUp ? glm::max(sx, sy, sz) : glm::min(sx, sy, sz);
|
||||||
|
|
||||||
|
for (auto part : parts) {
|
||||||
|
Vector3 localOff = _assemblyOrigin.Inverse() * part->cframe.Position();
|
||||||
|
localOff = localOff * factor;
|
||||||
|
part->cframe = part->cframe.Rotation() + _assemblyOrigin * localOff;
|
||||||
|
part->UpdateProperty("CFrame");
|
||||||
|
part->size *= factor;
|
||||||
|
part->UpdateProperty("Size");
|
||||||
|
}
|
||||||
|
|
||||||
|
_bounds = _bounds * factor;
|
||||||
|
}
|
35
core/src/partassembly.h
Normal file
35
core/src/partassembly.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "datatypes/cframe.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Part;
|
||||||
|
class Instance;
|
||||||
|
|
||||||
|
const std::vector<std::weak_ptr<Instance>> getSelection();
|
||||||
|
|
||||||
|
class PartAssembly {
|
||||||
|
CFrame _assemblyOrigin;
|
||||||
|
Vector3 _bounds;
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Part>> parts;
|
||||||
|
public:
|
||||||
|
PartAssembly(std::vector<std::shared_ptr<Part>>, bool worldMode = false);
|
||||||
|
|
||||||
|
static PartAssembly FromSelection(std::vector<std::weak_ptr<Instance>> selection = getSelection());
|
||||||
|
|
||||||
|
inline CFrame assemblyOrigin() { return _assemblyOrigin; };
|
||||||
|
inline Vector3 bounds() { return _bounds; };
|
||||||
|
|
||||||
|
// Transforms the assembly such that newOrigin is now this assembly's new assemblyOrigin
|
||||||
|
void SetOrigin(CFrame newOrigin);
|
||||||
|
|
||||||
|
// Rotates and translates the assembly by the transformation
|
||||||
|
void TransformBy(CFrame transform);
|
||||||
|
|
||||||
|
// Scales the assembly to the desired size
|
||||||
|
// If multiple parts are selected, finds the greatest scale factor of each component pair, and
|
||||||
|
// scales it up by that amount
|
||||||
|
void Scale(Vector3 newSize, bool scaleUp = true);
|
||||||
|
};
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
#include "datatypes/cframe.h"
|
#include "datatypes/cframe.h"
|
||||||
#include "datatypes/color3.h"
|
#include "datatypes/color3.h"
|
||||||
|
#include "datatypes/vector.h"
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "math_helper.h"
|
#include "math_helper.h"
|
||||||
|
#include "partassembly.h"
|
||||||
#include "rendering/torus.h"
|
#include "rendering/torus.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
|
@ -442,10 +444,11 @@ void renderOutlines() {
|
||||||
outlineShader->set("viewPos", camera.cameraPos);
|
outlineShader->set("viewPos", camera.cameraPos);
|
||||||
outlineShader->set("thickness", 0.4f);
|
outlineShader->set("thickness", 0.4f);
|
||||||
|
|
||||||
// outlineShader->set("color", glm::vec3(1.f, 0.f, 0.f));
|
outlineShader->set("color", glm::vec3(0.204, 0.584, 0.922));
|
||||||
|
|
||||||
glm::vec3 min, max;
|
glm::vec3 min, max;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) {
|
for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) {
|
||||||
InstanceRef inst = *it;
|
InstanceRef inst = *it;
|
||||||
|
@ -453,6 +456,7 @@ void renderOutlines() {
|
||||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||||
if (!part->selected) continue;
|
if (!part->selected) continue;
|
||||||
|
|
||||||
|
count++;
|
||||||
if (first)
|
if (first)
|
||||||
min = part->position(), max = part->position();
|
min = part->position(), max = part->position();
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -471,7 +475,7 @@ void renderOutlines() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render AABB of selected parts
|
// Render AABB of selected parts
|
||||||
if (first) return;
|
if (count <= 1) return;
|
||||||
|
|
||||||
glm::vec3 outlineSize, outlinePos;
|
glm::vec3 outlineSize, outlinePos;
|
||||||
outlineSize = (max - min);
|
outlineSize = (max - min);
|
||||||
|
@ -487,6 +491,41 @@ void renderOutlines() {
|
||||||
glDrawArrays(GL_TRIANGLES, 0, OUTLINE_MESH->vertexCount);
|
glDrawArrays(GL_TRIANGLES, 0, OUTLINE_MESH->vertexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renderSelectionAssembly() {
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glCullFace(GL_BACK);
|
||||||
|
glFrontFace(GL_CCW);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
PartAssembly selectionAssembly = PartAssembly::FromSelection();
|
||||||
|
|
||||||
|
// Use shader
|
||||||
|
outlineShader->use();
|
||||||
|
|
||||||
|
// view/projection transformations
|
||||||
|
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f);
|
||||||
|
glm::mat4 view = camera.getLookAt();
|
||||||
|
outlineShader->set("projection", projection);
|
||||||
|
outlineShader->set("view", view);
|
||||||
|
|
||||||
|
// Pass in the camera position
|
||||||
|
outlineShader->set("viewPos", camera.cameraPos);
|
||||||
|
outlineShader->set("thickness", 0.4f);
|
||||||
|
|
||||||
|
outlineShader->set("color", glm::vec3(1.f, 0.f, 0.f));
|
||||||
|
|
||||||
|
glm::mat4 model = selectionAssembly.assemblyOrigin();
|
||||||
|
model = glm::scale(model, (glm::vec3)selectionAssembly.bounds() + glm::vec3(0.1));
|
||||||
|
outlineShader->set("model", model);
|
||||||
|
outlineShader->set("scale", (glm::vec3)selectionAssembly.bounds() + glm::vec3(0.05));
|
||||||
|
outlineShader->set("thickness", 0.2f);
|
||||||
|
|
||||||
|
OUTLINE_MESH->bind();
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, OUTLINE_MESH->vertexCount);
|
||||||
|
}
|
||||||
|
|
||||||
void renderRotationArcs() {
|
void renderRotationArcs() {
|
||||||
if (!editorToolHandles.active || editorToolHandles.handlesType != HandlesType::RotateHandles) return;
|
if (!editorToolHandles.active || editorToolHandles.handlesType != HandlesType::RotateHandles) return;
|
||||||
|
|
||||||
|
@ -599,6 +638,7 @@ void render(GLFWwindow* window) {
|
||||||
renderParts();
|
renderParts();
|
||||||
renderSurfaceExtras();
|
renderSurfaceExtras();
|
||||||
renderOutlines();
|
renderOutlines();
|
||||||
|
// renderSelectionAssembly();
|
||||||
renderRotationArcs();
|
renderRotationArcs();
|
||||||
if (wireframeRendering)
|
if (wireframeRendering)
|
||||||
renderWireframe();
|
renderWireframe();
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
#include <qsoundeffect.h>
|
#include <qsoundeffect.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "mainglwidget.h"
|
#include "mainglwidget.h"
|
||||||
|
#include "datatypes/vector.h"
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "math_helper.h"
|
#include "math_helper.h"
|
||||||
#include "objects/base/instance.h"
|
#include "objects/base/instance.h"
|
||||||
|
#include "partassembly.h"
|
||||||
#include "physics/util.h"
|
#include "physics/util.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
#include "rendering/shader.h"
|
#include "rendering/shader.h"
|
||||||
|
@ -171,6 +173,7 @@ inline glm::vec3 vec3fy(glm::vec4 vec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Taken from Godot's implementation of moving handles (godot/editor/plugins/gizmos/gizmo_3d_helper.cpp)
|
// Taken from Godot's implementation of moving handles (godot/editor/plugins/gizmos/gizmo_3d_helper.cpp)
|
||||||
|
Vector3 dragStartHandleOffset;
|
||||||
void MainGLWidget::handleLinearTransform(QMouseEvent* evt) {
|
void MainGLWidget::handleLinearTransform(QMouseEvent* evt) {
|
||||||
if (!isMouseDragging || !draggingHandle|| !editorToolHandles.active) return;
|
if (!isMouseDragging || !draggingHandle|| !editorToolHandles.active) return;
|
||||||
|
|
||||||
|
@ -183,7 +186,9 @@ void MainGLWidget::handleLinearTransform(QMouseEvent* evt) {
|
||||||
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
||||||
pointDir = glm::normalize(pointDir);
|
pointDir = glm::normalize(pointDir);
|
||||||
|
|
||||||
CFrame handleCFrame = getHandleCFrame(draggingHandle.value());
|
// We use lastDragStartPos instead to consider the mouse's actual position, rather than the center
|
||||||
|
// of the handle. That way, transformations are "smoother" and do not jump the first movement
|
||||||
|
CFrame handleCFrame = getHandleCFrame(draggingHandle.value()) + dragStartHandleOffset;
|
||||||
|
|
||||||
// Current frame. Identity frame if worldMode == true, selected object's frame if worldMode == false
|
// Current frame. Identity frame if worldMode == true, selected object's frame if worldMode == false
|
||||||
CFrame frame = editorToolHandles.worldMode ? CFrame::IDENTITY + part->position() : part->cframe.Rotation();
|
CFrame frame = editorToolHandles.worldMode ? CFrame::IDENTITY + part->position() : part->cframe.Rotation();
|
||||||
|
@ -200,60 +205,64 @@ void MainGLWidget::handleLinearTransform(QMouseEvent* evt) {
|
||||||
glm::vec3 handlePoint, rb;
|
glm::vec3 handlePoint, rb;
|
||||||
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
||||||
|
|
||||||
// Find new part position
|
// We transform the handlePoint to the handle's cframe, and get it's length (Z)
|
||||||
glm::vec3 centerPoint = partCFrameFromHandlePos(draggingHandle.value(), handlePoint).Position();
|
float diff = (handleCFrame.Inverse() * handlePoint).Z();
|
||||||
|
// Vector3 absDiff = ((Vector3)handlePoint - handleCFrame.Position()); // Commented out because it is functionally identical to the below
|
||||||
|
Vector3 absDiff = handleCFrame.Rotation() * Vector3(0, 0, diff);
|
||||||
|
|
||||||
// Apply snapping in the current frame
|
// Apply snapping
|
||||||
glm::vec3 diff = centerPoint - (glm::vec3)part->position();
|
if (snappingFactor() > 0) {
|
||||||
if (snappingFactor()) diff = frame.Rotation() * (glm::round(glm::vec3(frame.Inverse().Rotation() * diff) / snappingFactor()) * snappingFactor());
|
diff = round(diff / snappingFactor()) * snappingFactor();
|
||||||
|
absDiff = handleCFrame.Rotation() * Vector3(0, 0, diff);
|
||||||
Vector3 oldSize = part->size;
|
|
||||||
|
|
||||||
switch (mainWindow()->selectedTool) {
|
|
||||||
case TOOL_MOVE: {
|
|
||||||
// Add difference
|
|
||||||
part->cframe = part->cframe + diff;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case TOOL_SCALE: {
|
|
||||||
// Find local difference
|
|
||||||
glm::vec3 localDiff = frame.Inverse() * diff;
|
|
||||||
// Find outwarwd difference
|
|
||||||
localDiff = localDiff * glm::sign(draggingHandle->normal);
|
|
||||||
|
|
||||||
// Special case: minimum size to size mod snapping factor
|
|
||||||
if (snappingFactor() > 0 && glm::all(glm::lessThan((part->size + localDiff) * glm::abs(draggingHandle->normal), glm::vec3(0.01f)))) {
|
|
||||||
// I tried something fancy here, but honestly I'm not smart enough. Return;
|
|
||||||
// glm::vec3 finalSize = part->size + localDiff;
|
|
||||||
// finalSize = glm::mod(finalSize * glm::abs(draggingHandle->normal), snappingFactor()) + finalSize * (glm::vec3(1) - glm::abs(draggingHandle->normal));
|
|
||||||
// localDiff = finalSize - part->size;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Minimum size of 0.01f
|
|
||||||
localDiff = glm::max(part->size + localDiff, 0.01f) - part->size;
|
|
||||||
diff = frame * (localDiff * glm::sign(draggingHandle->normal));
|
|
||||||
|
|
||||||
// Add local difference to size
|
|
||||||
part->size += localDiff;
|
|
||||||
|
|
||||||
// If ctrl is not pressed, offset the part by half the size difference to keep the other bound where it was originally
|
|
||||||
if (!(evt->modifiers() & Qt::ControlModifier))
|
|
||||||
part->cframe = part->cframe + diff * 0.5f;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Logger::error("Invalid tool was set to be handled by handleLinearTransform\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snappingFactor() != 0 && mainWindow()->editSoundEffects && (oldSize != part->size) && QFile::exists("./assets/excluded/switch.wav"))
|
PartAssembly selectionAssembly = PartAssembly::FromSelection();
|
||||||
playSound("./assets/excluded/switch.wav");
|
|
||||||
|
|
||||||
gWorkspace()->SyncPartPhysics(part);
|
if (editorToolHandles.handlesType == MoveHandles) {
|
||||||
part->UpdateProperty("Position");
|
selectionAssembly.TransformBy(CFrame() + absDiff);
|
||||||
part->UpdateProperty("Size");
|
} else if (editorToolHandles.handlesType == ScaleHandles) {
|
||||||
sendPropertyUpdatedSignal(part, "Position", part->position());
|
if (evt->modifiers() & Qt::AltModifier) {
|
||||||
sendPropertyUpdatedSignal(part, "Size", Vector3(part->size));
|
// If size gets too small, don't
|
||||||
|
if (glm::any(glm::lessThan(glm::vec3(selectionAssembly.bounds() + abs(draggingHandle->normal) * diff * 2.f), glm::vec3(0.001f))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectionAssembly.Scale(selectionAssembly.bounds() + abs(draggingHandle->normal) * diff * 2.f, diff > 0);
|
||||||
|
} else {
|
||||||
|
// If size gets too small, don't
|
||||||
|
if (glm::any(glm::lessThan(glm::vec3(selectionAssembly.bounds() + abs(draggingHandle->normal) * diff), glm::vec3(0.001f))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectionAssembly.TransformBy(CFrame() + absDiff * 0.5f);
|
||||||
|
selectionAssembly.Scale(selectionAssembly.bounds() + abs(draggingHandle->normal) * diff, diff > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainGLWidget::startLinearTransform(QMouseEvent* evt) {
|
||||||
|
if (!editorToolHandles.active) return;
|
||||||
|
|
||||||
|
QPoint position = evt->pos();
|
||||||
|
|
||||||
|
// This was actually quite a difficult problem to solve, managing to get the handle to go underneath the cursor
|
||||||
|
|
||||||
|
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
||||||
|
pointDir = glm::normalize(pointDir);
|
||||||
|
|
||||||
|
CFrame handleCFrame = getHandleCFrame(draggingHandle.value());
|
||||||
|
|
||||||
|
// Segment from axis stretching -4096 to +4096 rel to handle's position
|
||||||
|
glm::vec3 axisSegment0 = handleCFrame.Position() + (-handleCFrame.LookVector() * 4096.0f);
|
||||||
|
glm::vec3 axisSegment1 = handleCFrame.Position() + (-handleCFrame.LookVector() * -4096.0f);
|
||||||
|
|
||||||
|
// Segment from camera stretching 4096 forward
|
||||||
|
glm::vec3 mouseSegment0 = camera.cameraPos;
|
||||||
|
glm::vec3 mouseSegment1 = camera.cameraPos + pointDir * 4096.0f;
|
||||||
|
|
||||||
|
// Closest point on the axis segment between the two segments
|
||||||
|
glm::vec3 handlePoint, rb;
|
||||||
|
get_closest_points_between_segments(axisSegment0, axisSegment1, mouseSegment0, mouseSegment1, handlePoint, rb);
|
||||||
|
|
||||||
|
dragStartHandleOffset = (Vector3)handlePoint - handleCFrame.Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also implemented based on Godot: [c7ea8614](godot/editor/plugins/canvas_item_editor_plugin.cpp#L1490)
|
// Also implemented based on Godot: [c7ea8614](godot/editor/plugins/canvas_item_editor_plugin.cpp#L1490)
|
||||||
|
@ -369,6 +378,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
||||||
initialFrame = getHandleAdornee()->cframe;
|
initialFrame = getHandleAdornee()->cframe;
|
||||||
isMouseDragging = true;
|
isMouseDragging = true;
|
||||||
draggingHandle = handle;
|
draggingHandle = handle;
|
||||||
|
startLinearTransform(evt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,4 +511,4 @@ float MainGLWidget::snappingFactor() {
|
||||||
case GridSnappingMode::SNAP_OFF: return 0;
|
case GridSnappingMode::SNAP_OFF: return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -26,6 +26,7 @@ protected:
|
||||||
void handleLinearTransform(QMouseEvent* evt);
|
void handleLinearTransform(QMouseEvent* evt);
|
||||||
void handleRotationalTransform(QMouseEvent* evt);
|
void handleRotationalTransform(QMouseEvent* evt);
|
||||||
void handleCursorChange(QMouseEvent* evt);
|
void handleCursorChange(QMouseEvent* evt);
|
||||||
|
void startLinearTransform(QMouseEvent* evt);
|
||||||
std::optional<HandleFace> raycastHandle(glm::vec3 pointDir);
|
std::optional<HandleFace> raycastHandle(glm::vec3 pointDir);
|
||||||
|
|
||||||
void wheelEvent(QWheelEvent* evt) override;
|
void wheelEvent(QWheelEvent* evt) override;
|
||||||
|
|
Loading…
Add table
Reference in a new issue