Commit 8ea7e372 authored by Matthias Betz's avatar Matthias Betz
Browse files

Support coupled GL viewports for the dual-view healer



Add OrbitCamera.copyOrbitFrom (sync orbit/zoom/pan, keep per-viewport aspect),
and GLViewport interaction listener + requestRedraw + clearScene so two
viewports can share camera movement and be cleared/redrawn independently.

Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
parent 8dcb2575
...@@ -56,6 +56,10 @@ public class GLViewport { ...@@ -56,6 +56,10 @@ public class GLViewport {
private double lastX; private double lastX;
private double lastY; private double lastY;
// optional hook invoked after a camera interaction (orbit/pan/zoom) so a coupled viewport can be
// kept in sync and redrawn (used by the dual-viewport healer)
private Runnable interactionListener;
// on-demand render request. openglfx can drop a repaint() that arrives while a frame is rendering // on-demand render request. openglfx can drop a repaint() that arrives while a frame is rendering
// (its requestRepaint is an unconditional notify with no pending flag), so a single repaint is not // (its requestRepaint is an unconditional notify with no pending flag), so a single repaint is not
// reliable. This flag + pump re-deliver repaint() each pulse until a frame consumes the request, // reliable. This flag + pump re-deliver repaint() each pulse until a frame consumes the request,
...@@ -120,6 +124,19 @@ public class GLViewport { ...@@ -120,6 +124,19 @@ public class GLViewport {
public OrbitCamera camera() { return camera; } public OrbitCamera camera() { return camera; }
/** Hook invoked after a camera interaction so a coupled viewport can sync and redraw. */
public void setInteractionListener(Runnable listener) { this.interactionListener = listener; }
/** Public redraw trigger (e.g. for a coupled viewport). */
public void requestRedraw() { requestRender(); }
/** Clears the displayed geometry (draws nothing) until a new scene is set. */
public void clearScene() {
currentScene = null;
lastIndices = new int[0];
setIndexSet(new int[0]);
}
/** /**
* Requests a redraw. Sets the render flag, wakes the canvas immediately (best effort), and starts * Requests a redraw. Sets the render flag, wakes the canvas immediately (best effort), and starts
* the pump so the request is re-delivered until a frame actually consumes it. Call on the FX thread. * the pump so the request is re-delivered until a frame actually consumes it. Call on the FX thread.
...@@ -257,12 +274,20 @@ public class GLViewport { ...@@ -257,12 +274,20 @@ public class GLViewport {
camera.pan(-dx * speed, dy * speed); camera.pan(-dx * speed, dy * speed);
} }
requestRender(); requestRender();
notifyInteraction();
}); });
canvas.setOnScroll(e -> { canvas.setOnScroll(e -> {
camera.zoom(e.getDeltaY() < 0 ? 1.05 : 0.95); camera.zoom(e.getDeltaY() < 0 ? 1.05 : 0.95);
requestRender(); requestRender();
notifyInteraction();
}); });
} }
public void resetCamera() { camera.reset(); requestRender(); } public void resetCamera() { camera.reset(); requestRender(); }
private void notifyInteraction() {
if (interactionListener != null) {
interactionListener.run();
}
}
} }
...@@ -6,8 +6,8 @@ package de.hft.stuttgart.citydoctor2.gui.gl; ...@@ -6,8 +6,8 @@ package de.hft.stuttgart.citydoctor2.gui.gl;
*/ */
public class OrbitCamera { public class OrbitCamera {
private static final double INITIAL_AZIMUTH = 120.0; private static final double INITIAL_AZIMUTH = 180.0;
private static final double INITIAL_ELEVATION = 20.0; private static final double INITIAL_ELEVATION = -60.0;
private static final double INITIAL_DISTANCE = 100.0; private static final double INITIAL_DISTANCE = 100.0;
private static final double FOVY_RAD = Math.toRadians(30); private static final double FOVY_RAD = Math.toRadians(30);
private static final float NEAR = 0.1f; private static final float NEAR = 0.1f;
...@@ -57,6 +57,15 @@ public class OrbitCamera { ...@@ -57,6 +57,15 @@ public class OrbitCamera {
panY = 0; panY = 0;
} }
/** Copies the orbit/zoom/pan state from another camera (but not its aspect ratio). */
public void copyOrbitFrom(OrbitCamera other) {
this.azimuthDeg = other.azimuthDeg;
this.elevationDeg = other.elevationDeg;
this.distance = other.distance;
this.panX = other.panX;
this.panY = other.panY;
}
public double distance() { return distance; } public double distance() { return distance; }
/** Current azimuth (rotation about Z) in degrees. */ /** Current azimuth (rotation about Z) in degrees. */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment