Compare commits

..

6 commits

12 changed files with 312 additions and 93 deletions

1
.vscode/launch.json vendored
View file

@ -18,6 +18,7 @@
"program": "${workspaceFolder}/build/bin/editor", "program": "${workspaceFolder}/build/bin/editor",
"args": [], "args": [],
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"preLaunchTask": "buildDebug"
}, },
{ {
"type": "lldb", "type": "lldb",

11
.vscode/tasks.json vendored Normal file
View file

@ -0,0 +1,11 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "buildDebug",
"type": "process",
"command": "cmake",
"args": ["--build", "build", "-j16"]
}
]
}

17
.zed/debug.json Normal file
View file

@ -0,0 +1,17 @@
// Project-local debug tasks
//
// For more documentation on how to configure debug tasks,
// see: https://zed.dev/docs/debugger
[
{
"label": "Debug editor",
"build": {
"command": "cmake",
"args": ["--build", "build", "-j16"],
"cwd": "$ZED_WORKTREE_ROOT"
},
"program": "$ZED_WORKTREE_ROOT/build/bin/editor",
"request": "launch",
"adapter": "CodeLLDB"
}
]

View file

@ -57,6 +57,8 @@ set(SOURCES
src/rendering/font.h src/rendering/font.h
src/rendering/defaultmeshes.h src/rendering/defaultmeshes.h
src/rendering/texture3d.cpp src/rendering/texture3d.cpp
src/rendering/frustum.h
src/rendering/frustum.cpp
src/physics/world.h src/physics/world.h
src/physics/world.cpp src/physics/world.cpp
src/logger.cpp src/logger.cpp

View file

@ -67,3 +67,18 @@ void Workspace::PhysicsStep(float deltaTime) {
} }
} }
} }
std::vector<std::shared_ptr<Instance>> Workspace::CastFrustum(Frustum frustum) {
std::vector<std::shared_ptr<Instance>> parts;
for (auto it = GetDescendantsStart(); it != GetDescendantsEnd(); it++) {
if (!it->IsA<BasePart>()) continue;
std::shared_ptr<BasePart> part = std::dynamic_pointer_cast<BasePart>(*it);
if (!part->locked && frustum.checkAABB(part->position(), part->GetAABB())) {
parts.push_back(part);
}
}
return parts;
}

View file

@ -4,6 +4,7 @@
#include "objects/base/service.h" #include "objects/base/service.h"
#include "objects/joint/jointinstance.h" #include "objects/joint/jointinstance.h"
#include "physics/world.h" #include "physics/world.h"
#include "rendering/frustum.h"
#include <glm/ext/vector_float3.hpp> #include <glm/ext/vector_float3.hpp>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
@ -61,4 +62,5 @@ public:
void PhysicsStep(float deltaTime); void PhysicsStep(float deltaTime);
inline std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); } inline std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF) { return physicsWorld->castRay(point, rotation, maxLength, filter, categoryMaskBits); }
std::vector<std::shared_ptr<Instance>> CastFrustum(Frustum frustum);
}; };

View file

@ -144,6 +144,7 @@ void drawText(std::shared_ptr<Font> font, std::string text, float x, float y, fl
// activate corresponding render state // activate corresponding render state
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // TODO: Figure out why when changed to GL_ONE this causes graphical errors
fontShader->use(); fontShader->use();
fontShader->set("textColor", color); fontShader->set("textColor", color);

View file

@ -0,0 +1,100 @@
#include "frustum.h"
#include "datatypes/vector.h"
#include <glm/ext/matrix_clip_space.hpp>
// https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling
// https://stackoverflow.com/q/66227192/16255372
FrustumPlane::FrustumPlane(Vector3 point, Vector3 normal) : normal(normal.Unit()), distance(normal.Unit().Dot(point)) {}
Frustum::Frustum() {}
Frustum::Frustum(const Camera cam, float aspect, float fovY, float zNear, float zFar) {
const float halfVSide = zFar * tanf(fovY * 0.5f);
const float halfHSide = halfVSide * aspect;
const glm::vec3 frontMultFar = zFar * -cam.cameraFront;
// Don't forget to normalize!!!
glm::vec3 camRight = glm::normalize(glm::cross(cam.cameraFront, cam.cameraUp)); // Technically this is left, but whatever
glm::vec3 trueCamUp = glm::cross(-cam.cameraFront, camRight);
near = { cam.cameraPos + zNear * -cam.cameraFront, -cam.cameraFront };
far = { cam.cameraPos + frontMultFar, cam.cameraFront };
right = { cam.cameraPos,
glm::cross(frontMultFar - camRight * halfHSide, trueCamUp) };
left = { cam.cameraPos,
glm::cross(trueCamUp,frontMultFar + camRight * halfHSide) };
top = { cam.cameraPos,
glm::cross(camRight, frontMultFar - trueCamUp * halfVSide) };
bottom = { cam.cameraPos,
glm::cross(frontMultFar + trueCamUp * halfVSide, camRight) };
}
Frustum Frustum::createSliced(const Camera cam, float width, float height, float left, float right, float top, float bottom, float fovY, float zNear, float zFar) {
Frustum frustum;
float aspect = width / height;
float halfVSide = zFar * tanf(fovY * 0.5f);
float halfHSide = halfVSide * aspect;
const glm::vec3 frontMultFar = zFar * -cam.cameraFront;
float leftSide = -halfHSide * (left / width * 2 - 1);
float rightSide = halfHSide * (right / width * 2 - 1);
float topSide = -halfVSide * (top / height * 2 - 1);
float bottomSide = halfVSide * (bottom / height * 2 - 1);
// Don't forget to normalize!!!
glm::vec3 camRight = glm::normalize(glm::cross(cam.cameraFront, cam.cameraUp)); // Technically this is left, but whatever
glm::vec3 trueCamUp = glm::cross(-cam.cameraFront, camRight);
frustum.near = { cam.cameraPos + zNear * -cam.cameraFront, -cam.cameraFront };
frustum.far = { cam.cameraPos + frontMultFar, cam.cameraFront };
frustum.right = { cam.cameraPos,
glm::cross(frontMultFar - camRight * rightSide, trueCamUp) };
frustum.left = { cam.cameraPos,
glm::cross(trueCamUp,frontMultFar + camRight * leftSide) };
frustum.top = { cam.cameraPos,
glm::cross(camRight, frontMultFar - trueCamUp * topSide) };
frustum.bottom = { cam.cameraPos,
glm::cross(frontMultFar + trueCamUp * bottomSide, camRight) };
return frustum;
}
bool FrustumPlane::checkPointForward(Vector3 point) {
return (normal.Dot(point) - distance) > 0;
}
bool FrustumPlane::checkAABBForward(Vector3 center, Vector3 extents) {
// Not entirely sure how this algorithm works... but hey, when has that ever stopped me?
// https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling
// https://gdbooks.gitbooks.io/3dcollisions/content/Chapter2/static_aabb_plane.html
// Compute the projection interval radius of b onto L(t) = b.c + t * p.n
extents = extents * 0.5f;
const float r = extents.X() * std::abs(normal.X()) +
extents.Y() * std::abs(normal.Y()) + extents.Z() * std::abs(normal.Z());
return -r <= (normal.Dot(center) - distance);
}
bool Frustum::checkPoint(Vector3 point) {
return true
// TODO: Near and far are broken for some reason
// && near.checkPointForward(point)
// && far.checkPointForward(point)
&& left.checkPointForward(point)
&& right.checkPointForward(point)
&& top.checkPointForward(point)
&& bottom.checkPointForward(point)
;
}
bool Frustum::checkAABB(Vector3 center, Vector3 extents) {
return true
// TODO: Near and far are broken for some reason
// && near.checkAABBForward(center, extents)
// && far.checkAABBForward(center, extents)
&& left.checkAABBForward(center, extents)
&& right.checkAABBForward(center, extents)
&& top.checkAABBForward(center, extents)
&& bottom.checkAABBForward(center, extents)
;
}

View file

@ -0,0 +1,35 @@
#pragma once
#include "camera.h"
#include "datatypes/vector.h"
// https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling
struct FrustumPlane {
Vector3 normal;
float distance; // leastPoint = normal * distance
// leastPoint is the closest point to (0,0)
FrustumPlane(Vector3 point, Vector3 normal);
FrustumPlane() = default;
bool checkPointForward(Vector3);
bool checkAABBForward(Vector3 center, Vector3 extents);
};
struct Frustum {
FrustumPlane near;
FrustumPlane far;
FrustumPlane left;
FrustumPlane right;
FrustumPlane top;
FrustumPlane bottom;
Frustum(const Camera cam, float aspect, float fovY, float zNear, float zFar);
static Frustum createSliced(const Camera cam, float width, float height, float left, float right, float top, float bottom, float fovY, float zNear, float zFar);
bool checkPoint(Vector3);
bool checkAABB(Vector3 center, Vector3 extents);
private:
Frustum();
};

View file

@ -1,6 +1,4 @@
#include <glad/gl.h> #include <glad/gl.h>
#include <cmath>
#include <cstdio>
#include <glm/ext.hpp> #include <glm/ext.hpp>
#include <glm/ext/matrix_clip_space.hpp> #include <glm/ext/matrix_clip_space.hpp>
#include <glm/ext/matrix_float4x4.hpp> #include <glm/ext/matrix_float4x4.hpp>
@ -79,8 +77,6 @@ void renderInit(int width, int height) {
glEnable(GL_BLEND); glEnable(GL_BLEND);
glEnable(GL_MULTISAMPLE); glEnable(GL_MULTISAMPLE);
glFrontFace(GL_CW); glFrontFace(GL_CW);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
debugFontTexture = new Texture("assets/textures/debugfnt.bmp", GL_RGB); debugFontTexture = new Texture("assets/textures/debugfnt.bmp", GL_RGB);
@ -170,7 +166,7 @@ void renderParts() {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Use shader // Use shader
shader->use(); shader->use();
@ -234,7 +230,7 @@ void renderSurfaceExtras() {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Use shader // Use shader
ghostShader->use(); ghostShader->use();
@ -358,7 +354,7 @@ void renderAABB() {
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CW); glFrontFace(GL_CW);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Use shader // Use shader
ghostShader->use(); ghostShader->use();
@ -397,7 +393,7 @@ void renderWireframe() {
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CW); glFrontFace(GL_CW);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
// Use shader // Use shader
@ -437,7 +433,7 @@ void renderOutlines() {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Use shader // Use shader
outlineShader->use(); outlineShader->use();
@ -500,7 +496,7 @@ void renderSelectionAssembly() {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); glCullFace(GL_BACK);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
PartAssembly selectionAssembly = PartAssembly::FromSelection(gDataModel->GetService<Selection>()); PartAssembly selectionAssembly = PartAssembly::FromSelection(gDataModel->GetService<Selection>());
@ -538,7 +534,7 @@ void renderRotationArcs() {
glCullFace(GL_BACK); glCullFace(GL_BACK);
glFrontFace(GL_CW); glFrontFace(GL_CW);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Use shader // Use shader
handleShader->use(); handleShader->use();
@ -636,7 +632,6 @@ void renderMessages() {
// glEnable(GL_DEPTH_TEST); // glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
// glEnable(GL_BLEND); // glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) { for (auto it = gWorkspace()->GetDescendantsStart(); it != gWorkspace()->GetDescendantsEnd(); it++) {
if (!it->IsA<Message>()) continue; if (!it->IsA<Message>()) continue;
@ -653,7 +648,7 @@ void renderMessages() {
if (message->text == "") continue; if (message->text == "") continue;
float strokedTextWidth = calcTextWidth(sansSerif, message->text, true); float strokedTextWidth = calcTextWidth(sansSerif, message->text, true);
drawRect(0, 0, viewportWidth, viewportHeight, glm::vec4(0.5)); drawRect(0, 0, viewportWidth, viewportHeight, glm::vec4(0.5, 0.5, 0.5, 0.5));
drawText(sansSerif, message->text, ((float)viewportWidth - textWidth) / 2, ((float)viewportHeight - sansSerif->height) / 2, 1.f, glm::vec3(0), true); drawText(sansSerif, message->text, ((float)viewportWidth - textWidth) / 2, ((float)viewportHeight - sansSerif->height) / 2, 1.f, glm::vec3(0), true);
drawText(sansSerif, message->text, ((float)viewportWidth - strokedTextWidth) / 2, ((float)viewportHeight - sansSerif->height) / 2, 1.f, glm::vec3(1), false); drawText(sansSerif, message->text, ((float)viewportWidth - strokedTextWidth) / 2, ((float)viewportHeight - sansSerif->height) / 2, 1.f, glm::vec3(1), false);
} }
@ -666,6 +661,8 @@ void render() {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
// For some reason this is unset by QPainter, so we override it here
glEnable(GL_MULTISAMPLE);
renderSkyBox(); renderSkyBox();
renderHandles(); renderHandles();
@ -684,11 +681,25 @@ void render() {
// renderAABB(); // renderAABB();
renderTime = tu_clock_micros() - startTime; renderTime = tu_clock_micros() - startTime;
identityShader->use();
identityShader->set("aColor", glm::vec4(1,0,0,1));
// Unbinding both is important or else it will mess up QPainter
// https://stackoverflow.com/a/47417780/16255372
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER,0);
} }
void drawRect(int x, int y, int width, int height, glm::vec4 color) { void drawRect(int x, int y, int width, int height, glm::vec4 color) {
// GL_CULL_FACE has to be disabled as we are flipping the order of the vertices here, besides we don't really care about it // GL_CULL_FACE has to be disabled as we are flipping the order of the vertices here, besides we don't really care about it
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Multiply color
float a = color.a;
color *= a;
color.a = a;
glm::mat4 model(1.0f); // Same applies to this VV glm::mat4 model(1.0f); // Same applies to this VV
// Make sure to cast these to floats, as mat4<i> is a different type that is not compatible // Make sure to cast these to floats, as mat4<i> is a different type that is not compatible
glm::mat4 proj = glm::ortho(0.f, (float)viewportWidth, (float)viewportHeight, 0.f, -1.f, 1.f); glm::mat4 proj = glm::ortho(0.f, (float)viewportWidth, (float)viewportHeight, 0.f, -1.f, 1.f);

View file

@ -1,29 +1,17 @@
#include <glad/gl.h> #include <glad/gl.h>
#include <glm/common.hpp>
#include <glm/vector_relational.hpp>
#include <memory> #include <memory>
#include <miniaudio.h> #include <miniaudio.h>
#include <qcursorconstraints.h> #include <qcursorconstraints.h>
#include <qnamespace.h> #include <QPainter>
#include <qguiapplication.h>
#include <string>
#include "./ui_mainwindow.h" #include "./ui_mainwindow.h"
#include "mainglwidget.h"
#include "datatypes/vector.h"
#include "enum/surface.h"
#include "handles.h"
#include "logger.h"
#include "mainwindow.h"
#include "common.h" #include "common.h"
#include "mainwindow.h"
#include "math_helper.h" #include "math_helper.h"
#include "objects/base/instance.h"
#include "objects/pvinstance.h"
#include "objects/service/selection.h" #include "objects/service/selection.h"
#include "partassembly.h" #include "partassembly.h"
#include "rendering/renderer.h" #include "rendering/renderer.h"
#include "rendering/shader.h" #include "mainglwidget.h"
#include "datatypes/variant.h"
#include "undohistory.h"
#define PI 3.14159 #define PI 3.14159
#define M_mainWindow dynamic_cast<MainWindow*>(window()) #define M_mainWindow dynamic_cast<MainWindow*>(window())
@ -68,9 +56,16 @@ glm::vec2 secondPoint;
extern std::weak_ptr<BasePart> draggingObject; extern std::weak_ptr<BasePart> draggingObject;
extern std::optional<HandleFace> draggingHandle; extern std::optional<HandleFace> draggingHandle;
extern Shader* shader;
void MainGLWidget::paintGL() { void MainGLWidget::paintGL() {
QPainter painter(this);
painter.beginNativePainting();
::render(); ::render();
painter.endNativePainting();
painter.setPen(QColor(200, 200, 200));
painter.drawRect(selectionLasso);
painter.end();
} }
bool isMouseRightDragging = false; bool isMouseRightDragging = false;
@ -326,7 +321,7 @@ std::optional<HandleFace> MainGLWidget::raycastHandle(glm::vec3 pointDir) {
} }
void MainGLWidget::handleCursorChange(QMouseEvent* evt) { void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
if (isMouseRightDragging) return; // Don't change the cursor while it is intentionally blank if (isMouseRightDragging || selectionLasso != QRect{0,0,0,0}) return; // Don't change the cursor while it is intentionally blank
QPoint position = evt->pos(); QPoint position = evt->pos();
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()));
@ -369,43 +364,32 @@ void MainGLWidget::mouseMoveEvent(QMouseEvent* evt) {
default: default:
break; break;
} }
if (selectionLasso != QRect {0,0,0,0}) {
selectionLasso = {selectionLasso.topLeft(), evt->pos()};
float left = std::min(selectionLasso.left(), selectionLasso.right());
float right = std::max(selectionLasso.left(), selectionLasso.right());
float top = std::min(selectionLasso.top(), selectionLasso.bottom());
float bottom = std::max(selectionLasso.top(), selectionLasso.bottom());
Frustum selectionFrustum = Frustum::createSliced(camera, width(), height(), left, right, top, bottom, glm::radians(45.f), 0.1f, 1000.0f);
std::vector<std::shared_ptr<Instance>> castedParts = gWorkspace()->CastFrustum(selectionFrustum);
gDataModel->GetService<Selection>()->Set(castedParts);
}
} }
void MainGLWidget::mousePressEvent(QMouseEvent* evt) { bool MainGLWidget::handlePartClick(QMouseEvent* evt) {
initialTransforms = {};
tryMouseContextMenu = evt->button() == Qt::RightButton;
switch(evt->button()) {
// Camera drag
case Qt::RightButton: {
mouseLockedPos = evt->pos();
isMouseRightDragging = true;
setCursor(Qt::BlankCursor);
QCursorConstraints::lockCursor(window()->windowHandle());
return;
// Clicking on objects
} case Qt::LeftButton: {
QPoint position = evt->pos(); QPoint position = evt->pos();
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()));
// raycast handles
auto handle = raycastHandle(pointDir);
if (handle.has_value()) {
startPoint = glm::vec2(evt->pos().x(), evt->pos().y());
initialAssembly = PartAssembly::FromSelection(gDataModel->GetService<Selection>());
initialFrame = initialAssembly.assemblyOrigin();
initialTransforms = PartAssembly::FromSelection(gDataModel->GetService<Selection>()).GetCurrentTransforms();
isMouseDragging = true;
draggingHandle = handle;
startLinearTransform(evt);
return;
}
// raycast part // raycast part
std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>(); std::shared_ptr<Selection> selection = gDataModel->GetService<Selection>();
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000); std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
if (!rayHit || !rayHit->hitPart) { selection->Set({}); return; } if (!rayHit || !rayHit->hitPart) { selection->Set({}); return false; }
std::shared_ptr<BasePart> part = rayHit->hitPart; std::shared_ptr<BasePart> part = rayHit->hitPart;
if (part->locked) { selection->Set({}); return; } if (part->locked) { selection->Set({}); return false; }
std::shared_ptr<PVInstance> selObject = part; std::shared_ptr<PVInstance> selObject = part;
@ -439,7 +423,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
if (mainWindow()->editSoundEffects && QFile::exists("./assets/excluded/electronicpingshort.wav")) if (mainWindow()->editSoundEffects && QFile::exists("./assets/excluded/electronicpingshort.wav"))
playSound("./assets/excluded/electronicpingshort.wav"); playSound("./assets/excluded/electronicpingshort.wav");
return; return true;
} }
//part.selected = true; //part.selected = true;
@ -458,6 +442,42 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
// Disable bit so that we can ignore the part while raycasting // Disable bit so that we can ignore the part while raycasting
// part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10); // part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
return true;
}
void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
initialTransforms = {};
tryMouseContextMenu = evt->button() == Qt::RightButton;
switch(evt->button()) {
// Camera drag
case Qt::RightButton: {
mouseLockedPos = evt->pos();
isMouseRightDragging = true;
setCursor(Qt::BlankCursor);
QCursorConstraints::lockCursor(window()->windowHandle());
return;
// Clicking on objects
} case Qt::LeftButton: {
QPoint position = evt->pos();
glm::vec3 pointDir = camera.getScreenDirection(glm::vec2(position.x(), position.y()), glm::vec2(width(), height()));
// raycast handles
auto handle = raycastHandle(pointDir);
if (handle.has_value()) {
startPoint = glm::vec2(evt->pos().x(), evt->pos().y());
initialAssembly = PartAssembly::FromSelection(gDataModel->GetService<Selection>());
initialFrame = initialAssembly.assemblyOrigin();
initialTransforms = PartAssembly::FromSelection(gDataModel->GetService<Selection>()).GetCurrentTransforms();
isMouseDragging = true;
draggingHandle = handle;
startLinearTransform(evt);
return;
}
if (handlePartClick(evt)) return;
selectionLasso = {position, QSize {0, 0}};
return; return;
} default: } default:
return; return;
@ -471,6 +491,7 @@ void MainGLWidget::mouseReleaseEvent(QMouseEvent* evt) {
isMouseDragging = false; isMouseDragging = false;
draggingObject = {}; draggingObject = {};
draggingHandle = std::nullopt; draggingHandle = std::nullopt;
selectionLasso = {0,0,0,0};
setCursor(Qt::ArrowCursor); setCursor(Qt::ArrowCursor);
if (!initialTransforms.empty()) { if (!initialTransforms.empty()) {

View file

@ -1,13 +1,13 @@
#ifndef MAINGLWIDGET_H #ifndef MAINGLWIDGET_H
#define MAINGLWIDGET_H #define MAINGLWIDGET_H
#include "objects/part/part.h" #include <glm/fwd.hpp>
#include "qevent.h"
#include <QOpenGLWidget>
#include <QWidget>
#include <memory> #include <memory>
#include <qmenu.h> #include <QEvent>
#include <QOpenGLWidget>
#include <QMenu>
class BasePart;
class HandleFace; class HandleFace;
class MainWindow; class MainWindow;
@ -28,6 +28,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);
bool handlePartClick(QMouseEvent* evt);
void startLinearTransform(QMouseEvent* evt); void startLinearTransform(QMouseEvent* evt);
std::optional<HandleFace> raycastHandle(glm::vec3 pointDir); std::optional<HandleFace> raycastHandle(glm::vec3 pointDir);
@ -42,6 +43,8 @@ protected:
MainWindow* mainWindow(); MainWindow* mainWindow();
float snappingFactor(); float snappingFactor();
QRect selectionLasso;
}; };
#endif // MAINGLWIDGET_H #endif // MAINGLWIDGET_H