mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 02:23:34 +00:00
Route bonsai through wgpu; delete the GL backend
Bonsai now drives the wgpu viewport for both sidecar and direct-IFC
loads. The GL viewer and its supporting state classes are gone.
SceneLoader rewire:
- Takes WgpuViewportWindow* instead of ViewportWindow*.
- Sidecar path reads metadata only (readSidecarMetadataOnly) and hands
the StreamingSidecar off to the new applyCachedModel. Field accesses
inside applySidecarData go through .meta.
- Direct-IFC path uses the wgpu A-path (upload{Mesh,Instance}Chunk +
finalizeModel). The applyLodExtension call is dropped — wgpu has no
live LOD1 splice; LOD1 still lands in the on-disk sidecar for the
next open.
Bonsai migration:
- ViewportWindow → WgpuViewportWindow across MainWindow, Measurement,
SessionState, and every modules/*/{Commands,Panel,View}.{h,cpp} —
116 sites total. Same s/OverlayRenderer::/WgpuOverlayRenderer::/
rename, 12 sites.
- Includes flipped from ../ifcviewer/ViewportWindow.h to
../ifcviewer-wgpu/WgpuViewportWindow.h. OverlayRenderer.h include
dropped (transitively reached via the viewport header).
- BonsaiViewer links IfcViewerWgpu in addition to IfcViewer for the
duration of the migration; the GL-side IfcViewer also publicly links
IfcViewerWgpu so SceneLoader can resolve WgpuViewportWindow.
GL backend deletion:
- src/ifcviewer/ViewportWindow.{cpp,h}, BvhAccel.*, OverlayRenderer.*,
Selection.*, Visibility.* all gone.
- src/ifcviewer-minimal/ removed entirely (MinimalWindow drove the GL
viewport).
- src/ifcviewer/tests: test_bvh_accel, test_selection, test_visibility
removed. The first has no replacement (wgpu doesn't use a per-instance
BVH); the latter two are ported separately. test_lod_builder,
test_sidecar_cache, test_instanced_geometry, test_federation remain
(backend-agnostic).
- IfcViewer's CMakeLists drops OpenGL, Qt::OpenGL, Qt::Widgets — none
of the surviving translation units reach for them.
Build flag plumbing:
- BUILD_BONSAIVIEWER now auto-enables BUILD_BONSAIVIEWER_WGPU since
SceneLoader requires the wgpu lib for its WgpuViewportWindow* arg.
- The wgpu subprojects add_subdirectory ahead of the GL one so
IfcViewerWgpu exists when IfcViewer's link evaluates.
- src/ifcviewer-minimal subdir reference removed from cmake/CMakeLists.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -37,7 +37,7 @@ void SceneLoader::setShouldWriteSidecar(bool enabled) {
|
||||
should_write_sidecar_ = enabled;
|
||||
}
|
||||
|
||||
SceneLoader::SceneLoader(ViewportWindow* viewport, QObject* parent)
|
||||
SceneLoader::SceneLoader(WgpuViewportWindow* viewport, QObject* parent)
|
||||
: QObject(parent), viewport_(viewport)
|
||||
{
|
||||
connect(&element_poll_timer_, &QTimer::timeout,
|
||||
@@ -189,11 +189,11 @@ void SceneLoader::startNextLoad() {
|
||||
joinSidecarThread();
|
||||
sidecar_read_thread_ = std::thread([this, ifc_path, mid, is_sidecar_source]() {
|
||||
QElapsedTimer rt; rt.start();
|
||||
auto cached = readSidecar(ifc_path);
|
||||
qDebug(" Sidecar read: %lld ms (%s)", rt.elapsed(), ifc_path.c_str());
|
||||
auto result = std::make_shared<std::optional<SidecarData>>(std::move(cached));
|
||||
auto cached = readSidecarMetadataOnly(ifc_path);
|
||||
qDebug(" Sidecar metadata read: %lld ms (%s)", rt.elapsed(), ifc_path.c_str());
|
||||
auto result = std::make_shared<std::optional<StreamingSidecar>>(std::move(cached));
|
||||
QMetaObject::invokeMethod(this, [this, mid, result, is_sidecar_source]() {
|
||||
if (*result && !(*result)->instances.empty()) {
|
||||
if (*result && !(*result)->meta.instances.empty()) {
|
||||
applySidecarData(mid, std::move(**result));
|
||||
if (!is_sidecar_source) {
|
||||
startDataSourceLoad(mid);
|
||||
@@ -233,36 +233,37 @@ void SceneLoader::startStreamLoadFor(uint32_t mid) {
|
||||
m.file_path.toStdString(), next_object_id_, loading_model_id_);
|
||||
}
|
||||
|
||||
void SceneLoader::applySidecarData(uint32_t mid, SidecarData data) {
|
||||
void SceneLoader::applySidecarData(uint32_t mid, StreamingSidecar metadata) {
|
||||
auto it = models_.find(mid);
|
||||
if (it == models_.end()) return;
|
||||
auto& model = it->second;
|
||||
SidecarData& d = metadata.meta;
|
||||
|
||||
qDebug("Sidecar hit: %s (%zu verts, %zu indices, %zu meshes, %zu instances, %zu elements)",
|
||||
qDebug("Sidecar hit: %s (%zu metadata bytes, %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());
|
||||
size_t(metadata.vertex_total_bytes),
|
||||
size_t(metadata.index_total_count),
|
||||
d.meshes.size(),
|
||||
d.instances.size(),
|
||||
d.elements.size());
|
||||
|
||||
// Rebase object/model IDs onto the current session's ID space. Two
|
||||
// cached models both starting at object_id=1 would collide otherwise.
|
||||
uint32_t min_oid = UINT32_MAX;
|
||||
for (const auto& pe : data.elements) {
|
||||
for (const auto& pe : d.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) {
|
||||
if (!d.elements.empty() && min_oid < UINT32_MAX) {
|
||||
oid_offset = next_object_id_ - min_oid;
|
||||
}
|
||||
for (auto& pe : data.elements) {
|
||||
for (auto& pe : d.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) {
|
||||
for (auto& inst : d.instances) {
|
||||
inst.object_id += oid_offset;
|
||||
inst.model_id = mid;
|
||||
}
|
||||
@@ -273,26 +274,26 @@ void SceneLoader::applySidecarData(uint32_t mid, SidecarData data) {
|
||||
// .ifc/.rdb sibling is absent.
|
||||
{
|
||||
ModelGeoref& gr = model.georef;
|
||||
gr.has_coordinate_operation = data.has_coordinate_operation != 0;
|
||||
gr.has_coordinate_operation = d.has_coordinate_operation != 0;
|
||||
Eigen::Map<const Eigen::Matrix<double, 4, 4, Eigen::ColMajor>> M(
|
||||
data.coordinate_operation_meters);
|
||||
d.coordinate_operation_meters);
|
||||
gr.coordinate_operation_meters = M;
|
||||
gr.units.project_length_to_meters = data.project_length_to_meters;
|
||||
gr.units.map_unit_to_meters = data.map_unit_to_meters;
|
||||
gr.units.project_length_to_meters = d.project_length_to_meters;
|
||||
gr.units.map_unit_to_meters = d.map_unit_to_meters;
|
||||
model.has_georef = true;
|
||||
}
|
||||
|
||||
if (!data.instances.empty() && !model.has_first_placement) {
|
||||
if (!d.instances.empty() && !model.has_first_placement) {
|
||||
using Mat4dCol = Eigen::Matrix<double, 4, 4, Eigen::ColMajor>;
|
||||
model.first_placement =
|
||||
Eigen::Map<const Mat4dCol>(data.instances[0].placement_transformation);
|
||||
Eigen::Map<const Mat4dCol>(d.instances[0].placement_transformation);
|
||||
model.has_first_placement = true;
|
||||
}
|
||||
|
||||
std::vector<PackedElementInfo> elements = std::move(data.elements);
|
||||
std::string stbl = std::move(data.string_table);
|
||||
std::vector<PackedElementInfo> elements = std::move(d.elements);
|
||||
std::string stbl = std::move(d.string_table);
|
||||
|
||||
viewport_->applyCachedModel(mid, std::move(data));
|
||||
viewport_->applyCachedModel(mid, std::move(metadata));
|
||||
|
||||
emit sidecarElementsReady(mid, std::move(elements), std::move(stbl));
|
||||
|
||||
@@ -397,8 +398,11 @@ void SceneLoader::onStreamerFinished() {
|
||||
next_object_id_ = m.streamer->lastObjectId();
|
||||
viewport_->finalizeModel(mid);
|
||||
|
||||
// Sidecar finalize + LOD application + disk write. Runs on the
|
||||
// GUI thread so applyLodExtension's GL touches are safe.
|
||||
// Sidecar finalize + disk write. Wgpu has no live LOD1 apply —
|
||||
// LOD1 indices land in the on-disk sidecar and are picked up
|
||||
// on the *next* open of this file; first-session view is
|
||||
// LOD0-only. Acceptable trade-off vs reallocating chunk index
|
||||
// slices live to splice LOD1 in.
|
||||
if (m.sidecar_builder) {
|
||||
ModelGeoref georef;
|
||||
if (auto* file = m.streamer->ifcFile()) {
|
||||
@@ -406,7 +410,6 @@ void SceneLoader::onStreamerFinished() {
|
||||
}
|
||||
QElapsedTimer wt; wt.start();
|
||||
SidecarData data = m.sidecar_builder->finalize(georef, m.streamed_elements);
|
||||
viewport_->applyLodExtension(mid, data);
|
||||
const bool ok = writeSidecar(m.file_path.toStdString(), data);
|
||||
qDebug(" Sidecar finalize + write: %lld ms (%s)",
|
||||
wt.elapsed(), ok ? "ok" : "FAILED");
|
||||
|
||||
Reference in New Issue
Block a user