mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 18:16:40 +00:00
ifcviewer: split into shared library and two app executables
Turn src/ifcviewer into libIfcViewer.so holding the rendering engine + geometry pipeline (ViewportWindow, GeometryStreamer, BvhAccel, InstancedGeometry, SidecarCache, LodBuilder, AppSettings). Move the existing UI shell (MainWindow, SettingsWindow, main.cpp) into src/ifcviewer-full as the IfcViewerFull executable. Add a new src/ifcviewer-minimal target with a MinimalWindow that hosts only the viewport and reuses the sidecar fast-path for benchmark/debug runs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -674,6 +674,8 @@ if(BUILD_IFCGEOM)
|
||||
endif(BUILD_IFCGEOM)
|
||||
if(BUILD_IFCVIEWER)
|
||||
add_subdirectory(../src/ifcviewer ifcviewer)
|
||||
add_subdirectory(../src/ifcviewer-minimal ifcviewer-minimal)
|
||||
add_subdirectory(../src/ifcviewer-full ifcviewer-full)
|
||||
endif()
|
||||
|
||||
# Cmake uninstall target
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
message("Running CMakeLists.txt in /src/ifcviewer-full")
|
||||
|
||||
file(GLOB IFCVIEWER_FULL_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB IFCVIEWER_FULL_H_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||
set(IFCVIEWER_FULL_FILES ${IFCVIEWER_FULL_CPP_FILES} ${IFCVIEWER_FULL_H_FILES})
|
||||
|
||||
add_executable(IfcViewerFull ${IFCVIEWER_FULL_FILES})
|
||||
|
||||
set_target_properties(IfcViewerFull PROPERTIES
|
||||
AUTOMOC ON
|
||||
WIN32_EXECUTABLE ON
|
||||
MACOSX_BUNDLE ON
|
||||
)
|
||||
|
||||
target_link_libraries(IfcViewerFull PRIVATE IfcViewer)
|
||||
|
||||
install(TARGETS IfcViewerFull EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
@@ -0,0 +1,36 @@
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of IfcOpenShell. #
|
||||
# #
|
||||
# IfcOpenShell is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the Lesser GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3.0 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IfcOpenShell is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# Lesser GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the Lesser GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
message("Running CMakeLists.txt in /src/ifcviewer-minimal")
|
||||
|
||||
file(GLOB IFCVIEWER_MINIMAL_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB IFCVIEWER_MINIMAL_H_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||
set(IFCVIEWER_MINIMAL_FILES ${IFCVIEWER_MINIMAL_CPP_FILES} ${IFCVIEWER_MINIMAL_H_FILES})
|
||||
|
||||
add_executable(IfcViewerMinimal ${IFCVIEWER_MINIMAL_FILES})
|
||||
|
||||
set_target_properties(IfcViewerMinimal PROPERTIES
|
||||
AUTOMOC ON
|
||||
WIN32_EXECUTABLE ON
|
||||
MACOSX_BUNDLE ON
|
||||
)
|
||||
|
||||
target_link_libraries(IfcViewerMinimal PRIVATE IfcViewer)
|
||||
|
||||
install(TARGETS IfcViewerMinimal EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
@@ -0,0 +1,278 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "MinimalWindow.h"
|
||||
#include "AppSettings.h"
|
||||
#include "SidecarCache.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QStatusBar>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
MinimalWindow::MinimalWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
viewport_ = new ViewportWindow();
|
||||
viewport_container_ = QWidget::createWindowContainer(viewport_, this);
|
||||
viewport_container_->setMinimumSize(400, 300);
|
||||
viewport_container_->setFocusPolicy(Qt::StrongFocus);
|
||||
setCentralWidget(viewport_container_);
|
||||
|
||||
status_label_ = new QLabel("Ready");
|
||||
stats_label_ = new QLabel();
|
||||
stats_label_->setVisible(AppSettings::instance().showStats());
|
||||
statusBar()->addWidget(status_label_, 1);
|
||||
statusBar()->addPermanentWidget(stats_label_);
|
||||
|
||||
connect(viewport_, &ViewportWindow::frameStatsUpdated, this,
|
||||
[this](const ViewportWindow::FrameStats& s) {
|
||||
if (!stats_label_->isVisible()) return;
|
||||
stats_label_->setText(
|
||||
QString("%1 fps | %2 ms | %3/%4 obj | %5/%6 tri | %7 gl_draws (%8 sub)")
|
||||
.arg(s.fps, 0, 'f', 1)
|
||||
.arg(s.frame_time_ms, 0, 'f', 1)
|
||||
.arg(s.visible_objects)
|
||||
.arg(s.total_objects)
|
||||
.arg(s.visible_triangles)
|
||||
.arg(s.total_triangles)
|
||||
.arg(s.gl_draw_calls)
|
||||
.arg(s.indirect_sub_draws));
|
||||
});
|
||||
|
||||
connect(&AppSettings::instance(), &AppSettings::showStatsChanged, this, [this](bool show) {
|
||||
stats_label_->setVisible(show);
|
||||
if (!show) stats_label_->clear();
|
||||
});
|
||||
|
||||
// Periodically drain the streamer's pending-elements buffer so it doesn't
|
||||
// grow unbounded on large models. We don't use the element data here —
|
||||
// this window has no tree — but the buffer must still be flushed.
|
||||
connect(&element_drain_timer_, &QTimer::timeout, this, &MinimalWindow::drainStreamerElements);
|
||||
element_drain_timer_.setInterval(250);
|
||||
|
||||
setWindowTitle("IfcViewerMinimal");
|
||||
resize(1200, 800);
|
||||
}
|
||||
|
||||
MinimalWindow::~MinimalWindow() {
|
||||
joinSidecarThread();
|
||||
}
|
||||
|
||||
void MinimalWindow::joinSidecarThread() {
|
||||
if (sidecar_read_thread_.joinable())
|
||||
sidecar_read_thread_.join();
|
||||
}
|
||||
|
||||
void MinimalWindow::addFiles(const QStringList& paths) {
|
||||
for (const auto& path : paths) {
|
||||
uint32_t id = next_model_id_++;
|
||||
ModelEntry entry;
|
||||
entry.id = id;
|
||||
entry.file_path = path;
|
||||
entry.display_name = QFileInfo(path).fileName();
|
||||
entry.streamer = new GeometryStreamer(this);
|
||||
models_[id] = entry;
|
||||
load_queue_.push_back(id);
|
||||
}
|
||||
|
||||
if (loading_model_id_ == 0) {
|
||||
QTimer::singleShot(0, this, &MinimalWindow::startNextLoad);
|
||||
}
|
||||
}
|
||||
|
||||
void MinimalWindow::connectStreamer(GeometryStreamer* streamer) {
|
||||
connect(streamer, &GeometryStreamer::meshReady,
|
||||
this, &MinimalWindow::onMeshReady, Qt::QueuedConnection);
|
||||
connect(streamer, &GeometryStreamer::instanceReady,
|
||||
this, &MinimalWindow::onInstanceReady, Qt::QueuedConnection);
|
||||
connect(streamer, &GeometryStreamer::finished,
|
||||
this, &MinimalWindow::onStreamingFinished, Qt::QueuedConnection);
|
||||
connect(streamer, &GeometryStreamer::errorOccurred,
|
||||
this, &MinimalWindow::onErrorOccurred, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MinimalWindow::startNextLoad() {
|
||||
if (load_queue_.empty()) {
|
||||
loading_model_id_ = 0;
|
||||
status_label_->setText(QString("Loaded %1 model(s)").arg(models_.size()));
|
||||
applyPendingBenchmark();
|
||||
return;
|
||||
}
|
||||
|
||||
loading_model_id_ = load_queue_.front();
|
||||
load_queue_.pop_front();
|
||||
|
||||
auto& model = models_[loading_model_id_];
|
||||
|
||||
load_timer_.restart();
|
||||
status_label_->setText("Loading: " + model.display_name);
|
||||
|
||||
std::string ifc_path = model.file_path.toStdString();
|
||||
uint64_t file_size = static_cast<uint64_t>(QFileInfo(model.file_path).size());
|
||||
uint32_t mid = loading_model_id_;
|
||||
|
||||
joinSidecarThread();
|
||||
sidecar_read_thread_ = std::thread([this, ifc_path, file_size, mid]() {
|
||||
QElapsedTimer rt; rt.start();
|
||||
auto cached = readSidecar(ifc_path, file_size);
|
||||
qDebug(" Sidecar read: %lld ms (%s)", rt.elapsed(), ifc_path.c_str());
|
||||
auto result = std::make_shared<std::optional<SidecarData>>(std::move(cached));
|
||||
QMetaObject::invokeMethod(this, [this, mid, result]() {
|
||||
if (*result && !(*result)->instances.empty()) {
|
||||
applySidecarData(mid, std::move(**result));
|
||||
} else {
|
||||
auto it = models_.find(mid);
|
||||
if (it == models_.end()) return;
|
||||
auto& m = it->second;
|
||||
connectStreamer(m.streamer);
|
||||
element_drain_timer_.start();
|
||||
m.streamer->loadFile(
|
||||
m.file_path.toStdString(), next_object_id_, loading_model_id_);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
|
||||
void MinimalWindow::applySidecarData(uint32_t mid, SidecarData data) {
|
||||
auto it = models_.find(mid);
|
||||
if (it == models_.end()) return;
|
||||
auto& model = it->second;
|
||||
|
||||
qDebug("Sidecar hit: %s (%zu verts, %zu indices, %zu meshes, %zu instances, %zu elements)",
|
||||
model.file_path.toStdString().c_str(),
|
||||
data.vertices.size() / INSTANCED_VERTEX_STRIDE_BYTES,
|
||||
data.indices.size(),
|
||||
data.meshes.size(),
|
||||
data.instances.size(),
|
||||
data.elements.size());
|
||||
|
||||
// Rebase object/model IDs onto the current session's ID space. Matches
|
||||
// MainWindow::applySidecarData — two cached models both starting at
|
||||
// object_id=1 would collide otherwise.
|
||||
uint32_t min_oid = UINT32_MAX;
|
||||
for (const auto& pe : data.elements) {
|
||||
if (pe.object_id < min_oid) min_oid = pe.object_id;
|
||||
}
|
||||
uint32_t oid_offset = 0;
|
||||
if (!data.elements.empty() && min_oid < UINT32_MAX) {
|
||||
oid_offset = next_object_id_ - min_oid;
|
||||
}
|
||||
for (auto& pe : data.elements) {
|
||||
pe.object_id += oid_offset;
|
||||
pe.model_id = mid;
|
||||
if (pe.object_id >= next_object_id_)
|
||||
next_object_id_ = pe.object_id + 1;
|
||||
}
|
||||
for (auto& inst : data.instances) {
|
||||
inst.object_id += oid_offset;
|
||||
inst.model_id = mid;
|
||||
}
|
||||
|
||||
viewport_->applyCachedModel(mid, std::move(data));
|
||||
|
||||
qint64 ms = load_timer_.elapsed();
|
||||
QString elapsed = (ms >= 1000)
|
||||
? QString::number(ms / 1000.0, 'f', 2) + " s"
|
||||
: QString::number(ms) + " ms";
|
||||
status_label_->setText(QString("%1 loaded from cache in %2")
|
||||
.arg(model.display_name).arg(elapsed));
|
||||
|
||||
loading_model_id_ = 0;
|
||||
QTimer::singleShot(0, this, &MinimalWindow::startNextLoad);
|
||||
}
|
||||
|
||||
void MinimalWindow::onMeshReady(MeshChunk chunk) {
|
||||
viewport_->uploadMeshChunk(chunk);
|
||||
}
|
||||
|
||||
void MinimalWindow::onInstanceReady(InstanceChunk chunk) {
|
||||
viewport_->uploadInstanceChunk(chunk);
|
||||
}
|
||||
|
||||
void MinimalWindow::drainStreamerElements() {
|
||||
if (loading_model_id_ == 0) return;
|
||||
auto it = models_.find(loading_model_id_);
|
||||
if (it == models_.end()) return;
|
||||
(void)it->second.streamer->drainElements();
|
||||
}
|
||||
|
||||
void MinimalWindow::onStreamingFinished() {
|
||||
element_drain_timer_.stop();
|
||||
drainStreamerElements();
|
||||
|
||||
if (loading_model_id_ != 0) {
|
||||
auto it = models_.find(loading_model_id_);
|
||||
if (it != models_.end()) {
|
||||
next_object_id_ = it->second.streamer->lastObjectId();
|
||||
viewport_->finalizeModel(loading_model_id_);
|
||||
}
|
||||
}
|
||||
|
||||
qint64 ms = load_timer_.elapsed();
|
||||
QString elapsed = (ms >= 1000)
|
||||
? QString::number(ms / 1000.0, 'f', 2) + " s"
|
||||
: QString::number(ms) + " ms";
|
||||
|
||||
auto it = models_.find(loading_model_id_);
|
||||
QString name = (it != models_.end()) ? it->second.display_name : QString();
|
||||
status_label_->setText(QString("%1 streamed in %2").arg(name).arg(elapsed));
|
||||
|
||||
startNextLoad();
|
||||
}
|
||||
|
||||
void MinimalWindow::onErrorOccurred(const QString& message) {
|
||||
qWarning("IfcViewerMinimal error: %s", qPrintable(message));
|
||||
status_label_->setText("Error: " + message);
|
||||
}
|
||||
|
||||
void MinimalWindow::setPendingCamera(const QString& params) {
|
||||
pending_camera_ = params;
|
||||
}
|
||||
|
||||
void MinimalWindow::setPendingBenchmark(int frames) {
|
||||
pending_benchmark_ = frames;
|
||||
}
|
||||
|
||||
void MinimalWindow::applyPendingBenchmark() {
|
||||
if (pending_camera_.isEmpty() && pending_benchmark_ <= 0) return;
|
||||
|
||||
if (!pending_camera_.isEmpty()) {
|
||||
QStringList parts = pending_camera_.split(',');
|
||||
if (parts.size() == 6) {
|
||||
viewport_->setCamera(
|
||||
parts[0].toFloat(), parts[1].toFloat(), parts[2].toFloat(),
|
||||
parts[3].toFloat(), parts[4].toFloat(), parts[5].toFloat());
|
||||
qDebug("Camera set: %s", qPrintable(pending_camera_));
|
||||
} else {
|
||||
qWarning("--camera expects 6 comma-separated values: tx,ty,tz,dist,yaw,pitch");
|
||||
}
|
||||
pending_camera_.clear();
|
||||
}
|
||||
|
||||
if (pending_benchmark_ > 0) {
|
||||
qDebug("Starting benchmark: %d frames", pending_benchmark_);
|
||||
viewport_->setBenchmarkFrames(pending_benchmark_);
|
||||
pending_benchmark_ = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef MINIMALWINDOW_H
|
||||
#define MINIMALWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <thread>
|
||||
|
||||
#include "ViewportWindow.h"
|
||||
#include "GeometryStreamer.h"
|
||||
|
||||
class MinimalWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MinimalWindow(QWidget* parent = nullptr);
|
||||
~MinimalWindow();
|
||||
|
||||
void addFiles(const QStringList& paths);
|
||||
void setPendingCamera(const QString& params);
|
||||
void setPendingBenchmark(int frames);
|
||||
|
||||
private slots:
|
||||
void onMeshReady(MeshChunk chunk);
|
||||
void onInstanceReady(InstanceChunk chunk);
|
||||
void onStreamingFinished();
|
||||
void onErrorOccurred(const QString& message);
|
||||
void drainStreamerElements();
|
||||
|
||||
private:
|
||||
struct ModelEntry {
|
||||
uint32_t id = 0;
|
||||
QString file_path;
|
||||
QString display_name;
|
||||
GeometryStreamer* streamer = nullptr;
|
||||
};
|
||||
|
||||
void startNextLoad();
|
||||
void connectStreamer(GeometryStreamer* streamer);
|
||||
void joinSidecarThread();
|
||||
void applySidecarData(uint32_t mid, SidecarData data);
|
||||
void applyPendingBenchmark();
|
||||
|
||||
ViewportWindow* viewport_ = nullptr;
|
||||
QWidget* viewport_container_ = nullptr;
|
||||
QLabel* status_label_ = nullptr;
|
||||
QLabel* stats_label_ = nullptr;
|
||||
|
||||
std::map<uint32_t, ModelEntry> models_;
|
||||
std::deque<uint32_t> load_queue_;
|
||||
uint32_t next_model_id_ = 1;
|
||||
uint32_t next_object_id_ = 1;
|
||||
uint32_t loading_model_id_ = 0;
|
||||
std::thread sidecar_read_thread_;
|
||||
|
||||
QTimer element_drain_timer_;
|
||||
QElapsedTimer load_timer_;
|
||||
|
||||
QString pending_camera_;
|
||||
int pending_benchmark_ = 0;
|
||||
};
|
||||
|
||||
#endif // MINIMALWINDOW_H
|
||||
@@ -0,0 +1,65 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QSurfaceFormat>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "MinimalWindow.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
app.setApplicationName("IfcViewerMinimal");
|
||||
app.setOrganizationName("IfcOpenShell");
|
||||
|
||||
QSurfaceFormat fmt;
|
||||
fmt.setVersion(4, 5);
|
||||
fmt.setProfile(QSurfaceFormat::CoreProfile);
|
||||
fmt.setDepthBufferSize(24);
|
||||
fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
|
||||
fmt.setSamples(4);
|
||||
QSurfaceFormat::setDefaultFormat(fmt);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("IfcOpenShell minimal IFC viewer — benchmarking and debugging");
|
||||
parser.addHelpOption();
|
||||
parser.addPositionalArgument("files", "IFC file(s) to open", "[files...]");
|
||||
parser.addOption({{"c", "camera"},
|
||||
"Set camera: tx,ty,tz,dist,yaw,pitch", "params"});
|
||||
parser.addOption({{"b", "benchmark"},
|
||||
"Run N frames then print stats and exit", "frames"});
|
||||
parser.process(app);
|
||||
|
||||
MinimalWindow window;
|
||||
window.show();
|
||||
|
||||
auto args = parser.positionalArguments();
|
||||
if (!args.isEmpty()) {
|
||||
window.addFiles(args);
|
||||
}
|
||||
|
||||
if (parser.isSet("camera")) {
|
||||
window.setPendingCamera(parser.value("camera"));
|
||||
}
|
||||
if (parser.isSet("benchmark")) {
|
||||
window.setPendingBenchmark(parser.value("benchmark").toInt());
|
||||
}
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -20,9 +20,9 @@
|
||||
message("Running CMakeLists.txt in /src/ifcviewer")
|
||||
|
||||
set(QT_VERSION 6 CACHE STRING "Qt version")
|
||||
# IfcViewer always needs OpenGL in addition to Core/Gui/Widgets. We don't use
|
||||
# the CACHE'd QT_COMPONENTS here because it may have been set by another target
|
||||
# (e.g. qtviewer) without the OpenGL component.
|
||||
# IfcViewerLib always needs OpenGL in addition to Core/Gui/Widgets. We don't
|
||||
# use the CACHE'd QT_COMPONENTS here because it may have been set by another
|
||||
# target (e.g. qtviewer) without the OpenGL component.
|
||||
find_package(Qt${QT_VERSION} COMPONENTS Core Gui Widgets OpenGL REQUIRED PATHS ${QT_DIR})
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
@@ -32,17 +32,21 @@ file(GLOB IFCVIEWER_CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB IFCVIEWER_H_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||
set(IFCVIEWER_FILES ${IFCVIEWER_CPP_FILES} ${IFCVIEWER_H_FILES})
|
||||
|
||||
add_executable(IfcViewer ${IFCVIEWER_FILES})
|
||||
add_library(IfcViewer ${IFCVIEWER_FILES})
|
||||
|
||||
set_target_properties(IfcViewer PROPERTIES
|
||||
AUTOMOC ON
|
||||
WIN32_EXECUTABLE ON
|
||||
MACOSX_BUNDLE ON
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
# Consumers include headers as `#include "ViewportWindow.h"`, so expose this
|
||||
# directory on the public interface.
|
||||
target_include_directories(IfcViewer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_dependencies(IfcViewer ${kernel_libraries} ${mapping_libraries})
|
||||
|
||||
target_link_libraries(IfcViewer PRIVATE
|
||||
target_link_libraries(IfcViewer PUBLIC
|
||||
IfcGeom
|
||||
IfcParse
|
||||
${OpenCASCADE_LIBRARIES}
|
||||
@@ -58,7 +62,11 @@ target_link_libraries(IfcViewer PRIVATE
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(IfcViewer PRIVATE Threads::Threads)
|
||||
target_link_libraries(IfcViewer PUBLIC Threads::Threads)
|
||||
endif()
|
||||
|
||||
install(TARGETS IfcViewer EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
|
||||
install(FILES ${IFCVIEWER_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcviewer
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user