mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 10:57:49 +00:00
ifcviewer: scaffold ViewportHost + ViewportCore (Path A step 1)
Define the boundary the Path-A web-bring-up refactor will move things
across:
- ViewportHost.h is the embedder interface — surface creation,
framebuffer geometry, frame scheduling, quit, and notification
callbacks (onObjectPicked, onToolModeChanged, …). Desktop hosts
forward notifications to Q_SIGNALS; the future web host pushes
them to JS callbacks.
- ViewportCore.{h,cpp} is the platform-agnostic render-core target.
Empty today — the body fills in across the #78-#86 sequence as
each Qt subsystem (matrices, vectors, strings, timers, render
path, input) gets de-Qt'd and moved over.
- ViewportWindow now multiply-inherits ViewportHost alongside QWindow
and implements the host overrides as thin forwarders: createSurface
returns the cached surface_, requestFrame -> requestUpdate, quit ->
QCoreApplication::quit, onObjectPicked -> emit objectPicked.
Renamed the DPR accessor `dpr()` (vs `devicePixelRatio`) to avoid
the inherited-virtual clash with QWindow's qreal-returning version.
No method movement yet — this is purely the architectural scaffold so
subsequent commits have a destination.
This commit is contained in:
@@ -145,6 +145,7 @@ set(IFCVIEWER_CORE_SOURCES
|
||||
SidecarCache.cpp
|
||||
StreamingLoader.cpp
|
||||
StreamingThread.cpp
|
||||
ViewportCore.cpp
|
||||
)
|
||||
set(IFCVIEWER_CORE_HEADERS
|
||||
BufferPool.h
|
||||
@@ -158,6 +159,8 @@ set(IFCVIEWER_CORE_HEADERS
|
||||
StreamingLoader.h
|
||||
StreamingThread.h
|
||||
VertexQuantization.h
|
||||
ViewportCore.h
|
||||
ViewportHost.h
|
||||
VisibilityState.h
|
||||
)
|
||||
list(TRANSFORM IFCVIEWER_CORE_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 "ViewportCore.h"
|
||||
|
||||
ViewportCore::ViewportCore(ViewportHost* host) : host_(host) {}
|
||||
ViewportCore::~ViewportCore() = default;
|
||||
@@ -0,0 +1,51 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 VIEWPORTCORE_H
|
||||
#define VIEWPORTCORE_H
|
||||
|
||||
// Platform-agnostic render core. Owns the wgpu state + scene state +
|
||||
// per-frame render path. Talks to its embedder through ViewportHost
|
||||
// (window/canvas surface, scheduling, notifications) — has no Qt or
|
||||
// browser dependencies of its own.
|
||||
//
|
||||
// Empty for now: this header / TU is the placeholder for the
|
||||
// incremental Path-A refactor (#77-#86). Each subsequent commit moves
|
||||
// one subsystem out of ViewportWindow.cpp into here and updates the
|
||||
// public surface accordingly. Until that work lands, ViewportWindow
|
||||
// retains its render body; this class is just the target for the
|
||||
// move.
|
||||
|
||||
#include "ViewportHost.h"
|
||||
|
||||
class ViewportCore {
|
||||
public:
|
||||
explicit ViewportCore(ViewportHost* host);
|
||||
~ViewportCore();
|
||||
|
||||
ViewportCore(const ViewportCore&) = delete;
|
||||
ViewportCore& operator=(const ViewportCore&) = delete;
|
||||
|
||||
ViewportHost* host() const { return host_; }
|
||||
|
||||
private:
|
||||
ViewportHost* host_;
|
||||
};
|
||||
|
||||
#endif // VIEWPORTCORE_H
|
||||
@@ -0,0 +1,101 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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 VIEWPORTHOST_H
|
||||
#define VIEWPORTHOST_H
|
||||
|
||||
// Abstraction layer between the platform-agnostic ViewportCore (wgpu
|
||||
// state, scene state, render path, cull, input) and whichever host owns
|
||||
// the native window / canvas / event loop. On desktop the host is a
|
||||
// QWindow-derived ViewportWindow; on web it'll be a small canvas-bound
|
||||
// shell in src/ifcviewer-web. The host implements this interface so
|
||||
// ViewportCore can call back into it for:
|
||||
//
|
||||
// - surface creation (only the host knows its native handle)
|
||||
// - framebuffer geometry (size, DPR)
|
||||
// - scheduling the next render tick (QWindow::requestUpdate vs RAF)
|
||||
// - quitting the process
|
||||
// - bubbling user-facing notifications (selection changed, picked
|
||||
// object, tool mode, frame stats) up to whatever signal/callback
|
||||
// mechanism the host uses
|
||||
//
|
||||
// All host-side notifications have default empty implementations so
|
||||
// hosts only override the ones they care about — minimal-boilerplate
|
||||
// hosts (a screenshot CI runner, the web spike before UI lands) can
|
||||
// ignore the rest. Inverting control this way keeps ViewportCore from
|
||||
// having to know whether it's running inside Qt's event loop or
|
||||
// Emscripten's main-loop.
|
||||
|
||||
#include <webgpu/webgpu.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class ViewportHost {
|
||||
public:
|
||||
virtual ~ViewportHost() = default;
|
||||
|
||||
// Surface creation. The host wraps its native window/canvas in the
|
||||
// appropriate WGPUSurfaceDescriptor extension struct (Xlib, HWND,
|
||||
// CAMetalLayer, EmscriptenCanvas) and returns the resulting surface.
|
||||
// Returns nullptr if the surface can't be created — caller logs and
|
||||
// aborts init.
|
||||
virtual WGPUSurface createSurface(WGPUInstance instance) = 0;
|
||||
|
||||
// Framebuffer geometry. width/height are in device pixels (post-
|
||||
// multiplied by devicePixelRatio); the depth attachment and surface
|
||||
// configuration both consume these.
|
||||
virtual void framebufferSize(int& width_px, int& height_px) const = 0;
|
||||
// Device pixel ratio (CSS-px → device-px). Renamed from
|
||||
// `devicePixelRatio` because QWindow already exposes that name; an
|
||||
// override conflict between qreal (QWindow) and float (a hypothetical
|
||||
// ViewportHost::devicePixelRatio) would surprise readers. `dpr` is
|
||||
// unambiguous.
|
||||
virtual float dpr() const = 0;
|
||||
|
||||
// Ask the host to schedule another render tick. On Qt this is
|
||||
// QWindow::requestUpdate (coalesced + DPR-aware); on web this is a
|
||||
// requestAnimationFrame schedule. Idempotent within a tick.
|
||||
virtual void requestFrame() = 0;
|
||||
|
||||
// Ask the host to terminate the process / close the tab. Used by
|
||||
// the --screenshot / --benchmark exits, and by the future
|
||||
// window-close path.
|
||||
virtual void quit() = 0;
|
||||
|
||||
// ---- Notifications ----------------------------------------------------
|
||||
//
|
||||
// Each callback corresponds to something ViewportWindow currently
|
||||
// exposes as a Q_SIGNAL. Default empty body so non-Qt hosts can
|
||||
// selectively implement; the desktop ViewportWindow override
|
||||
// forwards each to emit objectPicked() / emit toolModeChanged() etc.
|
||||
|
||||
virtual void onObjectPicked(uint32_t /*object_id*/) {}
|
||||
virtual void onSurfacePickedInTool(int /*x_px*/, int /*y_px*/,
|
||||
int /*modifiers*/) {}
|
||||
virtual void onToolModeChanged(int /*tool_mode*/) {}
|
||||
virtual void onToolBackspacePressed() {}
|
||||
// FrameStats is a Qt-using struct declared inside ViewportWindow
|
||||
// today; once the move to ViewportCore happens it'll come back here
|
||||
// as a plain POD. For B4 the desktop ViewportWindow keeps the
|
||||
// existing typed signal and this is just the placeholder.
|
||||
virtual void onFrameStats(double /*frame_ms*/, double /*cull_ms*/,
|
||||
uint32_t /*draws*/, uint32_t /*tris*/) {}
|
||||
};
|
||||
|
||||
#endif // VIEWPORTHOST_H
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "StreamingLoader.h"
|
||||
#include "VertexQuantization.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QGuiApplication>
|
||||
#include <QResizeEvent>
|
||||
#include <QDebug>
|
||||
@@ -628,6 +629,57 @@ ViewportWindow::~ViewportWindow() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
// ---- ViewportHost overrides ------------------------------------------------
|
||||
//
|
||||
// Scaffolding for Path-A. ViewportCore is empty today, so these don't
|
||||
// yet have callers; the abstract methods exist only to define the
|
||||
// boundary that subsequent commits will rely on. Each notification
|
||||
// forwards to the existing Q_SIGNAL so bonsai-side consumers see no
|
||||
// change.
|
||||
|
||||
WGPUSurface ViewportWindow::createSurface(WGPUInstance /*instance*/) {
|
||||
// initWgpu() still drives surface creation through the private
|
||||
// no-arg createSurface() helper that populates surface_. Once
|
||||
// ViewportCore takes over the wgpu init flow it'll call this
|
||||
// override instead and the private helper goes away; for now the
|
||||
// override is a getter.
|
||||
return surface_;
|
||||
}
|
||||
|
||||
void ViewportWindow::framebufferSize(int& width_px, int& height_px) const {
|
||||
const float r = float(QWindow::devicePixelRatio());
|
||||
width_px = int(QWindow::width() * r);
|
||||
height_px = int(QWindow::height() * r);
|
||||
}
|
||||
|
||||
float ViewportWindow::dpr() const {
|
||||
return float(QWindow::devicePixelRatio());
|
||||
}
|
||||
|
||||
void ViewportWindow::requestFrame() {
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void ViewportWindow::quit() {
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
void ViewportWindow::onObjectPicked(uint32_t object_id) {
|
||||
emit objectPicked(object_id);
|
||||
}
|
||||
|
||||
void ViewportWindow::onSurfacePickedInTool(int x_px, int y_px, int modifiers) {
|
||||
emit surfacePickedInTool(x_px, y_px, modifiers);
|
||||
}
|
||||
|
||||
void ViewportWindow::onToolModeChanged(int tool_mode) {
|
||||
emit toolModeChanged(static_cast<ToolMode>(tool_mode));
|
||||
}
|
||||
|
||||
void ViewportWindow::onToolBackspacePressed() {
|
||||
emit toolBackspacePressed();
|
||||
}
|
||||
|
||||
void ViewportWindow::setBackgroundColor(const QColor& color) {
|
||||
background_color_ = color;
|
||||
if (isExposed()) requestUpdate();
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "OverlayRenderer.h"
|
||||
#include "SelectionState.h"
|
||||
#include "StreamingThread.h"
|
||||
#include "ViewportCore.h"
|
||||
#include "ViewportHost.h"
|
||||
#include "VisibilityState.h"
|
||||
|
||||
// Stage-2 wgpu viewport: opens a native QWindow, brings up a wgpu instance/
|
||||
@@ -57,12 +59,37 @@
|
||||
//
|
||||
// Mirrors the lifecycle shape of the GL ViewportWindow so subsequent stages
|
||||
// can grow this into a full IFC renderer without restructuring the host.
|
||||
class ViewportWindow : public QWindow {
|
||||
//
|
||||
// Also implements ViewportHost: as the Path-A refactor moves rendering
|
||||
// state out into ViewportCore, this class plays the embedder role
|
||||
// (provides the wgpu surface, schedules frames, forwards notifications
|
||||
// to Q_SIGNALS). The web target's host is the analog on the Emscripten
|
||||
// side. Today most state still lives here; the override implementations
|
||||
// at the bottom of the class are the bridge for whatever has already
|
||||
// moved.
|
||||
class ViewportWindow : public QWindow, public ViewportHost {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ViewportWindow(QWindow* parent = nullptr);
|
||||
~ViewportWindow();
|
||||
|
||||
// --- ViewportHost ----------------------------------------------------
|
||||
//
|
||||
// Implementations live in ViewportWindow.cpp alongside the
|
||||
// platform-specific surface code so the Qt + native window-handle
|
||||
// bits stay co-located. Notification overrides (onObjectPicked
|
||||
// etc.) forward to the existing Q_SIGNALS so bonsai-side consumers
|
||||
// see no change.
|
||||
WGPUSurface createSurface(WGPUInstance instance) override;
|
||||
void framebufferSize(int& width_px, int& height_px) const override;
|
||||
float dpr() const override;
|
||||
void requestFrame() override;
|
||||
void quit() override;
|
||||
void onObjectPicked(uint32_t object_id) override;
|
||||
void onSurfacePickedInTool(int x_px, int y_px, int modifiers) override;
|
||||
void onToolModeChanged(int tool_mode) override;
|
||||
void onToolBackspacePressed() override;
|
||||
|
||||
void setBackgroundColor(const QColor& color);
|
||||
|
||||
// Queue a sidecar path to be loaded after wgpu init completes. Safe to
|
||||
|
||||
Reference in New Issue
Block a user