Compare commits
4 commits
d8d469d0e8
...
d972f98ea4
Author | SHA1 | Date | |
---|---|---|---|
d972f98ea4 | |||
9602aa96c0 | |||
ee05b8d9d5 | |||
07272dbe95 |
13 changed files with 309 additions and 98 deletions
11
assets/shaders/outline.fs
Normal file
11
assets/shaders/outline.fs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 330 core
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform vec3 color;
|
||||
|
||||
// Main
|
||||
|
||||
void main() {
|
||||
FragColor = vec4(color, 1);
|
||||
}
|
15
assets/shaders/outline.vs
Normal file
15
assets/shaders/outline.vs
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
|
||||
out vec3 vPos;
|
||||
out vec3 vNormal;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||
}
|
11
assets/shaders/wireframe.fs
Normal file
11
assets/shaders/wireframe.fs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 330 core
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform vec3 color;
|
||||
|
||||
// Main
|
||||
|
||||
void main() {
|
||||
FragColor = vec4(color, 1);
|
||||
}
|
15
assets/shaders/wireframe.vs
Normal file
15
assets/shaders/wireframe.vs
Normal file
|
@ -0,0 +1,15 @@
|
|||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
|
||||
out vec3 vPos;
|
||||
out vec3 vNormal;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||
}
|
|
@ -42,6 +42,7 @@ int main() {
|
|||
.size = glm::vec3(512, 1.2, 512),
|
||||
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.anchored = true,
|
||||
.locked = true,
|
||||
}));
|
||||
|
||||
gWorkspace()->AddChild(lastPart = Part::New({
|
||||
|
|
|
@ -62,7 +62,7 @@ Part::Part(): Part(PartConstructParams { .color = Data::Color3(0.639216f, 0.6352
|
|||
}
|
||||
|
||||
Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(params.position, params.rotation)),
|
||||
size(params.size), color(params.color), anchored(params.anchored) {
|
||||
size(params.size), color(params.color), anchored(params.anchored), locked(params.locked) {
|
||||
this->memberMap = std::make_unique<MemberMap>(MemberMap {
|
||||
.super = std::move(this->memberMap),
|
||||
.members = {
|
||||
|
@ -71,6 +71,10 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par
|
|||
.type = &Data::Bool::TYPE,
|
||||
.codec = fieldCodecOf<Data::Bool, bool>(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||
}}, { "Locked", {
|
||||
.backingField = &locked,
|
||||
.type = &Data::Bool::TYPE,
|
||||
.codec = fieldCodecOf<Data::Bool, bool>(),
|
||||
}}, { "Position", {
|
||||
.backingField = &cframe,
|
||||
.type = &Vector3::TYPE,
|
||||
|
|
|
@ -20,6 +20,7 @@ struct PartConstructParams {
|
|||
Data::Color3 color;
|
||||
|
||||
bool anchored = false;
|
||||
bool locked = false;
|
||||
};
|
||||
|
||||
class Part : public Instance {
|
||||
|
@ -36,6 +37,7 @@ public:
|
|||
bool selected = false;
|
||||
|
||||
bool anchored = false;
|
||||
bool locked = false;
|
||||
rp::RigidBody* rigidBody = nullptr;
|
||||
|
||||
SurfaceType topSurface = SurfaceType::SurfaceStuds;
|
||||
|
|
|
@ -28,10 +28,14 @@ Shader* skyboxShader = NULL;
|
|||
Shader* handleShader = NULL;
|
||||
Shader* identityShader = NULL;
|
||||
Shader* ghostShader = NULL;
|
||||
Shader* wireframeShader = NULL;
|
||||
Shader* outlineShader = NULL;
|
||||
extern Camera camera;
|
||||
Skybox* skyboxTexture = NULL;
|
||||
Texture3D* studsTexture = NULL;
|
||||
|
||||
bool wireframeRendering = false;
|
||||
|
||||
static int viewportWidth, viewportHeight;
|
||||
|
||||
void renderInit(GLFWwindow* window, int width, int height) {
|
||||
|
@ -45,7 +49,6 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
|||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
|
||||
skyboxTexture = new Skybox({
|
||||
"assets/textures/skybox/null_plainsky512_lf.jpg",
|
||||
"assets/textures/skybox/null_plainsky512_rt.jpg",
|
||||
|
@ -63,6 +66,8 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
|||
handleShader = new Shader("assets/shaders/handle.vs", "assets/shaders/handle.fs");
|
||||
identityShader = new Shader("assets/shaders/identity.vs", "assets/shaders/identity.fs");
|
||||
ghostShader = new Shader("assets/shaders/ghost.vs", "assets/shaders/ghost.fs");
|
||||
wireframeShader = new Shader("assets/shaders/wireframe.vs", "assets/shaders/wireframe.fs");
|
||||
outlineShader = new Shader("assets/shaders/outline.vs", "assets/shaders/outline.fs");
|
||||
}
|
||||
|
||||
void renderParts() {
|
||||
|
@ -308,6 +313,112 @@ void renderAABB() {
|
|||
}
|
||||
}
|
||||
|
||||
void renderWireframe() {
|
||||
glDepthMask(GL_TRUE);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CW);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
||||
|
||||
// Use shader
|
||||
wireframeShader->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();
|
||||
wireframeShader->set("projection", projection);
|
||||
wireframeShader->set("view", view);
|
||||
|
||||
// Pass in the camera position
|
||||
wireframeShader->set("viewPos", camera.cameraPos);
|
||||
|
||||
wireframeShader->set("transparency", 0.5f);
|
||||
wireframeShader->set("color", glm::vec3(1.f, 0.f, 0.f));
|
||||
|
||||
// Sort by nearest
|
||||
for (InstanceRef inst : gWorkspace()->GetChildren()) {
|
||||
if (inst->GetClass()->className != "Part") continue;
|
||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||
glm::mat4 model = part->cframe;
|
||||
model = glm::scale(model, (glm::vec3)part->size);
|
||||
wireframeShader->set("model", model);
|
||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
||||
wireframeShader->set("normalMatrix", normalMatrix);
|
||||
|
||||
CUBE_MESH->bind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
||||
}
|
||||
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
}
|
||||
|
||||
void renderOutline() {
|
||||
glDepthMask(GL_TRUE);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
glFrontFace(GL_CW);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
||||
glLineWidth(10.f);
|
||||
|
||||
// Use shader
|
||||
wireframeShader->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();
|
||||
wireframeShader->set("projection", projection);
|
||||
wireframeShader->set("view", view);
|
||||
|
||||
// Pass in the camera position
|
||||
wireframeShader->set("viewPos", camera.cameraPos);
|
||||
|
||||
wireframeShader->set("transparency", 0.5f);
|
||||
wireframeShader->set("color", glm::vec3(0.204, 0.584, 0.922));
|
||||
|
||||
// Sort by nearest
|
||||
for (InstanceRef inst : gWorkspace()->GetChildren()) {
|
||||
if (inst->GetClass()->className != "Part") continue;
|
||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||
if (!part->selected) continue;
|
||||
glm::mat4 model = part->cframe;
|
||||
model = glm::scale(model, (glm::vec3)part->size / glm::vec3(2) + glm::vec3(0.001));
|
||||
wireframeShader->set("model", model);
|
||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
||||
wireframeShader->set("normalMatrix", normalMatrix);
|
||||
|
||||
// CUBE_MESH->bind();
|
||||
// glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
||||
|
||||
glBegin(GL_LINES);
|
||||
// Upper face
|
||||
glVertex3f(-1., 1., -1.); glVertex3f(1., 1., -1.);
|
||||
glVertex3f(-1., 1., 1.); glVertex3f(1., 1., 1.);
|
||||
|
||||
glVertex3f(-1., 1., -1.); glVertex3f(-1., 1., 1.);
|
||||
glVertex3f(1., 1., -1.); glVertex3f(1., 1., 1.);
|
||||
|
||||
// Lower face
|
||||
glVertex3f(-1., -1., -1.); glVertex3f(1., -1., -1.);
|
||||
glVertex3f(-1., -1., 1.); glVertex3f(1., -1., 1.);
|
||||
|
||||
glVertex3f(-1., -1., -1.); glVertex3f(-1., -1., 1.);
|
||||
glVertex3f(1., -1., -1.); glVertex3f(1., -1., 1.);
|
||||
|
||||
// Connecting vertical lines
|
||||
glVertex3f(-1., -1., -1.); glVertex3f(-1., 1., -1.);
|
||||
glVertex3f(1., -1., -1.); glVertex3f(1., 1., -1.);
|
||||
glVertex3f(-1., -1., 1.); glVertex3f(-1., 1., 1.);
|
||||
glVertex3f(1., -1., 1.); glVertex3f(1., 1., 1.);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
}
|
||||
|
||||
void render(GLFWwindow* window) {
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
@ -315,6 +426,9 @@ void render(GLFWwindow* window) {
|
|||
renderSkyBox();
|
||||
renderHandles();
|
||||
renderParts();
|
||||
renderOutline();
|
||||
if (wireframeRendering)
|
||||
renderWireframe();
|
||||
// TODO: Make this a debug flag
|
||||
// renderAABB();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
extern bool wireframeRendering;
|
||||
|
||||
void renderInit(GLFWwindow* window, int width, int height);
|
||||
void render(GLFWwindow* window);
|
||||
void setViewport(int width, int height);
|
|
@ -1,8 +1,10 @@
|
|||
#include <GL/glew.h>
|
||||
#include <qnamespace.h>
|
||||
#include <qsoundeffect.h>
|
||||
#include "mainglwidget.h"
|
||||
#include "common.h"
|
||||
#include "math_helper.h"
|
||||
#include "objects/base/instance.h"
|
||||
#include "physics/util.h"
|
||||
#include "rendering/renderer.h"
|
||||
#include "rendering/shader.h"
|
||||
|
@ -282,7 +284,7 @@ void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
|
|||
};
|
||||
|
||||
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
||||
if (rayHit && partFromBody(rayHit->body)->name != "Baseplate") {
|
||||
if (rayHit && !partFromBody(rayHit->body)->locked) {
|
||||
setCursor(Qt::OpenHandCursor);
|
||||
return;
|
||||
}
|
||||
|
@ -341,7 +343,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
|||
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
|
||||
if (!rayHit || !partFromBody(rayHit->body)) return;
|
||||
std::shared_ptr<Part> part = partFromBody(rayHit->body);
|
||||
if (part->name == "Baseplate") return;
|
||||
if (part->locked) return;
|
||||
|
||||
// Handle surface tool
|
||||
if (mainWindow()->selectedTool >= TOOL_SMOOTH) {
|
||||
|
@ -368,7 +370,20 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
|
|||
//part.selected = true;
|
||||
isMouseDragging = true;
|
||||
draggingObject = part;
|
||||
setSelection(std::vector<InstanceRefWeak> { part });
|
||||
if (evt->modifiers() & Qt::ControlModifier) {
|
||||
std::vector<InstanceRefWeak> currentSelection = getSelection();
|
||||
for (int i = 0; i < currentSelection.size(); i++) {
|
||||
InstanceRefWeak inst = currentSelection[i];
|
||||
if (!inst.expired() && inst.lock() == part) {
|
||||
currentSelection.erase(currentSelection.begin() + i);
|
||||
goto skipAddPart;
|
||||
}
|
||||
}
|
||||
currentSelection.push_back(part);
|
||||
skipAddPart:
|
||||
setSelection(currentSelection);
|
||||
}else
|
||||
setSelection(std::vector<InstanceRefWeak> { part });
|
||||
// Disable bit so that we can ignore the part while raycasting
|
||||
// part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "mainwindow.h"
|
||||
#include "./ui_mainwindow.h"
|
||||
#include "common.h"
|
||||
#include <memory>
|
||||
#include <qclipboard.h>
|
||||
#include <qmessagebox.h>
|
||||
#include <qmimedata.h>
|
||||
|
@ -72,6 +73,113 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
delete menu;
|
||||
});
|
||||
|
||||
connectActionHandlers();
|
||||
|
||||
// Update handles
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
editorToolHandles->adornee = std::nullopt;
|
||||
if (newSelection.size() == 0) return;
|
||||
InstanceRef inst = newSelection[0].lock();
|
||||
if (inst->GetClass() != &Part::TYPE) return;
|
||||
|
||||
editorToolHandles->adornee = std::dynamic_pointer_cast<Part>(inst);
|
||||
});
|
||||
|
||||
// Update properties
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
if (newSelection.size() == 0) return;
|
||||
if (newSelection.size() > 1)
|
||||
ui->propertiesView->setSelected(std::nullopt);
|
||||
ui->propertiesView->setSelected(newSelection[0].lock());
|
||||
});
|
||||
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool __) {
|
||||
for (InstanceRefWeak inst : oldSelection) {
|
||||
if (inst.expired() || inst.lock()->GetClass() != &Part::TYPE) continue;
|
||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst.lock());
|
||||
part->selected = false;
|
||||
}
|
||||
|
||||
for (InstanceRefWeak inst : newSelection) {
|
||||
if (inst.expired() || inst.lock()->GetClass() != &Part::TYPE) continue;
|
||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst.lock());
|
||||
part->selected = true;
|
||||
}
|
||||
});
|
||||
|
||||
// ui->explorerView->Init(ui);
|
||||
|
||||
// Baseplate
|
||||
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0, -5, 0),
|
||||
.rotation = glm::vec3(0),
|
||||
.size = glm::vec3(512, 1.2, 512),
|
||||
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.anchored = true,
|
||||
.locked = true,
|
||||
}));
|
||||
ui->mainWidget->lastPart->name = "Baseplate";
|
||||
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
|
||||
|
||||
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0),
|
||||
.rotation = glm::vec3(0.5, 2, 1),
|
||||
.size = glm::vec3(4, 1.2, 2),
|
||||
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
}));
|
||||
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* evt) {
|
||||
#ifdef NDEBUG
|
||||
// Ask if the user wants to save their changes
|
||||
// https://stackoverflow.com/a/33890731
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Save changes before creating new document?");
|
||||
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
msgBox.setDefaultButton(QMessageBox::Save);
|
||||
int result = msgBox.exec();
|
||||
|
||||
if (result == QMessageBox::Cancel) return evt->ignore();
|
||||
if (result == QMessageBox::Save) {
|
||||
std::optional<std::string> path;
|
||||
if (!gDataModel->HasFile())
|
||||
path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save " + gDataModel->name));
|
||||
if (!path || path == "") return evt->ignore();
|
||||
|
||||
gDataModel->SaveToFile(path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::handleLog(Logger::LogLevel logLevel, std::string message) {
|
||||
if (logLevel == Logger::LogLevel::DEBUG) return;
|
||||
|
||||
if (logLevel == Logger::LogLevel::INFO)
|
||||
ui->outputTextView->appendHtml(QString("<p>%1</p>").arg(QString::fromStdString(message)));
|
||||
if (logLevel == Logger::LogLevel::WARNING)
|
||||
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 127, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
|
||||
if (logLevel == Logger::LogLevel::ERROR || logLevel == Logger::LogLevel::FATAL_ERROR)
|
||||
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 0, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
|
||||
}
|
||||
|
||||
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
||||
void MainWindow::timerEvent(QTimerEvent* evt) {
|
||||
if (evt->timerId() != timer.timerId()) {
|
||||
QWidget::timerEvent(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
float deltaTime = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastTime).count();
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
|
||||
if (simulationPlaying)
|
||||
gWorkspace()->PhysicsStep(deltaTime);
|
||||
ui->mainWidget->update();
|
||||
ui->mainWidget->updateCycle();
|
||||
}
|
||||
|
||||
void MainWindow::connectActionHandlers() {
|
||||
// Explorer View
|
||||
|
||||
ui->explorerView->buildContextMenu();
|
||||
|
@ -166,6 +274,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
.size = glm::vec3(512, 1.2, 512),
|
||||
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.anchored = true,
|
||||
.locked = true,
|
||||
}));
|
||||
ui->mainWidget->lastPart->name = "Baseplate";
|
||||
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
|
||||
|
@ -309,94 +418,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
selectedParent->AddChild(inst.expect());
|
||||
}
|
||||
});
|
||||
|
||||
// Update handles
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
editorToolHandles->adornee = std::nullopt;
|
||||
if (newSelection.size() == 0) return;
|
||||
InstanceRef inst = newSelection[0].lock();
|
||||
if (inst->GetClass() != &Part::TYPE) return;
|
||||
|
||||
editorToolHandles->adornee = std::dynamic_pointer_cast<Part>(inst);
|
||||
});
|
||||
|
||||
// Update properties
|
||||
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
||||
if (newSelection.size() == 0) return;
|
||||
if (newSelection.size() > 1)
|
||||
ui->propertiesView->setSelected(std::nullopt);
|
||||
ui->propertiesView->setSelected(newSelection[0].lock());
|
||||
});
|
||||
|
||||
// ui->explorerView->Init(ui);
|
||||
|
||||
// Baseplate
|
||||
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0, -5, 0),
|
||||
.rotation = glm::vec3(0),
|
||||
.size = glm::vec3(512, 1.2, 512),
|
||||
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
||||
.anchored = true,
|
||||
}));
|
||||
ui->mainWidget->lastPart->name = "Baseplate";
|
||||
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
|
||||
|
||||
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
||||
.position = glm::vec3(0),
|
||||
.rotation = glm::vec3(0.5, 2, 1),
|
||||
.size = glm::vec3(4, 1.2, 2),
|
||||
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
||||
}));
|
||||
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* evt) {
|
||||
#ifdef NDEBUG
|
||||
// Ask if the user wants to save their changes
|
||||
// https://stackoverflow.com/a/33890731
|
||||
QMessageBox msgBox;
|
||||
msgBox.setText("Save changes before creating new document?");
|
||||
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
msgBox.setDefaultButton(QMessageBox::Save);
|
||||
int result = msgBox.exec();
|
||||
|
||||
if (result == QMessageBox::Cancel) return evt->ignore();
|
||||
if (result == QMessageBox::Save) {
|
||||
std::optional<std::string> path;
|
||||
if (!gDataModel->HasFile())
|
||||
path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save " + gDataModel->name));
|
||||
if (!path || path == "") return evt->ignore();
|
||||
|
||||
gDataModel->SaveToFile(path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::handleLog(Logger::LogLevel logLevel, std::string message) {
|
||||
if (logLevel == Logger::LogLevel::DEBUG) return;
|
||||
|
||||
if (logLevel == Logger::LogLevel::INFO)
|
||||
ui->outputTextView->appendHtml(QString("<p>%1</p>").arg(QString::fromStdString(message)));
|
||||
if (logLevel == Logger::LogLevel::WARNING)
|
||||
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 127, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
|
||||
if (logLevel == Logger::LogLevel::ERROR || logLevel == Logger::LogLevel::FATAL_ERROR)
|
||||
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 0, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
|
||||
}
|
||||
|
||||
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
||||
void MainWindow::timerEvent(QTimerEvent* evt) {
|
||||
if (evt->timerId() != timer.timerId()) {
|
||||
QWidget::timerEvent(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
float deltaTime = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastTime).count();
|
||||
lastTime = std::chrono::steady_clock::now();
|
||||
|
||||
if (simulationPlaying)
|
||||
gWorkspace()->PhysicsStep(deltaTime);
|
||||
ui->mainWidget->update();
|
||||
ui->mainWidget->updateCycle();
|
||||
}
|
||||
|
||||
void MainWindow::updateToolbars() {
|
||||
|
|
|
@ -54,6 +54,8 @@ private:
|
|||
void timerEvent(QTimerEvent*) override;
|
||||
void closeEvent(QCloseEvent* evt) override;
|
||||
void handleLog(Logger::LogLevel, std::string);
|
||||
|
||||
void connectActionHandlers();
|
||||
|
||||
std::optional<std::string> openFileDialog(QString filter, QString defaultExtension, QFileDialog::AcceptMode acceptMode, QString title = "");
|
||||
};
|
||||
|
|
|
@ -31,12 +31,10 @@ ExplorerView::ExplorerView(QWidget* parent):
|
|||
|
||||
connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
||||
std::vector<InstanceRefWeak> selectedInstances;
|
||||
selectedInstances.reserve(selected.count()); // This doesn't reserve everything, but should enhance things anyway
|
||||
selectedInstances.reserve(selectedIndexes().count()); // This doesn't reserve everything, but should enhance things anyway
|
||||
|
||||
for (auto range : selected) {
|
||||
for (auto index : range.indexes()) {
|
||||
selectedInstances.push_back(reinterpret_cast<Instance*>(index.internalPointer())->weak_from_this());
|
||||
}
|
||||
for (auto index : selectedIndexes()) {
|
||||
selectedInstances.push_back(reinterpret_cast<Instance*>(index.internalPointer())->weak_from_this());
|
||||
}
|
||||
|
||||
::setSelection(selectedInstances, true);
|
||||
|
|
Loading…
Add table
Reference in a new issue