/********************************************************************************
* *
* 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 . *
* *
********************************************************************************/
#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
#include
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