feat: viewport click-to-select
This commit is contained in:
parent
4caa65a437
commit
9437faadaa
10 changed files with 82 additions and 33 deletions
|
@ -7,8 +7,10 @@
|
|||
#include <glm/geometric.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
#include <reactphysics3d/collision/RaycastInfo.h>
|
||||
#include <vector>
|
||||
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "physics/util.h"
|
||||
#include "qcursor.h"
|
||||
#include "qevent.h"
|
||||
#include "qnamespace.h"
|
||||
|
@ -82,36 +84,14 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
|||
QPoint position = evt->pos();
|
||||
rp::Body* rayHitTarget = NULL;
|
||||
|
||||
// VVV Thank goodness for this person's answer
|
||||
// https://stackoverflow.com/a/30005258/16255372
|
||||
|
||||
// glm::vec3 worldPos = camera.cameraPos + glm::vec3(glm::vec4(float(position.x()) / width() - 0.5f, float(position.y()) / height() - 0.5f, 0, 0) * camera.getLookAt());
|
||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)width() / (float)height(), 0.1f, 100.0f);
|
||||
glm::mat4 view = glm::lookAt(glm::vec3(0), camera.cameraFront, camera.cameraUp);
|
||||
glm::mat4 inverseViewport = glm::inverse(projection * view);
|
||||
|
||||
glm::vec2 ndc = glm::vec2(float(position.x()) / width() * 2.f - 1.f, -float(position.y()) / height() * 2.f + 1.f);
|
||||
glm::vec4 world = glm::normalize(inverseViewport * glm::vec4(ndc, 1, 1));
|
||||
glm::vec3 flat = glm::vec3(world) / world.w; // https://stackoverflow.com/a/68870587/16255372
|
||||
|
||||
printf("At: %f; %f; %f\n", world.x, world.y, world.z);
|
||||
|
||||
workspace->AddChild(lastPart = Part::New({
|
||||
.position = camera.cameraPos + glm::vec3(world) * 10.f,
|
||||
.rotation = glm::vec3(0),
|
||||
.scale = glm::vec3(1, 1, 1),
|
||||
.material = Material {
|
||||
.diffuse = glm::vec3(1.0f, 0.5f, 0.31f),
|
||||
.specular = glm::vec3(0.5f, 0.5f, 0.5f),
|
||||
.shininess = 32.0f,
|
||||
},
|
||||
.anchored = true,
|
||||
}));
|
||||
syncPartPhysics(lastPart);
|
||||
|
||||
castRay(camera.cameraPos, world, 500, new FirstRayHit(&rayHitTarget));
|
||||
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
|
||||
castRay(camera.cameraPos, pointDir, 50000, new FirstRayHit(&rayHitTarget));
|
||||
if (!rayHitTarget) return;
|
||||
printf("Hit: %s\n", reinterpret_cast<Part*>(rayHitTarget->getUserData())->name.c_str());
|
||||
std::shared_ptr<Part> part = partFromBody(rayHitTarget);
|
||||
|
||||
//part.selected = true;
|
||||
setSelection(std::vector<InstanceRefWeak> { part });
|
||||
|
||||
return;
|
||||
} default:
|
||||
return;
|
||||
|
|
|
@ -71,6 +71,10 @@ QModelIndex ExplorerModel::toIndex(InstanceRef item) {
|
|||
return QModelIndex{};
|
||||
}
|
||||
|
||||
QModelIndex ExplorerModel::ObjectToIndex(InstanceRef item) {
|
||||
return toIndex(item);
|
||||
}
|
||||
|
||||
QModelIndex ExplorerModel::parent(const QModelIndex &index) const {
|
||||
if (!index.isValid())
|
||||
return {};
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
Qt::DropActions supportedDragActions() const override;
|
||||
Qt::DropActions supportedDropActions() const override;
|
||||
InstanceRef fromIndex(const QModelIndex index) const;
|
||||
QModelIndex ObjectToIndex(InstanceRef item);
|
||||
private:
|
||||
InstanceRef rootItem;
|
||||
QModelIndex toIndex(InstanceRef item);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "explorerview.h"
|
||||
#include "explorermodel.h"
|
||||
#include "common.h"
|
||||
#include "objects/base/instance.h"
|
||||
#include "qabstractitemmodel.h"
|
||||
#include "qaction.h"
|
||||
#include "qnamespace.h"
|
||||
|
@ -27,6 +28,15 @@ ExplorerView::ExplorerView(QWidget* parent):
|
|||
contextMenu.exec(this->viewport()->mapToGlobal(point));
|
||||
});
|
||||
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
this->clearSelection();
|
||||
for (InstanceRefWeak inst : newSelection) {
|
||||
if (inst.expired()) continue;
|
||||
QModelIndex index = this->model.ObjectToIndex(inst.lock());
|
||||
this->selectionModel()->select(index, QItemSelectionModel::SelectionFlag::Select);
|
||||
}
|
||||
});
|
||||
|
||||
buildContextMenu();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "camera.h"
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
|
||||
Camera::Camera(glm::vec3 initalPosition) {
|
||||
|
@ -53,3 +54,19 @@ void Camera::processRotation(float deltaX, float deltaY) {
|
|||
if(pitch < -89.0f)
|
||||
pitch = -89.0f;
|
||||
}
|
||||
|
||||
glm::vec3 Camera::getScreenDirection(glm::vec2 screenPos, glm::vec2 screenSize) {
|
||||
// VVV Thank goodness for this person's answer
|
||||
// https://stackoverflow.com/a/30005258/16255372
|
||||
|
||||
// glm::vec3 worldPos = camera.cameraPos + glm::vec3(glm::vec4(float(position.x()) / width() - 0.5f, float(position.y()) / height() - 0.5f, 0, 0) * camera.getLookAt());
|
||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)screenSize.x / (float)screenSize.y, 0.1f, 100.0f);
|
||||
glm::mat4 view = glm::lookAt(glm::vec3(0), this->cameraFront, this->cameraUp);
|
||||
glm::mat4 inverseViewport = glm::inverse(projection * view);
|
||||
|
||||
glm::vec2 ndc = glm::vec2(screenPos.x / screenSize.x * 2.f - 1.f, -screenPos.y / screenSize.y * 2.f + 1.f);
|
||||
glm::vec4 world = glm::normalize(inverseViewport * glm::vec4(ndc, 1, 1));
|
||||
//glm::vec3 flat = glm::vec3(world) / world.w; // https://stackoverflow.com/a/68870587/16255372
|
||||
|
||||
return glm::vec3(world);
|
||||
}
|
|
@ -24,7 +24,8 @@ public:
|
|||
Camera(glm::vec3 initialPosition);
|
||||
|
||||
glm::mat4 getLookAt();
|
||||
/** Converts a set of screen coords to a direction from the camera's pos */
|
||||
glm::vec3 getScreenDirection(glm::vec2 screenPos, glm::vec2 screenSize);
|
||||
void processRotation(float deltaX, float deltaY);
|
||||
void processMovement(Direction direction, float deltaTime);
|
||||
|
||||
};
|
||||
|
|
|
@ -7,4 +7,24 @@ Camera camera(glm::vec3(0.0, 0.0, 3.0));
|
|||
//std::vector<Part> parts;
|
||||
std::shared_ptr<Workspace> workspace = Workspace::New();
|
||||
std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
||||
std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||
std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||
|
||||
|
||||
std::vector<InstanceRefWeak> currentSelection;
|
||||
std::vector<SelectionUpdateHandler> selectionUpdateHandlers;
|
||||
|
||||
void setSelection(std::vector<InstanceRefWeak> newSelection, bool fromExplorer) {
|
||||
for (SelectionUpdateHandler handler : selectionUpdateHandlers) {
|
||||
handler(currentSelection, newSelection, fromExplorer);
|
||||
}
|
||||
|
||||
currentSelection = newSelection;
|
||||
}
|
||||
|
||||
const std::vector<InstanceRefWeak> getSelection() {
|
||||
return currentSelection;
|
||||
}
|
||||
|
||||
void addSelectionListener(SelectionUpdateHandler handler) {
|
||||
selectionUpdateHandlers.push_back(handler);
|
||||
}
|
10
src/common.h
10
src/common.h
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "objects/base/instance.h"
|
||||
#include "objects/workspace.h"
|
||||
#include "camera.h"
|
||||
#include <functional>
|
||||
|
@ -8,10 +9,15 @@ class Instance;
|
|||
// typedef std::function<void(std::shared_ptr<Instance> element, std::optional<std::shared_ptr<Instance>> newParent)> HierarchyUpdateHandler;
|
||||
typedef std::function<void(InstanceRef object, std::optional<InstanceRef> oldParent, std::optional<InstanceRef> newParent)> HierarchyPreUpdateHandler;
|
||||
typedef std::function<void(InstanceRef object, std::optional<InstanceRef> oldParent, std::optional<InstanceRef> newParent)> HierarchyPostUpdateHandler;
|
||||
typedef std::function<void(std::vector<InstanceRefWeak> oldSelection, std::vector<InstanceRefWeak> newSelection, bool fromExplorer)> SelectionUpdateHandler;
|
||||
|
||||
// TEMPORARY COMMON DATA FOR DIFFERENT INTERNAL COMPONENTS
|
||||
// TEMPORARY COMMON DATA FOR VARIOUS INTERNAL COMPONENTS
|
||||
|
||||
extern Camera camera;
|
||||
extern std::shared_ptr<Workspace> workspace;
|
||||
extern std::optional<HierarchyPreUpdateHandler> hierarchyPreUpdateHandler;
|
||||
extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||
extern std::optional<HierarchyPostUpdateHandler> hierarchyPostUpdateHandler;
|
||||
|
||||
void setSelection(std::vector<InstanceRefWeak> newSelection, bool fromExplorer = false);
|
||||
const std::vector<InstanceRefWeak> getSelection();
|
||||
void addSelectionListener(SelectionUpdateHandler handler);
|
|
@ -31,6 +31,7 @@ public:
|
|||
glm::quat rotation = glm::identity<glm::quat>();
|
||||
glm::vec3 scale;
|
||||
Material material;
|
||||
bool selected = false;
|
||||
|
||||
bool anchored = false;
|
||||
rp::RigidBody* rigidBody = nullptr;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#pragma once
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <memory>
|
||||
#include <reactphysics3d/body/Body.h>
|
||||
#include <reactphysics3d/mathematics/Quaternion.h>
|
||||
#include <reactphysics3d/mathematics/Vector3.h>
|
||||
#include <reactphysics3d/mathematics/mathematics.h>
|
||||
#include <glm/ext.hpp>
|
||||
#include "objects/part.h"
|
||||
|
||||
namespace rp = reactphysics3d;
|
||||
|
||||
|
@ -21,4 +24,10 @@ inline glm::vec3 rpToGlm(rp::Vector3 vec) {
|
|||
|
||||
inline glm::quat rpToGlm(rp::Quaternion quat) {
|
||||
return glm::quat(quat.w, quat.x, quat.y, quat.z);
|
||||
}
|
||||
|
||||
inline std::shared_ptr<Part> partFromBody(rp::Body* body) {
|
||||
Part* raw = reinterpret_cast<Part*>(body->getUserData());
|
||||
std::shared_ptr<Part> shared = std::dynamic_pointer_cast<Part>(raw->shared_from_this());
|
||||
return shared;
|
||||
}
|
Loading…
Add table
Reference in a new issue