From: Jakob Haufe Date: Mon, 29 Sep 2025 09:04:04 +0000 (+0200) Subject: New upstream version 0.11.1 X-Git-Tag: upstream/0.11.1^0 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=42f401f68291f6e547fd276e8084200f18b7f12a;p=fstl New upstream version 0.11.1 --- diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..6aec0ae --- /dev/null +++ b/.clang-format @@ -0,0 +1,21 @@ +# see https://clang.llvm.org/docs/ClangFormatStyleOptions.html +--- +BasedOnStyle: LLVM +Language: Cpp +Standard: Cpp11 + +ColumnLimit: 135 + +AccessModifierOffset: -4 +IndentWidth: 4 +UseTab: Never + +BreakBeforeBraces: Linux +AlignEscapedNewlines: Left +AllowShortFunctionsOnASingleLine: Empty +AllowShortLambdasOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: true +BreakConstructorInitializers: AfterColon +ConstructorInitializerAllOnOneLineOrOnePerLine: true +IndentPPDirectives: AfterHash +PointerAlignment: Left \ No newline at end of file diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..41391f4 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,45 @@ +name: Build + +on: + push: + branches: [main, master] + pull_request: + branches: [main, master] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + compiler: [gcc, clang] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y qt5-qmake qtbase5-dev build-essential clang clang-format + + - name: Set compiler + run: | + if [ "${{ matrix.compiler }}" = "clang" ]; then + export CC=clang + export CXX=clang++ + else + export CC=gcc + export CXX=g++ + fi + echo "CC=$CC" >> $GITHUB_ENV + echo "CXX=$CXX" >> $GITHUB_ENV + + - name: Build + run: | + cmake -S . -B build -DFSTL_CHECK_FORMAT=ON + cmake --build build --target fstl --config Release -- -j$(nproc) + + - name: Check format + run: | + # Print the version for troubleshooting purposes + clang-format --version + cmake --build build --target check-format diff --git a/CMakeLists.txt b/CMakeLists.txt index fe586c7..2fbea66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,19 +2,55 @@ # Original Project Author: Matt Keeter Copyright 2014-2024 # Author: Paul Tsouchlos Copyright 2017-2024 -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.10) project(fstl) -# Setting -std=c++11 -set(CMAKE_CXX_STANDARD 11) -# Setting standard to required, as requisted by DeveloperPaul123 on github +# Setting -std=c++14 +set(CMAKE_CXX_STANDARD 14) set(CXX_STANDARD_REQUIRED ON) +option(FSTL_CHECK_FORMAT "Check source code formatting with clang-format" OFF) +if(FSTL_CHECK_FORMAT) + find_program(CLANG_FORMAT_EXE NAMES clang-format) + if(NOT CLANG_FORMAT_EXE) + message(FATAL_ERROR "Could not find clang-format executable!") + endif() + + file(GLOB_RECURSE ALL_SOURCE_FILES CONFIGURE_DEPENDS + src/*.h + src/*.cpp + qt/*.h + qt/*.cpp + gl/*.h + gl/*.cpp + exe/*.h + exe/*.cpp + ) + + add_custom_target(check-format + COMMAND ${CLANG_FORMAT_EXE} + --Werror + --style=file + --dry-run + ${ALL_SOURCE_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Checking source code formatting" + VERBATIM) + add_custom_target(fix-format + COMMAND ${CLANG_FORMAT_EXE} + --style=file + -i + ${ALL_SOURCE_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Fixing source code formatting" + VERBATIM) +endif() + # Set the version number set (FSTL_VERSION_MAJOR "0") set (FSTL_VERSION_MINOR "11") -set (FSTL_VERSION_PATCH "0") +set (FSTL_VERSION_PATCH "1") set (PROJECT_VERSION "${FSTL_VERSION_MAJOR}.${FSTL_VERSION_MINOR}.${FSTL_VERSION_PATCH}") message(STATUS "Version: ${PROJECT_VERSION}") @@ -54,7 +90,7 @@ set(Icon_Resource exe/fstl.rc) set(OpenGL_GL_PREFERENCE GLVND) #find required packages. -find_package(Qt5 5.14 REQUIRED COMPONENTS Core Gui Widgets OpenGL) +find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets OpenGL) find_package(OpenGL REQUIRED) find_package(Threads REQUIRED) diff --git a/src/app.cpp b/src/app.cpp index 07de99e..09799a6 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,22 +1,20 @@ #include -#include #include +#include #include "app.h" #include "window.h" -App::App(int& argc, char *argv[]) : - QApplication(argc, argv), window(new Window()) +App::App(int& argc, char* argv[]) : QApplication(argc, argv), window(new Window()) { if (argc > 1) { - QString filename = argv[1]; + const auto args = QCoreApplication::arguments(); + QString filename = args.at(1); if (filename.startsWith("~")) { filename.replace(0, 1, QDir::homePath()); } window->load_stl(filename); - } - else - { + } else { window->load_stl(":gl/sphere.stl"); } window->show(); @@ -29,13 +27,10 @@ App::~App() bool App::event(QEvent* e) { - if (e->type() == QEvent::FileOpen) - { + if (e->type() == QEvent::FileOpen) { window->load_stl(static_cast(e)->file()); return true; - } - else - { + } else { return QApplication::event(e); } } diff --git a/src/app.h b/src/app.h index 6afb4d7..876e3d5 100644 --- a/src/app.h +++ b/src/app.h @@ -9,13 +9,14 @@ class App : public QApplication { Q_OBJECT public: - explicit App(int& argc, char *argv[]); - ~App(); + explicit App(int& argc, char* argv[]); + ~App(); + protected: bool event(QEvent* e) override; + private: Window* const window; - }; #endif // APP_H diff --git a/src/axis.cpp b/src/axis.cpp index 831f592..ae0a312 100644 --- a/src/axis.cpp +++ b/src/axis.cpp @@ -1,27 +1,8 @@ #include "axis.h" -const float xLet[] = { - -0.1, -0.2, 0, - 0.1, 0.2, 0, - 0.1, -0.2, 0, - -0.1, 0.2, 0 -}; -const float yLet[] = { - 0, -0.2, 0, - 0, 0, 0, - 0, 0, 0, - 0.1, 0.2, 0, - 0, 0, 0, - -0.1, 0.2, 0 -}; -const float zLet[] = { - -0.1, -0.2, 0, - 0.1, -0.2, 0, - 0.1, -0.2, 0, - -0.1, 0.2, 0, - -0.1, 0.2, 0, - 0.1, 0.2, 0 -}; +const float xLet[] = {-0.1, -0.2, 0, 0.1, 0.2, 0, 0.1, -0.2, 0, -0.1, 0.2, 0}; +const float yLet[] = {0, -0.2, 0, 0, 0, 0, 0, 0, 0, 0.1, 0.2, 0, 0, 0, 0, -0.1, 0.2, 0}; +const float zLet[] = {-0.1, -0.2, 0, 0.1, -0.2, 0, 0.1, -0.2, 0, -0.1, 0.2, 0, -0.1, 0.2, 0, 0.1, 0.2, 0}; const int axisSegCount[] = {2, 3, 3}; const float* axisLabels[] = {xLet, yLet, zLet}; @@ -32,38 +13,35 @@ Axis::Axis() shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/gl/colored_lines.vert"); shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/colored_lines.frag"); shader.link(); - const int ptSize = 6*sizeof(float); - for(int lIdx = 0; lIdx < 3; lIdx++) - { + const int ptSize = 6 * sizeof(float); + for (int lIdx = 0; lIdx < 3; lIdx++) { const float* l = axisLabels[lIdx]; - const int ptCount = axisSegCount[lIdx]*2; + const int ptCount = axisSegCount[lIdx] * 2; float c[3] = {0.0}; - c[lIdx] = 1.0;//set color + c[lIdx] = 1.0; // set color QOpenGLBuffer b = flowerLabelVertices[lIdx]; b.create(); b.bind(); - b.allocate(ptCount*ptSize); - for(int pIdx = 0; pIdx < ptCount; pIdx++) - { - b.write(pIdx*ptSize, &(l[pIdx*3]), ptSize/2);//write coords - b.write(pIdx*ptSize + ptSize/2, c, ptSize/2);//write color + b.allocate(ptCount * ptSize); + for (int pIdx = 0; pIdx < ptCount; pIdx++) { + b.write(pIdx * ptSize, &(l[pIdx * 3]), ptSize / 2); // write coords + b.write(pIdx * ptSize + ptSize / 2, c, ptSize / 2); // write color } b.release(); } - //Axis buffer: 6 floats per vertex, 2 vert per line, 3 lines - float aBuf[6*2*3] = {0.0}; - for(int aIdx = 0; aIdx < 3; aIdx++) - { - aBuf[(2*aIdx)*6+3+aIdx] = 1.0;//Set color (last 3 floats) - aBuf[(2*aIdx+1)*6+3+aIdx] = 1.0;//Set color (last 3 floats) - aBuf[(2*aIdx+1)*6+aIdx] = 1.0;//Extend line in axis + // Axis buffer: 6 floats per vertex, 2 vert per line, 3 lines + float aBuf[6 * 2 * 3] = {0.0}; + for (int aIdx = 0; aIdx < 3; aIdx++) { + aBuf[(2 * aIdx) * 6 + 3 + aIdx] = 1.0; // Set color (last 3 floats) + aBuf[(2 * aIdx + 1) * 6 + 3 + aIdx] = 1.0; // Set color (last 3 floats) + aBuf[(2 * aIdx + 1) * 6 + aIdx] = 1.0; // Extend line in axis } - //The lines which form the 'axis-flower' in the corner + // The lines which form the 'axis-flower' in the corner flowerAxisVertices.create(); flowerAxisVertices.bind(); flowerAxisVertices.allocate(aBuf, sizeof(aBuf)); flowerAxisVertices.release(); - //The lines which form the model-space axes + // The lines which form the model-space axes vertices.create(); vertices.bind(); vertices.allocate(aBuf, sizeof(aBuf)); @@ -71,92 +49,77 @@ Axis::Axis() } void Axis::setScale(QVector3D min, QVector3D max) { - //Max function. not worth importing just for max - auto Max = [](float a, float b) - { + // Max function. not worth importing just for max + auto Max = [](float a, float b) { return (a > b) ? a : b; }; - //This is how much the axes extend beyond the model - //We want it to be dependent on the model's size, but uniform on all axes. - const float axismargin = 0.25*Max(Max(max[0]-min[0], max[1]-min[1]), max[2]-min[2]); + // This is how much the axes extend beyond the model + // We want it to be dependent on the model's size, but uniform on all axes. + const float axismargin = 0.25 * Max(Max(max[0] - min[0], max[1] - min[1]), max[2] - min[2]); vertices.bind(); - //Manually rewrite coordinates to control axis draw lengths + // Manually rewrite coordinates to control axis draw lengths float s = sizeof(float); - //aIdx*12+aIdx gets us to the set of 2 points of the axis line, plus the offset for that dimension + // aIdx*12+aIdx gets us to the set of 2 points of the axis line, plus the offset for that dimension //+6 gets us to the other end of the line in that dimension - for(int aIdx = 0; aIdx < 3; aIdx++) - { - float t = min[aIdx]-axismargin; - vertices.write(s*(aIdx*12+aIdx), &t, s); - t = max[aIdx]+axismargin; - vertices.write(s*(aIdx*12+aIdx+6), &t, s); + for (int aIdx = 0; aIdx < 3; aIdx++) { + float t = min[aIdx] - axismargin; + vertices.write(s * (aIdx * 12 + aIdx), &t, s); + t = max[aIdx] + axismargin; + vertices.write(s * (aIdx * 12 + aIdx + 6), &t, s); } vertices.release(); } -void Axis::draw(QMatrix4x4 transMat, QMatrix4x4 viewMat, - QMatrix4x4 orientMat, QMatrix4x4 aspectMat, float aspectRatio) +void Axis::draw(QMatrix4x4 transMat, QMatrix4x4 viewMat, QMatrix4x4 orientMat, QMatrix4x4 aspectMat, float aspectRatio) { shader.bind(); vertices.bind(); // Load the transform and view matrices into the shader - auto loadMatrixUniforms = [&](QMatrix4x4 transform, QMatrix4x4 view) - { - glUniformMatrix4fv( - shader.uniformLocation("transform_matrix"), - 1, GL_FALSE, transform.data()); - glUniformMatrix4fv( - shader.uniformLocation("view_matrix"), - 1, GL_FALSE, view.data()); + auto loadMatrixUniforms = [&](QMatrix4x4 transform, QMatrix4x4 view) { + glUniformMatrix4fv(shader.uniformLocation("transform_matrix"), 1, GL_FALSE, transform.data()); + glUniformMatrix4fv(shader.uniformLocation("view_matrix"), 1, GL_FALSE, view.data()); }; const GLuint vp = shader.attributeLocation("vertex_position"); const GLuint vc = shader.attributeLocation("vertex_color"); glEnableVertexAttribArray(vp); glEnableVertexAttribArray(vc); - auto loadAttribPtr = [&]() - { - glVertexAttribPointer(vp, 3, GL_FLOAT, false, - 6 * sizeof(GLfloat), 0); - glVertexAttribPointer(vc, 3, GL_FLOAT, false, - 6 * sizeof(GLfloat), - (GLvoid*)(3 * sizeof(GLfloat))); + auto loadAttribPtr = [&]() { + glVertexAttribPointer(vp, 3, GL_FLOAT, false, 6 * sizeof(GLfloat), 0); + glVertexAttribPointer(vc, 3, GL_FLOAT, false, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); }; loadMatrixUniforms(transMat, viewMat); loadAttribPtr(); - glDrawArrays(GL_LINES, 0, 3*6); + glDrawArrays(GL_LINES, 0, 3 * 6); vertices.release(); - //Next, we draw the hud axis-flower + // Next, we draw the hud axis-flower flowerAxisVertices.bind(); - glClear(GL_DEPTH_BUFFER_BIT);//Ensure hud draws over everything + glClear(GL_DEPTH_BUFFER_BIT); // Ensure hud draws over everything const float hudSize = 0.2; QMatrix4x4 hudMat; - //Move the hud to the bottom left corner with margin - if (aspectRatio > 1.0) - { - hudMat.translate(aspectRatio-2*hudSize, -1.0+2*hudSize, 0); + // Move the hud to the bottom left corner with margin + if (aspectRatio > 1.0) { + hudMat.translate(aspectRatio - 2 * hudSize, -1.0 + 2 * hudSize, 0); + } else { + hudMat.translate(1.0 - 2 * hudSize, -1.0 / aspectRatio + 2 * hudSize, 0); } - else - { - hudMat.translate(1.0-2*hudSize, -1.0/aspectRatio+2*hudSize, 0); - } - //Scale the hud to be small + // Scale the hud to be small hudMat.scale(hudSize, hudSize, 1); - loadMatrixUniforms(orientMat, aspectMat*hudMat); + loadMatrixUniforms(orientMat, aspectMat * hudMat); loadAttribPtr(); - glDrawArrays(GL_LINES, 0, 3*6); + glDrawArrays(GL_LINES, 0, 3 * 6); flowerAxisVertices.release(); - for(int aIdx = 0; aIdx < 3; aIdx++){ + for (int aIdx = 0; aIdx < 3; aIdx++) { QVector3D transVec = QVector3D(); - transVec[aIdx] = 1.25;//This is how far we want the letters to be extended out + transVec[aIdx] = 1.25; // This is how far we want the letters to be extended out QOpenGLBuffer b = flowerLabelVertices[aIdx]; - //The only transform we want is to translate the letters to the ends of the axis lines + // The only transform we want is to translate the letters to the ends of the axis lines QMatrix4x4 labelTransMat = QMatrix4x4(); labelTransMat.translate(orientMat * transVec); b.bind(); loadMatrixUniforms(labelTransMat, aspectMat * hudMat); loadAttribPtr(); - glDrawArrays(GL_LINES, 0, axisSegCount[aIdx]*2*6); + glDrawArrays(GL_LINES, 0, axisSegCount[aIdx] * 2 * 6); b.release(); } shader.release(); diff --git a/src/axis.h b/src/axis.h index 7d0a991..f7baba0 100644 --- a/src/axis.h +++ b/src/axis.h @@ -2,21 +2,21 @@ #define AXIS_H #include -#include #include +#include class Axis : protected QOpenGLFunctions { public: Axis(); void setScale(QVector3D min, QVector3D max); - void draw(QMatrix4x4 transMat, QMatrix4x4 viewMat, - QMatrix4x4 orientMat, QMatrix4x4 aspectMat, float aspectRatio); + void draw(QMatrix4x4 transMat, QMatrix4x4 viewMat, QMatrix4x4 orientMat, QMatrix4x4 aspectMat, float aspectRatio); + private: QOpenGLShaderProgram shader; - QOpenGLBuffer vertices, //GL Buffer for model-space coords - flowerAxisVertices; //GL Buffer for hud-space axis lines - QOpenGLBuffer flowerLabelVertices[3];//Buffer for hud-space label lines + QOpenGLBuffer vertices, // GL Buffer for model-space coords + flowerAxisVertices; // GL Buffer for hud-space axis lines + QOpenGLBuffer flowerLabelVertices[3]; // Buffer for hud-space label lines }; #endif // AXIS_H diff --git a/src/backdrop.cpp b/src/backdrop.cpp index 4ef1bba..2100ea8 100644 --- a/src/backdrop.cpp +++ b/src/backdrop.cpp @@ -8,11 +8,7 @@ Backdrop::Backdrop() shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/quad.frag"); shader.link(); - float vbuf[] = { - -1, -1, 0.00, 0.10, 0.15, - -1, 1, 0.03, 0.21, 0.26, - 1, -1, 0.00, 0.12, 0.18, - 1, 1, 0.06, 0.26, 0.30}; + float vbuf[] = {-1, -1, 0.00, 0.10, 0.15, -1, 1, 0.03, 0.21, 0.26, 1, -1, 0.00, 0.12, 0.18, 1, 1, 0.06, 0.26, 0.30}; vertices.create(); vertices.bind(); @@ -31,11 +27,8 @@ void Backdrop::draw() glEnableVertexAttribArray(vp); glEnableVertexAttribArray(vc); - glVertexAttribPointer(vp, 2, GL_FLOAT, false, - 5 * sizeof(GLfloat), 0); - glVertexAttribPointer(vc, 3, GL_FLOAT, false, - 5 * sizeof(GLfloat), - (GLvoid*)(2 * sizeof(GLfloat))); + glVertexAttribPointer(vp, 2, GL_FLOAT, false, 5 * sizeof(GLfloat), 0); + glVertexAttribPointer(vc, 3, GL_FLOAT, false, 5 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat))); glDrawArrays(GL_TRIANGLE_STRIP, 0, 8); diff --git a/src/backdrop.h b/src/backdrop.h index 95ae48b..5709993 100644 --- a/src/backdrop.h +++ b/src/backdrop.h @@ -2,14 +2,15 @@ #define BACKDROP_H #include -#include #include +#include class Backdrop : protected QOpenGLFunctions { public: Backdrop(); void draw(); + private: QOpenGLShaderProgram shader; QOpenGLBuffer vertices; diff --git a/src/canvas.cpp b/src/canvas.cpp index ad4ec37..eed3671 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -2,9 +2,9 @@ #include -#include "canvas.h" -#include "backdrop.h" #include "axis.h" +#include "backdrop.h" +#include "canvas.h" #include "glmesh.h" #include "mesh.h" @@ -17,30 +17,42 @@ const QString Canvas::DIRECTIVE_COLOR = "directiveColor"; const QString Canvas::DIRECTIVE_FACTOR = "directiveFactor"; const QString Canvas::CURRENT_LIGHT_DIRECTION = "currentLightDirection"; -const QColor Canvas::defaultAmbientColor = QColor::fromRgbF(0.22,0.8,1.0); -const QColor Canvas::defaultDirectiveColor = QColor(255,255,255); +const QColor Canvas::defaultAmbientColor = QColor::fromRgbF(0.22, 0.8, 1.0); +const QColor Canvas::defaultDirectiveColor = QColor(255, 255, 255); const float Canvas::defaultAmbientFactor = 0.67; const float Canvas::defaultDirectiveFactor = 0.5; const int Canvas::defaultCurrentLightDirection = 1; -Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent) - : QOpenGLWidget(parent), mesh(nullptr), - scale(1), zoom(1), - anim(this, "perspective"), status(" "), - meshInfo("") +namespace +{ +/** + * Abstract differences between accessing QWheelEvent position data for different versions of Qt. + */ +auto position(const QWheelEvent* const event) +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + return event->pos(); +#else + return event->position(); +#endif +} +} // namespace + +Canvas::Canvas(const QSurfaceFormat& format, QWidget* parent) : + QOpenGLWidget(parent), mesh(nullptr), scale(1), zoom(1), anim(this, "perspective"), status(" "), meshInfo("") { setFormat(format); QFile styleFile(":/qt/style.qss"); - styleFile.open( QFile::ReadOnly ); + styleFile.open(QFile::ReadOnly); setStyleSheet(styleFile.readAll()); currentTransform = QMatrix4x4(); resetTransform(); QSettings settings; - ambientColor = settings.value(AMBIENT_COLOR,defaultAmbientColor).value(); - directiveColor = settings.value(DIRECTIVE_COLOR,defaultDirectiveColor).value(); - ambientFactor = settings.value(AMBIENT_FACTOR,defaultAmbientFactor).value(); - directiveFactor = settings.value(DIRECTIVE_FACTOR,defaultDirectiveFactor).value(); + ambientColor = settings.value(AMBIENT_COLOR, defaultAmbientColor).value(); + directiveColor = settings.value(DIRECTIVE_COLOR, defaultDirectiveColor).value(); + ambientFactor = settings.value(AMBIENT_FACTOR, defaultAmbientFactor).value(); + directiveFactor = settings.value(DIRECTIVE_FACTOR, defaultDirectiveFactor).value(); // Fill direction list // Fill in directions @@ -50,18 +62,18 @@ Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent) xname << "right " << " " << "left "; yname << "top " << " " << "bottom "; zname << "rear " << " " << "front "; - for (int i=-1; i<2 ; i++) { - for (int j=-1; j<2; j++) { - for (int k=-1; k<2; k++) { - QString current = xname.at(i+1) + yname.at(j+1) + zname.at(k+1); - if (!(i==0 && j==0 && k==0)) { + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + for (int k = -1; k < 2; k++) { + QString current = xname.at(i + 1) + yname.at(j + 1) + zname.at(k + 1); + if (!(i == 0 && j == 0 && k == 0)) { nameDir << current.simplified(); - listDir << QVector3D((double)i,(double)j,(double)k); + listDir << QVector3D((double)i, (double)j, (double)k); } } } } - currentLightDirection = settings.value(CURRENT_LIGHT_DIRECTION,defaultCurrentLightDirection).value(); + currentLightDirection = settings.value(CURRENT_LIGHT_DIRECTION, defaultCurrentLightDirection).value(); if (currentLightDirection < 0 || currentLightDirection >= nameDir.length()) { currentLightDirection = defaultCurrentLightDirection; } @@ -99,44 +111,32 @@ void Canvas::common_view_change(enum ViewPoint c) currentTransform.setToIdentity(); currentTransform.rotate(180.0, QVector3D(0, 0, 1)); - switch (c) - { - case isoview: - { - currentTransform.rotate(90, QVector3D(1, 0, 0)); - currentTransform.rotate(-45, QVector3D(0, 0, 1)); - currentTransform.rotate(35.264, QVector3D(1, 1, 0)); - } - break; - case topview: - { - currentTransform.rotate(180, QVector3D(1, 0, 0)); - } - break; - case leftview: - { - currentTransform.rotate(180, QVector3D(1, 0, 0)); - currentTransform.rotate(90, QVector3D(0, 0, 1)); - currentTransform.rotate(90, QVector3D(0, 1, 0)); - } - break; - case rightview: - { - currentTransform.rotate(180, QVector3D(1, 0, 0)); - currentTransform.rotate(-90.0, QVector3D(0, 1, 0)); - currentTransform.rotate(-90, QVector3D(1, 0, 0)); - } - break; - case frontview: - { - currentTransform.rotate(90, QVector3D(1, 0, 0)); - } - break; - case backview: - { - currentTransform.rotate(90, QVector3D(1, 0, 0)); - currentTransform.rotate(180, QVector3D(0, 0, 1)); - } + switch (c) { + case isoview: { + currentTransform.rotate(90, QVector3D(1, 0, 0)); + currentTransform.rotate(-45, QVector3D(0, 0, 1)); + currentTransform.rotate(35.264, QVector3D(1, 1, 0)); + } break; + case topview: { + currentTransform.rotate(180, QVector3D(1, 0, 0)); + } break; + case leftview: { + currentTransform.rotate(180, QVector3D(1, 0, 0)); + currentTransform.rotate(90, QVector3D(0, 0, 1)); + currentTransform.rotate(90, QVector3D(0, 1, 0)); + } break; + case rightview: { + currentTransform.rotate(180, QVector3D(1, 0, 0)); + currentTransform.rotate(-90.0, QVector3D(0, 1, 0)); + currentTransform.rotate(-90, QVector3D(1, 0, 0)); + } break; + case frontview: { + currentTransform.rotate(90, QVector3D(1, 0, 0)); + } break; + case backview: { + currentTransform.rotate(90, QVector3D(1, 0, 0)); + currentTransform.rotate(180, QVector3D(0, 0, 1)); + } case bottomview: [[fallthrough]]; default: @@ -145,13 +145,11 @@ void Canvas::common_view_change(enum ViewPoint c) update(); } -void Canvas::view_perspective(float p, bool animate){ - if(animate) - { +void Canvas::view_perspective(float p, bool animate) +{ + if (animate) { view_anim(p); - } - else - { + } else { set_perspective(p); } } @@ -168,17 +166,19 @@ void Canvas::invert_zoom(bool d) update(); } -void Canvas::setResetTransformOnLoad(bool d) { +void Canvas::setResetTransformOnLoad(bool d) +{ resetTransformOnLoad = d; } -void Canvas::resetTransform() { +void Canvas::resetTransform() +{ currentTransform.setToIdentity(); // apply some rotations to define initial orientation currentTransform.rotate(-90.0, QVector3D(1, 0, 0)); currentTransform.rotate(180.0 + 15.0, QVector3D(0, 0, 1)); - currentTransform.rotate(15.0, QVector3D(1, -sin(M_PI/12), 0)); - + currentTransform.rotate(15.0, QVector3D(1, -sin(M_PI / 12), 0)); + zoom = 1; } @@ -188,8 +188,7 @@ void Canvas::load_mesh(Mesh* m, bool is_reload) mesh = new GLMesh(m); QVector3D lower(m->xmin(), m->ymin(), m->zmin()); QVector3D upper(m->xmax(), m->ymax(), m->zmax()); - if (!is_reload) - { + if (!is_reload) { default_center = center = (lower + upper) / 2; default_scale = scale = 2 / (upper - lower).length(); @@ -200,14 +199,15 @@ void Canvas::load_mesh(Mesh* m, bool is_reload) } } meshInfo = QStringLiteral("Triangles: %1\nX: [%2, %3]\nY: [%4, %5]\nZ: [%6, %7]").arg(m->triCount()); - for(int dIdx = 0; dIdx < 3; dIdx++) meshInfo = meshInfo.arg(lower[dIdx]).arg(upper[dIdx]); + for (int dIdx = 0; dIdx < 3; dIdx++) + meshInfo = meshInfo.arg(lower[dIdx]).arg(upper[dIdx]); axis->setScale(lower, upper); update(); delete m; } -void Canvas::set_status(const QString &s) +void Canvas::set_status(const QString& s) { status = s; update(); @@ -254,44 +254,37 @@ void Canvas::initializeGL() axis = new Axis(); } - void Canvas::paintGL() { glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); backdrop->draw(); - if (mesh) draw_mesh(); - if (drawAxes) axis->draw(transform_matrix(), view_matrix(), - orient_matrix(), aspect_matrix(), width() / float(height())); + if (mesh) + draw_mesh(); + if (drawAxes) + axis->draw(transform_matrix(), view_matrix(), orient_matrix(), aspect_matrix(), width() / float(height())); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); float textHeight = painter.fontInfo().pointSize(); - if (drawAxes) painter.drawText(QRect(10, textHeight, width(), height()), meshInfo); + if (drawAxes) + painter.drawText(QRect(10, textHeight, width(), height()), meshInfo); painter.drawText(10, height() - textHeight, status); } void Canvas::draw_mesh() { QOpenGLShaderProgram* selected_mesh_shader = NULL; - if(drawMode == wireframe) - { + if (drawMode == wireframe) { selected_mesh_shader = &mesh_wireframe_shader; glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } - else - { - if(drawMode == shaded) - { + } else { + if (drawMode == shaded) { selected_mesh_shader = &mesh_shader; - } - else if (drawMode == surfaceangle) - { + } else if (drawMode == surfaceangle) { selected_mesh_shader = &mesh_surfaceangle_shader; - } - else if (drawMode == meshlight) - { + } else if (drawMode == meshlight) { selected_mesh_shader = &mesh_meshlight_shader; } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -300,24 +293,22 @@ void Canvas::draw_mesh() selected_mesh_shader->bind(); // Load the transform and view matrices into the shader - glUniformMatrix4fv( - selected_mesh_shader->uniformLocation("transform_matrix"), - 1, GL_FALSE, transform_matrix().data()); - glUniformMatrix4fv( - selected_mesh_shader->uniformLocation("view_matrix"), - 1, GL_FALSE, view_matrix().data()); + glUniformMatrix4fv(selected_mesh_shader->uniformLocation("transform_matrix"), 1, GL_FALSE, transform_matrix().data()); + glUniformMatrix4fv(selected_mesh_shader->uniformLocation("view_matrix"), 1, GL_FALSE, view_matrix().data()); // Compensate for z-flattening when zooming - glUniform1f(selected_mesh_shader->uniformLocation("zoom"), 1/zoom); + glUniform1f(selected_mesh_shader->uniformLocation("zoom"), 1 / zoom); // specific meshlight arguments if (drawMode == meshlight) { // Ambient Light Color, followed by the ambient light coefficient to use - //glUniform4f(selected_mesh_shader->uniformLocation("ambient_light_color"),0.22f, 0.8f, 1.0f, 0.67f); - glUniform4f(selected_mesh_shader->uniformLocation("ambient_light_color"),ambientColor.redF(), ambientColor.greenF(), ambientColor.blueF(), ambientFactor); + // glUniform4f(selected_mesh_shader->uniformLocation("ambient_light_color"),0.22f, 0.8f, 1.0f, 0.67f); + glUniform4f(selected_mesh_shader->uniformLocation("ambient_light_color"), ambientColor.redF(), ambientColor.greenF(), + ambientColor.blueF(), ambientFactor); // Directive Light Color, followed by the directive light coefficient to use - //glUniform4f(selected_mesh_shader->uniformLocation("directive_light_color"),1.0f,1.0f,1.0f,0.5f); - glUniform4f(selected_mesh_shader->uniformLocation("directive_light_color"),directiveColor.redF(),directiveColor.greenF(),directiveColor.blueF(),directiveFactor); + // glUniform4f(selected_mesh_shader->uniformLocation("directive_light_color"),1.0f,1.0f,1.0f,0.5f); + glUniform4f(selected_mesh_shader->uniformLocation("directive_light_color"), directiveColor.redF(), directiveColor.greenF(), + directiveColor.blueF(), directiveFactor); // Directive Light Direction // dir 1,0,0 Light from the left @@ -328,8 +319,9 @@ void Canvas::draw_mesh() // dir 0,0,-1 Light from behind // // -1,-1,0 Light from top right - //glUniform3f(selected_mesh_shader->uniformLocation("directive_light_direction"),-1.0f,-1.0f,0.0f); - glUniform3f(selected_mesh_shader->uniformLocation("directive_light_direction"),listDir.at(currentLightDirection).x(), listDir.at(currentLightDirection).y(), listDir.at(currentLightDirection).z()); + // glUniform3f(selected_mesh_shader->uniformLocation("directive_light_direction"),-1.0f,-1.0f,0.0f); + glUniform3f(selected_mesh_shader->uniformLocation("directive_light_direction"), listDir.at(currentLightDirection).x(), + listDir.at(currentLightDirection).y(), listDir.at(currentLightDirection).z()); } // Find and enable the attribute location for vertex position @@ -361,12 +353,9 @@ QMatrix4x4 Canvas::transform_matrix() const QMatrix4x4 Canvas::aspect_matrix() const { QMatrix4x4 m; - if (width() > height()) - { + if (width() > height()) { m.scale(-height() / float(width()), 1, 0.5); - } - else - { + } else { m.scale(-1, width() / float(height()), 0.5); } return m; @@ -381,9 +370,7 @@ QMatrix4x4 Canvas::view_matrix() const void Canvas::mousePressEvent(QMouseEvent* event) { - if (event->button() == Qt::LeftButton || - event->button() == Qt::RightButton) - { + if (event->button() == Qt::LeftButton || event->button() == Qt::RightButton) { mouse_pos = event->pos(); setCursor(Qt::ClosedHandCursor); } @@ -391,18 +378,16 @@ void Canvas::mousePressEvent(QMouseEvent* event) void Canvas::mouseReleaseEvent(QMouseEvent* event) { - if (event->button() == Qt::LeftButton || - event->button() == Qt::RightButton) - { + if (event->button() == Qt::LeftButton || event->button() == Qt::RightButton) { unsetCursor(); } } - // This method change the referential of the mouse point coordinates // into a referential x=[-1.0,1.0], y=[-1.0,1.0], with 0,0 being the // center of the widget. -QPointF Canvas::changeMouseCoordinates(QPoint p) { +QPointF Canvas::changeMouseCoordinates(QPoint p) +{ QPointF pr; // Change coordinates double ws2 = this->width() / 2.0; @@ -412,7 +397,8 @@ QPointF Canvas::changeMouseCoordinates(QPoint p) { return pr; } -void Canvas::calcArcballTransform(QPointF p1, QPointF p2) { +void Canvas::calcArcballTransform(QPointF p1, QPointF p2) +{ // Calc z1 & z2 double x1 = p1.x(); double x2 = p2.x(); @@ -446,67 +432,55 @@ void Canvas::calcArcballTransform(QPointF p1, QPointF p2) { QVector3D v1xv2Obj = currentTransform.inverted().mapVector(v1xv2); // calc angle - double angle = acos(std::min(1.0f,QVector3D::dotProduct(v1, v2))) * 180.0 / M_PI; - + double angle = acos(std::min(1.0f, QVector3D::dotProduct(v1, v2))) * 180.0 / M_PI; + // apply transform - currentTransform.rotate(angle,v1xv2Obj); + currentTransform.rotate(angle, v1xv2Obj); } void Canvas::mouseMoveEvent(QMouseEvent* event) { auto p = event->pos(); auto d = p - mouse_pos; - - if (event->buttons() & Qt::LeftButton) - { + if (event->buttons() & Qt::LeftButton) { QPointF p1r = changeMouseCoordinates(mouse_pos); QPointF p2r = changeMouseCoordinates(p); - calcArcballTransform(p1r,p2r); + calcArcballTransform(p1r, p2r); update(); - } - else if (event->buttons() & Qt::RightButton) - { - center = transform_matrix().inverted() * - view_matrix().inverted() * - QVector3D(-d.x() / (0.5*width()), - d.y() / (0.5*height()), 0); + } else if (event->buttons() & Qt::RightButton) { + center = transform_matrix().inverted() * view_matrix().inverted() * + QVector3D(-d.x() / (0.5 * width()), d.y() / (0.5 * height()), 0); update(); } mouse_pos = p; } -void Canvas::wheelEvent(QWheelEvent *event) +void Canvas::wheelEvent(QWheelEvent* event) { // Find GL position before the zoom operation // (to zoom about mouse cursor) - auto p = event->position(); - QVector3D v(1 - p.x() / (0.5*width()), - p.y() / (0.5*height()) - 1, 0); - QVector3D a = transform_matrix().inverted() * - view_matrix().inverted() * v; - - if (event->angleDelta().y() < 0) - { - for (int i=0; i > event->angleDelta().y(); --i) + auto p = position(event); + QVector3D v(1 - p.x() / (0.5 * width()), p.y() / (0.5 * height()) - 1, 0); + QVector3D a = transform_matrix().inverted() * view_matrix().inverted() * v; + + if (event->angleDelta().y() < 0) { + for (int i = 0; i > event->angleDelta().y(); --i) if (invertZoom) zoom /= 1.001; - else + else zoom *= 1.001; - } - else if (event->angleDelta().y() > 0) - { - for (int i=0; i < event->angleDelta().y(); ++i) - if (invertZoom) + } else if (event->angleDelta().y() > 0) { + for (int i = 0; i < event->angleDelta().y(); ++i) + if (invertZoom) zoom *= 1.001; - else + else zoom /= 1.001; } // Then find the cursor's GL position post-zoom and adjust center. - QVector3D b = transform_matrix().inverted() * - view_matrix().inverted() * v; + QVector3D b = transform_matrix().inverted() * view_matrix().inverted() * v; center += b - a; update(); } @@ -516,70 +490,84 @@ void Canvas::resizeGL(int width, int height) glViewport(0, 0, width, height); } -QColor Canvas::getAmbientColor() { +QColor Canvas::getAmbientColor() +{ return ambientColor; } -void Canvas::setAmbientColor(QColor c) { +void Canvas::setAmbientColor(QColor c) +{ ambientColor = c; QSettings settings; - settings.setValue(AMBIENT_COLOR,c); + settings.setValue(AMBIENT_COLOR, c); } -double Canvas::getAmbientFactor() { - return (float) ambientFactor; +double Canvas::getAmbientFactor() +{ + return (float)ambientFactor; } -void Canvas::setAmbientFactor(double f) { - ambientFactor = (float) f; +void Canvas::setAmbientFactor(double f) +{ + ambientFactor = (float)f; QSettings settings; - settings.setValue(AMBIENT_FACTOR,f); + settings.setValue(AMBIENT_FACTOR, f); } -void Canvas::resetAmbientColor() { +void Canvas::resetAmbientColor() +{ setAmbientColor(defaultAmbientColor); setAmbientFactor(defaultAmbientFactor); } -QColor Canvas::getDirectiveColor() { +QColor Canvas::getDirectiveColor() +{ return directiveColor; } -void Canvas::setDirectiveColor(QColor c) { +void Canvas::setDirectiveColor(QColor c) +{ directiveColor = c; QSettings settings; - settings.setValue(DIRECTIVE_COLOR,c); + settings.setValue(DIRECTIVE_COLOR, c); } -double Canvas::getDirectiveFactor() { - return (float) directiveFactor; +double Canvas::getDirectiveFactor() +{ + return (float)directiveFactor; } -void Canvas::setDirectiveFactor(double f) { - directiveFactor = (float) f; +void Canvas::setDirectiveFactor(double f) +{ + directiveFactor = (float)f; QSettings settings; - settings.setValue(DIRECTIVE_FACTOR,f); + settings.setValue(DIRECTIVE_FACTOR, f); } -void Canvas::resetDirectiveColor() { +void Canvas::resetDirectiveColor() +{ setDirectiveColor(defaultDirectiveColor); setDirectiveFactor(defaultDirectiveFactor); } -QList Canvas::getNameDir() { +QList Canvas::getNameDir() +{ return nameDir; } -int Canvas::getCurrentLightDirection() { +int Canvas::getCurrentLightDirection() +{ return currentLightDirection; } -void Canvas::setCurrentLightDirection(int ind) { +void Canvas::setCurrentLightDirection(int ind) +{ currentLightDirection = ind; QSettings settings; - settings.setValue(CURRENT_LIGHT_DIRECTION,currentLightDirection); + settings.setValue(CURRENT_LIGHT_DIRECTION, currentLightDirection); } -void Canvas::resetCurrentLightDirection() { +void Canvas::resetCurrentLightDirection() +{ setCurrentLightDirection(defaultCurrentLightDirection); } diff --git a/src/canvas.h b/src/canvas.h index 8dab30c..692ecc0 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -1,24 +1,24 @@ #ifndef CANVAS_H #define CANVAS_H -#include -#include #include +#include +#include class GLMesh; class Mesh; class Backdrop; class Axis; -enum ViewPoint {centerview, isoview, topview, bottomview, leftview, rightview, frontview, backview}; -enum DrawMode {shaded, wireframe, surfaceangle, meshlight, DRAWMODECOUNT}; +enum ViewPoint { centerview, isoview, topview, bottomview, leftview, rightview, frontview, backview }; +enum DrawMode { shaded, wireframe, surfaceangle, meshlight, DRAWMODECOUNT }; class Canvas : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: - explicit Canvas(const QSurfaceFormat& format, QWidget* parent=0); + explicit Canvas(const QSurfaceFormat& format, QWidget* parent = 0); ~Canvas(); const static float P_PERSPECTIVE; @@ -62,7 +62,7 @@ protected: void mouseReleaseEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void wheelEvent(QWheelEvent* event) override; - + void set_perspective(float p); void view_anim(float v); @@ -102,7 +102,6 @@ private: const static QString DIRECTIVE_FACTOR; const static QString CURRENT_LIGHT_DIRECTION; - GLMesh* mesh; Backdrop* backdrop; Axis* axis; diff --git a/src/glmesh.cpp b/src/glmesh.cpp index 863f558..80afae8 100644 --- a/src/glmesh.cpp +++ b/src/glmesh.cpp @@ -1,8 +1,7 @@ #include "glmesh.h" #include "mesh.h" -GLMesh::GLMesh(const Mesh* const mesh) - : vertices(QOpenGLBuffer::VertexBuffer), indices(QOpenGLBuffer::IndexBuffer) +GLMesh::GLMesh(const Mesh* const mesh) : vertices(QOpenGLBuffer::VertexBuffer), indices(QOpenGLBuffer::IndexBuffer) { initializeOpenGLFunctions(); @@ -13,13 +12,11 @@ GLMesh::GLMesh(const Mesh* const mesh) indices.setUsagePattern(QOpenGLBuffer::StaticDraw); vertices.bind(); - vertices.allocate(mesh->vertices.data(), - mesh->vertices.size() * sizeof(float)); + vertices.allocate(mesh->vertices.data(), mesh->vertices.size() * sizeof(float)); vertices.release(); indices.bind(); - indices.allocate(mesh->indices.data(), - mesh->indices.size() * sizeof(uint32_t)); + indices.allocate(mesh->indices.data(), mesh->indices.size() * sizeof(uint32_t)); indices.release(); } @@ -28,9 +25,8 @@ void GLMesh::draw(GLuint vp) vertices.bind(); indices.bind(); - glVertexAttribPointer(vp, 3, GL_FLOAT, false, 3*sizeof(float), NULL); - glDrawElements(GL_TRIANGLES, indices.size() / sizeof(uint32_t), - GL_UNSIGNED_INT, NULL); + glVertexAttribPointer(vp, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); + glDrawElements(GL_TRIANGLES, indices.size() / sizeof(uint32_t), GL_UNSIGNED_INT, NULL); vertices.release(); indices.release(); diff --git a/src/glmesh.h b/src/glmesh.h index 5c47c2d..aeaa185 100644 --- a/src/glmesh.h +++ b/src/glmesh.h @@ -12,9 +12,10 @@ class GLMesh : protected QOpenGLFunctions public: GLMesh(const Mesh* const mesh); void draw(GLuint vp); + private: - QOpenGLBuffer vertices; - QOpenGLBuffer indices; + QOpenGLBuffer vertices; + QOpenGLBuffer indices; }; #endif // GLMESH_H diff --git a/src/loader.cpp b/src/loader.cpp index 58b81a1..d863b3e 100644 --- a/src/loader.cpp +++ b/src/loader.cpp @@ -3,8 +3,7 @@ #include "loader.h" #include "vertex.h" -Loader::Loader(QObject* parent, const QString& filename, bool is_reload) - : QThread(parent), filename(filename), is_reload(is_reload) +Loader::Loader(QObject* parent, const QString& filename, bool is_reload) : QThread(parent), filename(filename), is_reload(is_reload) { // Nothing to do here } @@ -12,15 +11,11 @@ Loader::Loader(QObject* parent, const QString& filename, bool is_reload) void Loader::run() { Mesh* mesh = load_stl(); - if (mesh) - { - if (mesh->empty()) - { + if (mesh) { + if (mesh->empty()) { emit error_empty_mesh(); delete mesh; - } - else - { + } else { emit got_mesh(mesh, is_reload); emit loaded_file(filename); } @@ -31,21 +26,15 @@ void Loader::run() void parallel_sort(Vertex* begin, Vertex* end, int threads) { - if (threads < 2 || end - begin < 2) - { + if (threads < 2 || end - begin < 2) { std::sort(begin, end); - } - else - { + } else { const auto mid = begin + (end - begin) / 2; - if (threads == 2) - { + if (threads == 2) { auto future = std::async(parallel_sort, begin, mid, threads / 2); std::sort(mid, end); future.wait(); - } - else - { + } else { auto a = std::async(std::launch::async, parallel_sort, begin, mid, threads / 2); auto b = std::async(std::launch::async, parallel_sort, mid, end, threads / 2); a.wait(); @@ -59,16 +48,14 @@ Mesh* mesh_from_verts(uint32_t tri_count, QVector& verts) { // Save indicies as the second element in the array // (so that we can reconstruct triangle order after sorting) - for (size_t i=0; i < tri_count*3; ++i) - { + for (size_t i = 0; i < tri_count * 3; ++i) { verts[i].i = i; } // Check how many threads the hardware can safely support. This may return // 0 if the property can't be read so we shoud check for that too. auto threads = std::thread::hardware_concurrency(); - if (threads == 0) - { + if (threads == 0) { threads = 8; } @@ -76,17 +63,15 @@ Mesh* mesh_from_verts(uint32_t tri_count, QVector& verts) parallel_sort(verts.begin(), verts.end(), threads); // This vector will store triangles as sets of 3 indices - std::vector indices(tri_count*3); + std::vector indices(tri_count * 3); // Go through the sorted vertex list, deduplicating and creating // an indexed geometry representation for the triangles. // Unique vertices are moved so that they occupy the first vertex_count // positions in the verts array. size_t vertex_count = 0; - for (auto v : verts) - { - if (!vertex_count || v != verts[vertex_count-1]) - { + for (auto v : verts) { + if (!vertex_count || v != verts[vertex_count - 1]) { verts[vertex_count++] = v; } indices[v.i] = vertex_count - 1; @@ -94,9 +79,8 @@ Mesh* mesh_from_verts(uint32_t tri_count, QVector& verts) verts.resize(vertex_count); std::vector flat_verts; - flat_verts.reserve(vertex_count*3); - for (auto v : verts) - { + flat_verts.reserve(vertex_count * 3); + for (auto v : verts) { flat_verts.push_back(v.x); flat_verts.push_back(v.y); flat_verts.push_back(v.z); @@ -110,8 +94,7 @@ Mesh* mesh_from_verts(uint32_t tri_count, QVector& verts) Mesh* Loader::load_stl() { QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) - { + if (!file.open(QIODevice::ReadOnly)) { emit error_missing_file(); return NULL; } @@ -122,17 +105,13 @@ Mesh* Loader::load_stl() file_size_old = file_size; QThread::usleep(100000); file_size = file.size(); - } - while(file_size != file_size_old); + } while (file_size != file_size_old); // First, try to read the stl as an ASCII file - if (file.read(5) == "solid") - { + if (file.read(5) == "solid") { file.readLine(); // skip solid name const auto line = file.readLine().trimmed(); - if (line.startsWith("facet") || - line.startsWith("endsolid")) - { + if (line.startsWith("facet") || line.startsWith("endsolid")) { file.seek(0); return read_stl_ascii(file); } @@ -158,14 +137,13 @@ Mesh* Loader::read_stl_binary(QFile& file) data >> tri_count; // Verify that the file is the right size - if (file.size() != 84 + tri_count*50) - { + if (file.size() != 84 + tri_count * 50) { emit error_bad_stl(); return NULL; } // Extract vertices into an array of xyz, unsigned pairs - QVector verts(tri_count*3); + QVector verts(tri_count * 3); // Dummy array, because readRawData is faster than skipRawData std::unique_ptr buffer(new uint8_t[tri_count * 50]); @@ -173,11 +151,9 @@ Mesh* Loader::read_stl_binary(QFile& file) // Store vertices in the array, processing one triangle at a time. auto b = buffer.get() + 3 * sizeof(float); - for (auto v=verts.begin(); v != verts.end(); v += 3) - { + for (auto v = verts.begin(); v != verts.end(); v += 3) { // Load vertex data from .stl file into vertices - for (unsigned i=0; i < 3; ++i) - { + for (unsigned i = 0; i < 3; ++i) { qFromLittleEndian(b, 3, &v[i]); b += 3 * sizeof(float); } @@ -193,28 +169,21 @@ Mesh* Loader::read_stl_ascii(QFile& file) { file.readLine(); uint32_t tri_count = 0; - QVector verts(tri_count*3); + QVector verts(tri_count * 3); bool okay = true; - while (!file.atEnd() && okay) - { + while (!file.atEnd() && okay) { const auto line = file.readLine().simplified(); - if (line.startsWith("endsolid")) - { + if (line.startsWith("endsolid")) { break; - } - else if (!line.startsWith("facet normal") || - !file.readLine().simplified().startsWith("outer loop")) - { + } else if (!line.startsWith("facet normal") || !file.readLine().simplified().startsWith("outer loop")) { okay = false; break; } - for (int i=0; i < 3; ++i) - { + for (int i = 0; i < 3; ++i) { auto line = file.readLine().simplified().split(' '); - if (line[0] != "vertex") - { + if (line[0] != "vertex") { okay = false; break; } @@ -223,23 +192,17 @@ Mesh* Loader::read_stl_ascii(QFile& file) const float z = line[3].toFloat(&okay); verts.push_back(Vertex(x, y, z)); } - if (!file.readLine().trimmed().startsWith("endloop") || - !file.readLine().trimmed().startsWith("endfacet")) - { + if (!file.readLine().trimmed().startsWith("endloop") || !file.readLine().trimmed().startsWith("endfacet")) { okay = false; break; } tri_count++; } - if (okay) - { + if (okay) { return mesh_from_verts(tri_count, verts); - } - else - { + } else { emit error_bad_stl(); return NULL; } } - diff --git a/src/main.cpp b/src/main.cpp index 14561eb..3999846 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ #include "app.h" -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { // Force C locale to force decimal point QLocale::setDefault(QLocale::c()); diff --git a/src/mesh.cpp b/src/mesh.cpp index 2c44a2c..8217f97 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include @@ -8,21 +8,18 @@ //////////////////////////////////////////////////////////////////////////////// -Mesh::Mesh(std::vector&& v, std::vector&& i) - : vertices(std::move(v)), indices(std::move(i)) +Mesh::Mesh(std::vector&& v, std::vector&& i) : vertices(std::move(v)), indices(std::move(i)) { // Nothing to do here } float Mesh::min(size_t start) const { - if (start >= vertices.size()) - { + if (start >= vertices.size()) { return -1; } float v = vertices[start]; - for (size_t i=start; i < vertices.size(); i += 3) - { + for (size_t i = start; i < vertices.size(); i += 3) { v = fmin(v, vertices[i]); } return v; @@ -30,13 +27,11 @@ float Mesh::min(size_t start) const float Mesh::max(size_t start) const { - if (start >= vertices.size()) - { + if (start >= vertices.size()) { return 1; } float v = vertices[start]; - for (size_t i=start; i < vertices.size(); i += 3) - { + for (size_t i = start; i < vertices.size(); i += 3) { v = fmax(v, vertices[i]); } return v; @@ -44,8 +39,9 @@ float Mesh::max(size_t start) const int Mesh::triCount() const { - return indices.size()/3; + return indices.size() / 3; } + bool Mesh::empty() const { return vertices.size() == 0; diff --git a/src/mesh.h b/src/mesh.h index 9e2ab0c..dbde3a2 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -14,12 +14,30 @@ public: float min(size_t start) const; float max(size_t start) const; - float xmin() const { return min(0); } - float ymin() const { return min(1); } - float zmin() const { return min(2); } - float xmax() const { return max(0); } - float ymax() const { return max(1); } - float zmax() const { return max(2); } + float xmin() const + { + return min(0); + } + float ymin() const + { + return min(1); + } + float zmin() const + { + return min(2); + } + float xmax() const + { + return max(0); + } + float ymax() const + { + return max(1); + } + float zmax() const + { + return max(2); + } int triCount() const; bool empty() const; diff --git a/src/shaderlightprefs.cpp b/src/shaderlightprefs.cpp index d00c707..198499b 100644 --- a/src/shaderlightprefs.cpp +++ b/src/shaderlightprefs.cpp @@ -4,7 +4,7 @@ const QString ShaderLightPrefs::PREFS_GEOM = "shaderPrefsGeometry"; -ShaderLightPrefs::ShaderLightPrefs(QWidget *parent, Canvas *_canvas) : QDialog(parent) +ShaderLightPrefs::ShaderLightPrefs(QWidget* parent, Canvas* _canvas) : QDialog(parent) { canvas = _canvas; @@ -24,75 +24,73 @@ ShaderLightPrefs::ShaderLightPrefs(QWidget *parent, Canvas *_canvas) : QDialog(p this->layout()->addWidget(middleWidget); // labels - middleLayout->addWidget(new QLabel("Ambient Color"),0,0); - middleLayout->addWidget(new QLabel("Directive Color"),1,0); - middleLayout->addWidget(new QLabel("Direction"),2,0); + middleLayout->addWidget(new QLabel("Ambient Color"), 0, 0); + middleLayout->addWidget(new QLabel("Directive Color"), 1, 0); + middleLayout->addWidget(new QLabel("Direction"), 2, 0); QPixmap dummy(20, 20); dummy.fill(canvas->getAmbientColor()); buttonAmbientColor = new QPushButton; buttonAmbientColor->setIcon(QIcon(dummy)); - middleLayout->addWidget(buttonAmbientColor,0,1); + middleLayout->addWidget(buttonAmbientColor, 0, 1); buttonAmbientColor->setFocusPolicy(Qt::NoFocus); - connect(buttonAmbientColor,SIGNAL(clicked(bool)),this,SLOT(buttonAmbientColorClicked())); + connect(buttonAmbientColor, SIGNAL(clicked(bool)), this, SLOT(buttonAmbientColorClicked())); editAmbientFactor = new QLineEdit; editAmbientFactor->setValidator(new QDoubleValidator); editAmbientFactor->setText(QString("%1").arg(canvas->getAmbientFactor())); - middleLayout->addWidget(editAmbientFactor,0,2); - connect(editAmbientFactor,SIGNAL(editingFinished()),this,SLOT(editAmbientFactorFinished())); + middleLayout->addWidget(editAmbientFactor, 0, 2); + connect(editAmbientFactor, SIGNAL(editingFinished()), this, SLOT(editAmbientFactorFinished())); QPushButton* buttonResetAmbientColor = new QPushButton("Reset"); - middleLayout->addWidget(buttonResetAmbientColor,0,3); + middleLayout->addWidget(buttonResetAmbientColor, 0, 3); buttonResetAmbientColor->setFocusPolicy(Qt::NoFocus); - connect(buttonResetAmbientColor,SIGNAL(clicked(bool)),this,SLOT(resetAmbientColorClicked())); - + connect(buttonResetAmbientColor, SIGNAL(clicked(bool)), this, SLOT(resetAmbientColorClicked())); dummy.fill(canvas->getDirectiveColor()); buttonDirectiveColor = new QPushButton; buttonDirectiveColor->setIcon(QIcon(dummy)); - middleLayout->addWidget(buttonDirectiveColor,1,1); + middleLayout->addWidget(buttonDirectiveColor, 1, 1); buttonDirectiveColor->setFocusPolicy(Qt::NoFocus); - connect(buttonDirectiveColor,SIGNAL(clicked(bool)),this,SLOT(buttonDirectiveColorClicked())); + connect(buttonDirectiveColor, SIGNAL(clicked(bool)), this, SLOT(buttonDirectiveColorClicked())); editDirectiveFactor = new QLineEdit; editDirectiveFactor->setValidator(new QDoubleValidator); editDirectiveFactor->setText(QString("%1").arg(canvas->getDirectiveFactor())); - middleLayout->addWidget(editDirectiveFactor,1,2); - connect(editDirectiveFactor,SIGNAL(editingFinished()),this,SLOT(editDirectiveFactorFinished())); + middleLayout->addWidget(editDirectiveFactor, 1, 2); + connect(editDirectiveFactor, SIGNAL(editingFinished()), this, SLOT(editDirectiveFactorFinished())); QPushButton* buttonResetDirectiveColor = new QPushButton("Reset"); - middleLayout->addWidget(buttonResetDirectiveColor,1,3); + middleLayout->addWidget(buttonResetDirectiveColor, 1, 3); buttonResetDirectiveColor->setFocusPolicy(Qt::NoFocus); - connect(buttonResetDirectiveColor,SIGNAL(clicked(bool)),this,SLOT(resetDirectiveColorClicked())); + connect(buttonResetDirectiveColor, SIGNAL(clicked(bool)), this, SLOT(resetDirectiveColorClicked())); // Fill in directions comboDirections = new QComboBox; - middleLayout->addWidget(comboDirections,2,1,1,2); + middleLayout->addWidget(comboDirections, 2, 1, 1, 2); comboDirections->addItems(canvas->getNameDir()); comboDirections->setCurrentIndex(canvas->getCurrentLightDirection()); - connect(comboDirections,SIGNAL(currentIndexChanged(int)),this,SLOT(comboDirectionsChanged(int))); + connect(comboDirections, SIGNAL(currentIndexChanged(int)), this, SLOT(comboDirectionsChanged(int))); QPushButton* buttonResetDirection = new QPushButton("Reset"); - middleLayout->addWidget(buttonResetDirection,2,3); + middleLayout->addWidget(buttonResetDirection, 2, 3); buttonResetDirection->setFocusPolicy(Qt::NoFocus); - connect(buttonResetDirection,SIGNAL(clicked(bool)),this,SLOT(resetDirection())); - + connect(buttonResetDirection, SIGNAL(clicked(bool)), this, SLOT(resetDirection())); // Ok button QWidget* boxButton = new QWidget; QHBoxLayout* boxButtonLayout = new QHBoxLayout; boxButton->setLayout(boxButtonLayout); - QFrame *spacerL = new QFrame; + QFrame* spacerL = new QFrame; spacerL->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding)); QPushButton* okButton = new QPushButton("Ok"); boxButtonLayout->addWidget(spacerL); boxButtonLayout->addWidget(okButton); this->layout()->addWidget(boxButton); okButton->setFocusPolicy(Qt::NoFocus); - connect(okButton,SIGNAL(clicked(bool)),this,SLOT(okButtonClicked())); + connect(okButton, SIGNAL(clicked(bool)), this, SLOT(okButtonClicked())); QSettings settings; if (!settings.value(PREFS_GEOM).isNull()) { @@ -100,10 +98,11 @@ ShaderLightPrefs::ShaderLightPrefs(QWidget *parent, Canvas *_canvas) : QDialog(p } } -void ShaderLightPrefs::buttonAmbientColorClicked() { - QColor newColor = QColorDialog::getColor(canvas->getAmbientColor(), this, QString("Choose color"),QColorDialog::DontUseNativeDialog); - if (newColor.isValid() == true) - { +void ShaderLightPrefs::buttonAmbientColorClicked() +{ + QColor newColor = + QColorDialog::getColor(canvas->getAmbientColor(), this, QString("Choose color"), QColorDialog::DontUseNativeDialog); + if (newColor.isValid() == true) { canvas->setAmbientColor(newColor); QPixmap dummy(20, 20); dummy.fill(canvas->getAmbientColor()); @@ -112,12 +111,14 @@ void ShaderLightPrefs::buttonAmbientColorClicked() { } } -void ShaderLightPrefs::editAmbientFactorFinished() { +void ShaderLightPrefs::editAmbientFactorFinished() +{ canvas->setAmbientFactor(editAmbientFactor->text().toDouble()); canvas->update(); } -void ShaderLightPrefs::resetAmbientColorClicked() { +void ShaderLightPrefs::resetAmbientColorClicked() +{ canvas->resetAmbientColor(); QPixmap dummy(20, 20); dummy.fill(canvas->getAmbientColor()); @@ -126,10 +127,11 @@ void ShaderLightPrefs::resetAmbientColorClicked() { canvas->update(); } -void ShaderLightPrefs::buttonDirectiveColorClicked() { - QColor newColor = QColorDialog::getColor(canvas->getDirectiveColor(), this, QString("Choose color"),QColorDialog::DontUseNativeDialog); - if (newColor.isValid() == true) - { +void ShaderLightPrefs::buttonDirectiveColorClicked() +{ + QColor newColor = + QColorDialog::getColor(canvas->getDirectiveColor(), this, QString("Choose color"), QColorDialog::DontUseNativeDialog); + if (newColor.isValid() == true) { canvas->setDirectiveColor(newColor); QPixmap dummy(20, 20); dummy.fill(canvas->getDirectiveColor()); @@ -138,12 +140,14 @@ void ShaderLightPrefs::buttonDirectiveColorClicked() { } } -void ShaderLightPrefs::editDirectiveFactorFinished() { +void ShaderLightPrefs::editDirectiveFactorFinished() +{ canvas->setDirectiveFactor(editDirectiveFactor->text().toDouble()); canvas->update(); } -void ShaderLightPrefs::resetDirectiveColorClicked() { +void ShaderLightPrefs::resetDirectiveColorClicked() +{ canvas->resetDirectiveColor(); QPixmap dummy(20, 20); dummy.fill(canvas->getDirectiveColor()); @@ -152,29 +156,30 @@ void ShaderLightPrefs::resetDirectiveColorClicked() { canvas->update(); } -void ShaderLightPrefs::okButtonClicked() { +void ShaderLightPrefs::okButtonClicked() +{ this->close(); } -void ShaderLightPrefs::comboDirectionsChanged(int ind) { +void ShaderLightPrefs::comboDirectionsChanged(int ind) +{ canvas->setCurrentLightDirection(ind); canvas->update(); } -void ShaderLightPrefs::resetDirection() { +void ShaderLightPrefs::resetDirection() +{ canvas->resetCurrentLightDirection(); comboDirections->setCurrentIndex(canvas->getCurrentLightDirection()); canvas->update(); } -void ShaderLightPrefs::resizeEvent(QResizeEvent *event) +void ShaderLightPrefs::resizeEvent(QResizeEvent* event) { QSettings().setValue(PREFS_GEOM, saveGeometry()); } -void ShaderLightPrefs::moveEvent(QMoveEvent *event) +void ShaderLightPrefs::moveEvent(QMoveEvent* event) { QSettings().setValue(PREFS_GEOM, saveGeometry()); } - - diff --git a/src/shaderlightprefs.h b/src/shaderlightprefs.h index 9f57339..4c4a1e6 100644 --- a/src/shaderlightprefs.h +++ b/src/shaderlightprefs.h @@ -15,8 +15,8 @@ public: ShaderLightPrefs(QWidget* parent, Canvas* _canvas); protected: - void resizeEvent(QResizeEvent *event) override; - void moveEvent(QMoveEvent *event) override; + void resizeEvent(QResizeEvent* event) override; + void moveEvent(QMoveEvent* event) override; private slots: void buttonAmbientColorClicked(); diff --git a/src/vertex.h b/src/vertex.h index 9738a75..06364b5 100644 --- a/src/vertex.h +++ b/src/vertex.h @@ -6,13 +6,12 @@ /* * Represents an optionally-indexed vertex in space */ -struct Vertex -{ +struct Vertex { Vertex() {} Vertex(float x, float y, float z) : x(x), y(y), z(z) {} GLfloat x, y, z; - GLuint i=0; + GLuint i = 0; bool operator!=(const Vertex& rhs) const { @@ -20,10 +19,14 @@ struct Vertex } bool operator<(const Vertex& rhs) const { - if (x != rhs.x) return x < rhs.x; - else if (y != rhs.y) return y < rhs.y; - else if (z != rhs.z) return z < rhs.z; - else return false; + if (x != rhs.x) + return x < rhs.x; + else if (y != rhs.y) + return y < rhs.y; + else if (z != rhs.z) + return z < rhs.z; + else + return false; } }; diff --git a/src/window.cpp b/src/window.cpp index c8aaba7..60239bc 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,9 +1,9 @@ #include -#include "window.h" #include "canvas.h" #include "loader.h" #include "shaderlightprefs.h" +#include "window.h" const QString Window::OPEN_EXTERNAL_KEY = "externalCmd"; const QString Window::RECENT_FILE_KEY = "recentFiles"; @@ -15,7 +15,7 @@ const QString Window::DRAW_MODE_KEY = "drawMode"; const QString Window::WINDOW_GEOM_KEY = "windowGeometry"; const QString Window::RESET_TRANSFORM_ON_LOAD_KEY = "resetTransformOnLoad"; -Window::Window(QWidget *parent) : +Window::Window(QWidget* parent) : QMainWindow(parent), open_action(new QAction("Open", this)), open_external_action(new QAction("Open with", this)), @@ -42,8 +42,8 @@ Window::Window(QWidget *parent) : autoreload_action(new QAction("Autoreload", this)), save_screenshot_action(new QAction("Save Screenshot", this)), hide_menuBar_action(new QAction("Hide Menu Bar", this)), - fullscreen_action(new QAction("Toggle Fullscreen",this)), - resetTransformOnLoadAction(new QAction("Reset rotation on load",this)), + fullscreen_action(new QAction("Toggle Fullscreen", this)), + resetTransformOnLoadAction(new QAction("Reset rotation on load", this)), recent_files(new QMenu("Open recent", this)), recent_files_group(new QActionGroup(this)), recent_files_clear_action(new QAction("Clear recent files", this)), @@ -61,20 +61,18 @@ Window::Window(QWidget *parent) : format.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(format); - + canvas = new Canvas(format, this); setCentralWidget(canvas); meshlightprefs = new ShaderLightPrefs(this, canvas); - QObject::connect(drawModePrefs_action, &QAction::triggered,this,&Window::on_drawModePrefs); + QObject::connect(drawModePrefs_action, &QAction::triggered, this, &Window::on_drawModePrefs); - QObject::connect(watcher, &QFileSystemWatcher::fileChanged, - this, &Window::on_watched_change); + QObject::connect(watcher, &QFileSystemWatcher::fileChanged, this, &Window::on_watched_change); open_action->setShortcut(QKeySequence::Open); - QObject::connect(open_action, &QAction::triggered, - this, &Window::on_open); + QObject::connect(open_action, &QAction::triggered, this, &Window::on_open); this->addAction(open_action); open_external_action->setShortcut(QKeySequence::Open); @@ -82,33 +80,26 @@ Window::Window(QWidget *parent) : this->addAction(open_external_action); open_external_action->setShortcut(QKeySequence(Qt::ALT + Qt::Key_S)); - QList quitShortcuts = { QKeySequence::Quit, QKeySequence::Close }; + QList quitShortcuts = {QKeySequence::Quit, QKeySequence::Close}; quit_action->setShortcuts(quitShortcuts); - QObject::connect(quit_action, &QAction::triggered, - this, &Window::close); + QObject::connect(quit_action, &QAction::triggered, this, &Window::close); this->addAction(quit_action); autoreload_action->setCheckable(true); - QObject::connect(autoreload_action, &QAction::triggered, - this, &Window::on_autoreload_triggered); + QObject::connect(autoreload_action, &QAction::triggered, this, &Window::on_autoreload_triggered); reload_action->setShortcut(QKeySequence::Refresh); reload_action->setEnabled(false); - QObject::connect(reload_action, &QAction::triggered, - this, &Window::on_reload); + QObject::connect(reload_action, &QAction::triggered, this, &Window::on_reload); - QObject::connect(about_action, &QAction::triggered, - this, &Window::on_about); + QObject::connect(about_action, &QAction::triggered, this, &Window::on_about); - QObject::connect(recent_files_clear_action, &QAction::triggered, - this, &Window::on_clear_recent); - QObject::connect(recent_files_group, &QActionGroup::triggered, - this, &Window::on_load_recent); + QObject::connect(recent_files_clear_action, &QAction::triggered, this, &Window::on_clear_recent); + QObject::connect(recent_files_group, &QActionGroup::triggered, this, &Window::on_load_recent); save_screenshot_action->setCheckable(false); - QObject::connect(save_screenshot_action, &QAction::triggered, - this, &Window::on_save_screenshot); - + QObject::connect(save_screenshot_action, &QAction::triggered, this, &Window::on_save_screenshot); + rebuild_recent_files(); const auto file_menu = menuBar()->addMenu("File"); @@ -126,14 +117,12 @@ Window::Window(QWidget *parent) : projection_menu->addAction(perspective_action); projection_menu->addAction(orthographic_action); const auto projections = new QActionGroup(projection_menu); - for (auto p : {perspective_action, orthographic_action}) - { + for (auto p : {perspective_action, orthographic_action}) { projections->addAction(p); p->setCheckable(true); } projections->setExclusive(true); - QObject::connect(projections, &QActionGroup::triggered, - this, &Window::on_projection); + QObject::connect(projections, &QActionGroup::triggered, this, &Window::on_projection); const auto draw_menu = view_menu->addMenu("Draw Mode"); draw_menu->addAction(shaded_action); @@ -141,14 +130,12 @@ Window::Window(QWidget *parent) : draw_menu->addAction(surfaceangle_action); draw_menu->addAction(meshlight_action); const auto drawModes = new QActionGroup(draw_menu); - for (auto p : {shaded_action, wireframe_action, surfaceangle_action, meshlight_action}) - { + for (auto p : {shaded_action, wireframe_action, surfaceangle_action, meshlight_action}) { drawModes->addAction(p); p->setCheckable(true); } drawModes->setExclusive(true); - QObject::connect(drawModes, &QActionGroup::triggered, - this, &Window::on_drawMode); + QObject::connect(drawModes, &QActionGroup::triggered, this, &Window::on_drawMode); view_menu->addAction(drawModePrefs_action); drawModePrefs_action->setDisabled(true); @@ -178,46 +165,40 @@ Window::Window(QWidget *parent) : common_view_left_action->setShortcut(Qt::Key_5); common_view_right_action->setShortcut(Qt::Key_6); common_view_center_action->setShortcut(Qt::Key_9); - QObject::connect(common_views, &QActionGroup::triggered, - this, &Window::on_common_view_change); + QObject::connect(common_views, &QActionGroup::triggered, this, &Window::on_common_view_change); view_menu->addAction(axes_action); axes_action->setCheckable(true); - QObject::connect(axes_action, &QAction::triggered, - this, &Window::on_drawAxes); + QObject::connect(axes_action, &QAction::triggered, this, &Window::on_drawAxes); view_menu->addAction(invert_zoom_action); invert_zoom_action->setCheckable(true); - QObject::connect(invert_zoom_action, &QAction::triggered, - this, &Window::on_invertZoom); + QObject::connect(invert_zoom_action, &QAction::triggered, this, &Window::on_invertZoom); view_menu->addAction(resetTransformOnLoadAction); resetTransformOnLoadAction->setCheckable(true); - QObject::connect(resetTransformOnLoadAction, &QAction::triggered, - this, &Window::on_resetTransformOnLoad); + QObject::connect(resetTransformOnLoadAction, &QAction::triggered, this, &Window::on_resetTransformOnLoad); view_menu->addAction(hide_menuBar_action); hide_menuBar_action->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_C); hide_menuBar_action->setCheckable(true); - QObject::connect(hide_menuBar_action, &QAction::toggled, - this, &Window::on_hide_menuBar); + QObject::connect(hide_menuBar_action, &QAction::toggled, this, &Window::on_hide_menuBar); this->addAction(hide_menuBar_action); view_menu->addAction(fullscreen_action); fullscreen_action->setShortcut(Qt::Key_F11); fullscreen_action->setCheckable(true); - QObject::connect(fullscreen_action, &QAction::toggled, - this, &Window::on_fullscreen); + QObject::connect(fullscreen_action, &QAction::toggled, this, &Window::on_fullscreen); this->addAction(fullscreen_action); - auto help_menu = menuBar()->addMenu("Help"); help_menu->addAction(about_action); load_persist_settings(); } -void Window::load_persist_settings(){ +void Window::load_persist_settings() +{ QSettings settings; bool invert_zoom = settings.value(INVERT_ZOOM_KEY, false).toBool(); canvas->invert_zoom(invert_zoom); @@ -234,17 +215,16 @@ void Window::load_persist_settings(){ axes_action->setChecked(draw_axes); QString projection = settings.value(PROJECTION_KEY, "perspective").toString(); - if(projection == "perspective"){ + if (projection == "perspective") { canvas->view_perspective(Canvas::P_PERSPECTIVE, false); perspective_action->setChecked(true); - }else{ + } else { canvas->view_perspective(Canvas::P_ORTHOGRAPHIC, false); orthographic_action->setChecked(true); } QString path = settings.value(OPEN_EXTERNAL_KEY, "").toString(); - if (!QDir::isAbsolutePath(path) && !path.isEmpty()) - { + if (!QDir::isAbsolutePath(path) && !path.isEmpty()) { path = QStandardPaths::findExecutable(path); } QString displayName = path.mid(path.lastIndexOf(QDir::separator()) + 1); @@ -252,12 +232,11 @@ void Window::load_persist_settings(){ open_external_action->setData(path); DrawMode draw_mode = (DrawMode)settings.value(DRAW_MODE_KEY, DRAWMODECOUNT).toInt(); - - if(draw_mode >= DRAWMODECOUNT) - { + + if (draw_mode >= DRAWMODECOUNT) { draw_mode = shaded; } - QAction* (dm_acts[]) = {shaded_action, wireframe_action, surfaceangle_action, meshlight_action}; + QAction*(dm_acts[]) = {shaded_action, wireframe_action, surfaceangle_action, meshlight_action}; dm_acts[draw_mode]->setChecked(true); on_drawMode(dm_acts[draw_mode]); @@ -265,7 +244,8 @@ void Window::load_persist_settings(){ restoreGeometry(settings.value(WINDOW_GEOM_KEY).toByteArray()); } -void Window::on_drawModePrefs() { +void Window::on_drawModePrefs() +{ // For now only one draw mode has settings // when settings for other draw mode will be available // we will need to check the current mode @@ -278,25 +258,21 @@ void Window::on_drawModePrefs() { void Window::on_open() { - const QString filename = QFileDialog::getOpenFileName( - this, "Load .stl file", QString(), "STL files (*.stl *.STL)"); - if (!filename.isNull()) - { + const QString filename = QFileDialog::getOpenFileName(this, "Load .stl file", QString(), "STL files (*.stl *.STL)"); + if (!filename.isNull()) { load_stl(filename); } } void Window::on_open_external() const { - if (current_file.isEmpty()) - { + if (current_file.isEmpty()) { return; } - QString program = open_external_action->data().toString(); if (program.isEmpty()) { - program = QFileDialog::getOpenFileName((QWidget*) this, "Select program to open with", QDir::rootPath()); + program = QFileDialog::getOpenFileName((QWidget*)this, "Select program to open with", QDir::rootPath()); if (!program.isEmpty()) { QSettings settings; settings.setValue(OPEN_EXTERNAL_KEY, program); @@ -312,13 +288,13 @@ void Window::on_open_external() const void Window::on_about() { QMessageBox::about(this, "", - "

fstl
" FSTL_VERSION "

" - "

A fast viewer for .stl files.
" - "https://github.com/fstl-app/fstl

" - "

© 2014-2024 Matthew Keeter
" - "matt.j.keeter@gmail.com

"); + "

fstl
" FSTL_VERSION "

" + "

A fast viewer for .stl files.
" + "https://github.com/fstl-app/fstl

" + "

© 2014-2025 Matthew Keeter
" + "matt.j.keeter@gmail.com

"); } void Window::on_bad_stl() @@ -356,8 +332,7 @@ void Window::disable_open() void Window::set_watched(const QString& filename) { const auto files = watcher->files(); - if (files.size()) - { + if (files.size()) { watcher->removePaths(watcher->files()); } watcher->addPath(filename); @@ -367,8 +342,7 @@ void Window::set_watched(const QString& filename) const auto f = QFileInfo(filename).absoluteFilePath(); recent.removeAll(f); recent.prepend(f); - while (recent.size() > MAX_RECENT_FILES) - { + while (recent.size() > MAX_RECENT_FILES) { recent.pop_back(); } settings.setValue(RECENT_FILE_KEY, recent); @@ -377,13 +351,10 @@ void Window::set_watched(const QString& filename) void Window::on_projection(QAction* proj) { - if (proj == perspective_action) - { + if (proj == perspective_action) { canvas->view_perspective(Canvas::P_PERSPECTIVE, true); QSettings().setValue(PROJECTION_KEY, "perspective"); - } - else - { + } else { canvas->view_perspective(Canvas::P_ORTHOGRAPHIC, true); QSettings().setValue(PROJECTION_KEY, "orthographic"); } @@ -395,23 +366,16 @@ void Window::on_drawMode(QAction* act) meshlightprefs->hide(); DrawMode mode; - if (act == shaded_action) - { + if (act == shaded_action) { drawModePrefs_action->setEnabled(false); mode = shaded; - } - else if (act == wireframe_action) - { + } else if (act == wireframe_action) { drawModePrefs_action->setEnabled(false); mode = wireframe; - } - else if (act == surfaceangle_action) - { + } else if (act == surfaceangle_action) { drawModePrefs_action->setEnabled(false); mode = surfaceangle; - } - else if (act == meshlight_action) - { + } else if (act == meshlight_action) { drawModePrefs_action->setEnabled(true); mode = meshlight; } @@ -431,23 +395,22 @@ void Window::on_invertZoom(bool d) QSettings().setValue(INVERT_ZOOM_KEY, d); } -void Window::on_resetTransformOnLoad(bool d) { +void Window::on_resetTransformOnLoad(bool d) +{ canvas->setResetTransformOnLoad(d); QSettings().setValue(RESET_TRANSFORM_ON_LOAD_KEY, d); } void Window::on_watched_change(const QString& filename) { - if (autoreload_action->isChecked()) - { + if (autoreload_action->isChecked()) { load_stl(filename, true); } } void Window::on_autoreload_triggered(bool b) { - if (b) - { + if (b) { on_reload(); } QSettings().setValue(AUTORELOAD_KEY, b); @@ -474,16 +437,12 @@ void Window::on_save_screenshot() { const auto image = canvas->grabFramebuffer(); auto file_name = QFileDialog::getSaveFileName( - this, - tr("Save Screenshot Image"), - QStandardPaths::standardLocations(QStandardPaths::StandardLocation::PicturesLocation).first(), - "Images (*.png *.jpg)"); + this, tr("Save Screenshot Image"), + QStandardPaths::standardLocations(QStandardPaths::StandardLocation::PicturesLocation).first(), "Images (*.png *.jpg)"); - auto get_file_extension = [](const std::string& file_name) -> std::string - { + auto get_file_extension = [](const std::string& file_name) -> std::string { const auto location = std::find(file_name.rbegin(), file_name.rend(), '.'); - if (location == file_name.rend()) - { + if (location == file_name.rend()) { return ""; } @@ -492,14 +451,12 @@ void Window::on_save_screenshot() }; const auto extension = get_file_extension(file_name.toStdString()); - if(extension.empty() || (extension != "png" && extension != "jpg")) - { + if (extension.empty() || (extension != "png" && extension != "jpg")) { file_name.append(".png"); } - + const auto save_ok = image.save(file_name); - if(!save_ok) - { + if (!save_ok) { QMessageBox::warning(this, tr("Error Saving Image"), tr("Unable to save screen shot image.")); } } @@ -515,21 +472,18 @@ void Window::rebuild_recent_files() QStringList files = settings.value(RECENT_FILE_KEY).toStringList(); const auto actions = recent_files_group->actions(); - for (auto a : actions) - { + for (auto a : actions) { recent_files_group->removeAction(a); } recent_files->clear(); - for (auto f : files) - { + for (auto f : files) { const auto a = new QAction(f, recent_files); a->setData(f); recent_files_group->addAction(a); recent_files->addAction(a); } - if (files.size() == 0) - { + if (files.size() == 0) { auto a = new QAction("No recent files", recent_files); recent_files->addAction(a); a->setEnabled(false); @@ -541,58 +495,54 @@ void Window::rebuild_recent_files() void Window::on_reload() { auto fs = watcher->files(); - if (fs.size() == 1) - { + if (fs.size() == 1) { load_stl(fs[0], true); } } void Window::on_common_view_change(QAction* common) { - if (common == common_view_center_action) canvas->common_view_change(centerview); - if (common == common_view_iso_action) canvas->common_view_change(isoview); - if (common == common_view_top_action) canvas->common_view_change(topview); - if (common == common_view_bottom_action) canvas->common_view_change(bottomview); - if (common == common_view_left_action) canvas->common_view_change(leftview); - if (common == common_view_right_action) canvas->common_view_change(rightview); - if (common == common_view_front_action) canvas->common_view_change(frontview); - if (common == common_view_back_action) canvas->common_view_change(backview); + if (common == common_view_center_action) + canvas->common_view_change(centerview); + if (common == common_view_iso_action) + canvas->common_view_change(isoview); + if (common == common_view_top_action) + canvas->common_view_change(topview); + if (common == common_view_bottom_action) + canvas->common_view_change(bottomview); + if (common == common_view_left_action) + canvas->common_view_change(leftview); + if (common == common_view_right_action) + canvas->common_view_change(rightview); + if (common == common_view_front_action) + canvas->common_view_change(frontview); + if (common == common_view_back_action) + canvas->common_view_change(backview); } bool Window::load_stl(const QString& filename, bool is_reload) { - if (!open_action->isEnabled()) return false; + if (!open_action->isEnabled()) + return false; canvas->set_status("Loading " + filename); Loader* loader = new Loader(this, filename, is_reload); - connect(loader, &Loader::started, - this, &Window::disable_open); - - connect(loader, &Loader::got_mesh, - canvas, &Canvas::load_mesh); - connect(loader, &Loader::error_bad_stl, - this, &Window::on_bad_stl); - connect(loader, &Loader::error_empty_mesh, - this, &Window::on_empty_mesh); - connect(loader, &Loader::error_missing_file, - this, &Window::on_missing_file); - - connect(loader, &Loader::finished, - loader, &Loader::deleteLater); - connect(loader, &Loader::finished, - this, &Window::enable_open); - connect(loader, &Loader::finished, - canvas, &Canvas::clear_status); - - if (filename[0] != ':') - { - connect(loader, &Loader::loaded_file, - this, &Window::setWindowTitle); - connect(loader, &Loader::loaded_file, - this, &Window::set_watched); - connect(loader, &Loader::loaded_file, - this, &Window::on_loaded); + connect(loader, &Loader::started, this, &Window::disable_open); + + connect(loader, &Loader::got_mesh, canvas, &Canvas::load_mesh); + connect(loader, &Loader::error_bad_stl, this, &Window::on_bad_stl); + connect(loader, &Loader::error_empty_mesh, this, &Window::on_empty_mesh); + connect(loader, &Loader::error_missing_file, this, &Window::on_missing_file); + + connect(loader, &Loader::finished, loader, &Loader::deleteLater); + connect(loader, &Loader::finished, this, &Window::enable_open); + connect(loader, &Loader::finished, canvas, &Canvas::clear_status); + + if (filename[0] != ':') { + connect(loader, &Loader::loaded_file, this, &Window::setWindowTitle); + connect(loader, &Loader::loaded_file, this, &Window::set_watched); + connect(loader, &Loader::loaded_file, this, &Window::on_loaded); reload_action->setEnabled(true); } @@ -600,28 +550,27 @@ bool Window::load_stl(const QString& filename, bool is_reload) return true; } -void Window::dragEnterEvent(QDragEnterEvent *event) +void Window::dragEnterEvent(QDragEnterEvent* event) { - if (event->mimeData()->hasUrls()) - { + if (event->mimeData()->hasUrls()) { auto urls = event->mimeData()->urls(); if (urls.size() == 1 && urls.front().path().endsWith(".stl")) event->acceptProposedAction(); } } -void Window::dropEvent(QDropEvent *event) +void Window::dropEvent(QDropEvent* event) { load_stl(event->mimeData()->urls().front().toLocalFile()); } -void Window::resizeEvent(QResizeEvent *event) +void Window::resizeEvent(QResizeEvent* event) { QSettings().setValue(WINDOW_GEOM_KEY, saveGeometry()); QWidget::resizeEvent(event); } -void Window::moveEvent(QMoveEvent *event) +void Window::moveEvent(QMoveEvent* event) { QSettings().setValue(WINDOW_GEOM_KEY, saveGeometry()); QWidget::moveEvent(event); @@ -632,17 +581,17 @@ void Window::sorted_insert(QStringList& list, const QCollator& collator, const Q int start = 0; int end = list.size() - 1; int index = 0; - while (start <= end){ - int mid = (start+end)/2; + while (start <= end) { + int mid = (start + end) / 2; if (list[mid] == value) { return; } int compare = collator.compare(value, list[mid]); if (compare < 0) { - end = mid-1; + end = mid - 1; index = mid; } else { - start = mid+1; + start = mid + 1; index = start; } } @@ -653,8 +602,7 @@ void Window::sorted_insert(QStringList& list, const QCollator& collator, const Q void Window::build_folder_file_list() { QString current_folder_path = QFileInfo(current_file).absoluteDir().absolutePath(); - if (!lookup_folder_files.isEmpty()) - { + if (!lookup_folder_files.isEmpty()) { if (current_folder_path == lookup_folder) { return; } @@ -735,24 +683,18 @@ bool Window::load_next(void) void Window::keyPressEvent(QKeyEvent* event) { - if (!open_action->isEnabled()) - { + if (!open_action->isEnabled()) { QMainWindow::keyPressEvent(event); return; } - if (event->key() == Qt::Key_Left) - { + if (event->key() == Qt::Key_Left) { load_prev(); return; - } - else if (event->key() == Qt::Key_Right) - { + } else if (event->key() == Qt::Key_Right) { load_next(); return; - } - else if (event->key() == Qt::Key_Escape) - { + } else if (event->key() == Qt::Key_Escape) { hide_menuBar_action->setChecked(false); return; } @@ -760,7 +702,8 @@ void Window::keyPressEvent(QKeyEvent* event) QMainWindow::keyPressEvent(event); } -void Window::on_fullscreen() { +void Window::on_fullscreen() +{ if (!this->isFullScreen()) { this->showFullScreen(); } else { diff --git a/src/window.h b/src/window.h index f13137b..200ded3 100644 --- a/src/window.h +++ b/src/window.h @@ -1,10 +1,10 @@ #ifndef WINDOW_H #define WINDOW_H -#include #include -#include #include +#include +#include class Canvas; class ShaderLightPrefs; @@ -13,16 +13,16 @@ class Window : public QMainWindow { Q_OBJECT public: - explicit Window(QWidget* parent=0); - bool load_stl(const QString& filename, bool is_reload=false); + explicit Window(QWidget* parent = 0); + bool load_stl(const QString& filename, bool is_reload = false); bool load_prev(void); bool load_next(void); protected: void dragEnterEvent(QDragEnterEvent* event) override; void dropEvent(QDropEvent* event) override; - void resizeEvent(QResizeEvent *event) override; - void moveEvent(QMoveEvent *event) override; + void resizeEvent(QResizeEvent* event) override; + void moveEvent(QMoveEvent* event) override; void keyPressEvent(QKeyEvent* event) override; public slots: @@ -94,7 +94,7 @@ private: QMenu* const recent_files; QActionGroup* const recent_files_group; QAction* const recent_files_clear_action; - const static int MAX_RECENT_FILES=8; + const static int MAX_RECENT_FILES = 8; static const QString OPEN_EXTERNAL_KEY; const static QString RECENT_FILE_KEY; const static QString INVERT_ZOOM_KEY;