mirror of https://github.com/rusefi/jzy3d-api.git
fixed first image not HiDPI and ensure profiling info displayed are those of the ccurrent rendering (and not previous one)
This commit is contained in:
parent
ea75026dc1
commit
f4fc69b8e9
|
@ -48,7 +48,7 @@ public class FrameAWT extends java.awt.Frame implements IFrame {
|
|||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
FrameAWT.this.remove((java.awt.Component) FrameAWT.this.chart.getCanvas());
|
||||
FrameAWT.this.chart.stopAnimation();
|
||||
FrameAWT.this.chart.stopAllThreads();
|
||||
FrameAWT.this.chart.dispose();
|
||||
FrameAWT.this.chart = null;
|
||||
FrameAWT.this.dispose();
|
||||
|
|
|
@ -156,13 +156,18 @@ public class Chart {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void startAnimation() {
|
||||
setAnimated(true);
|
||||
}
|
||||
|
||||
public void stopAnimation() {
|
||||
setAnimated(false);
|
||||
}
|
||||
|
||||
public void startAnimation() {
|
||||
setAnimated(true);
|
||||
public void stopAllThreads() {
|
||||
getMouse().getSlaveThreadController().stop();
|
||||
stopAnimation();
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,31 +199,31 @@ public class Chart {
|
|||
public ICameraMouseController addMouseCameraController() {
|
||||
if(mouse==null) {
|
||||
mouse = getFactory().getPainterFactory().newMouseCameraController(this);
|
||||
}
|
||||
|
||||
CameraThreadController rotation = mouse.getSlaveThreadController();//new CameraThreadController(this);
|
||||
rotation.setStep(0.025f);
|
||||
|
||||
// Always keep update view until the camera thread controller
|
||||
// Has a timer to avoid rotating too fast (when no update view, thread can
|
||||
// go much faster so rotation is to speedy!)
|
||||
rotation.setUpdateViewDefault(true);
|
||||
// later, should apply : !chart.getQuality().isAnimated());
|
||||
|
||||
|
||||
// mouse.addSlaveThreadController(rotation);
|
||||
|
||||
// Switch between on demand/continuous rendering
|
||||
// keep to false if animated to avoid double rendering
|
||||
// keep to true otherwise the mouse does not update
|
||||
mouse.setUpdateViewDefault(!getQuality().isAnimated());
|
||||
|
||||
CameraThreadController rotation = mouse.getSlaveThreadController();//new CameraThreadController(this);
|
||||
rotation.setStep(0.025f);
|
||||
|
||||
// Always keep update view until the camera thread controller
|
||||
// Has a timer to avoid rotating too fast (when no update view, thread can
|
||||
// go much faster so rotation is to speedy!)
|
||||
rotation.setUpdateViewDefault(true);
|
||||
// later, should apply : !chart.getQuality().isAnimated());
|
||||
|
||||
|
||||
// mouse.addSlaveThreadController(rotation);
|
||||
|
||||
// Switch between on demand/continuous rendering
|
||||
// keep to false if animated to avoid double rendering
|
||||
// keep to true otherwise the mouse does not update
|
||||
mouse.setUpdateViewDefault(!getQuality().isAnimated());
|
||||
|
||||
}
|
||||
return mouse;
|
||||
}
|
||||
|
||||
public IMousePickingController addMousePickingController(int clickWidth) {
|
||||
if(mousePicking==null) {
|
||||
mousePicking = getFactory().getPainterFactory().newMousePickingController(this, clickWidth);
|
||||
mousePicking = getFactory().getPainterFactory().newMousePickingController(this, clickWidth);
|
||||
}
|
||||
return mousePicking;
|
||||
}
|
||||
|
@ -226,11 +231,12 @@ public class Chart {
|
|||
public ICameraKeyController addKeyboardCameraController() {
|
||||
if(keyboard==null) {
|
||||
keyboard = getFactory().getPainterFactory().newKeyboardCameraController(this);
|
||||
|
||||
// Switch between on demand/continuous rendering
|
||||
// keep to false if animated to avoid double rendering
|
||||
// keep to true otherwise the mouse does not update
|
||||
keyboard.setUpdateViewDefault(!getQuality().isAnimated());
|
||||
}
|
||||
// Switch between on demand/continuous rendering
|
||||
// keep to false if animated to avoid double rendering
|
||||
// keep to true otherwise the mouse does not update
|
||||
keyboard.setUpdateViewDefault(!getQuality().isAnimated());
|
||||
|
||||
return keyboard;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package org.jzy3d.events;
|
||||
|
||||
public interface IViewIsVerticalEventListener {
|
||||
public interface IViewEventListener {
|
||||
public void viewFirstRender();
|
||||
|
||||
public void viewVerticalReached(ViewIsVerticalEvent e);
|
||||
|
||||
public void viewVerticalLeft(ViewIsVerticalEvent e);
|
|
@ -6,7 +6,7 @@ import org.apache.log4j.Logger;
|
|||
import org.jzy3d.chart.Chart;
|
||||
import org.jzy3d.chart.factories.IChartFactory;
|
||||
import org.jzy3d.colors.Color;
|
||||
import org.jzy3d.events.IViewIsVerticalEventListener;
|
||||
import org.jzy3d.events.IViewEventListener;
|
||||
import org.jzy3d.events.IViewLifecycleEventListener;
|
||||
import org.jzy3d.events.IViewPointChangedListener;
|
||||
import org.jzy3d.events.ViewIsVerticalEvent;
|
||||
|
@ -73,8 +73,7 @@ public class View {
|
|||
protected boolean squared = true;
|
||||
protected float cameraRenderingSphereRadiusFactor = 1f;
|
||||
protected float cameraRenderingSphereRadiusFactorOnTop = 0.25f;
|
||||
|
||||
|
||||
|
||||
// view objects
|
||||
protected Camera cam;
|
||||
protected IAxis axis;
|
||||
|
@ -91,10 +90,13 @@ public class View {
|
|||
|
||||
// view listeners
|
||||
protected List<IViewPointChangedListener> viewPointChangedListeners;
|
||||
protected List<IViewIsVerticalEventListener> viewOnTopListeners;
|
||||
protected List<IViewEventListener> viewOnTopListeners;
|
||||
protected List<IViewLifecycleEventListener> viewLifecycleListeners;
|
||||
protected boolean wasOnTopAtLastRendering;
|
||||
|
||||
// view states
|
||||
protected boolean first = true;
|
||||
|
||||
// constants
|
||||
public static final float PI_div2 = (float) Math.PI / 2;
|
||||
public static final float DISTANCE_DEFAULT = 2000;
|
||||
|
@ -657,11 +659,11 @@ public class View {
|
|||
return annotations.getGraph();
|
||||
}
|
||||
|
||||
public boolean addViewOnTopEventListener(IViewIsVerticalEventListener listener) {
|
||||
public boolean addViewEventListener(IViewEventListener listener) {
|
||||
return viewOnTopListeners.add(listener);
|
||||
}
|
||||
|
||||
public boolean removeViewOnTopEventListener(IViewIsVerticalEventListener listener) {
|
||||
public boolean removeViewOnTopEventListener(IViewEventListener listener) {
|
||||
return viewOnTopListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
@ -669,13 +671,18 @@ public class View {
|
|||
ViewIsVerticalEvent e = new ViewIsVerticalEvent(this);
|
||||
|
||||
if (isOnTop)
|
||||
for (IViewIsVerticalEventListener listener : viewOnTopListeners)
|
||||
for (IViewEventListener listener : viewOnTopListeners)
|
||||
listener.viewVerticalReached(e);
|
||||
else
|
||||
for (IViewIsVerticalEventListener listener : viewOnTopListeners)
|
||||
for (IViewEventListener listener : viewOnTopListeners)
|
||||
listener.viewVerticalLeft(e);
|
||||
}
|
||||
|
||||
protected void fireViewFirstRender() {
|
||||
for (IViewEventListener listener : viewOnTopListeners)
|
||||
listener.viewFirstRender();
|
||||
}
|
||||
|
||||
public boolean addViewPointChangedListener(IViewPointChangedListener listener) {
|
||||
return viewPointChangedListeners.add(listener);
|
||||
}
|
||||
|
@ -832,7 +839,7 @@ public class View {
|
|||
|
||||
public void render() {
|
||||
fireViewLifecycleWillRender(null);
|
||||
|
||||
|
||||
renderBackground(0f, 1f);
|
||||
renderScene();
|
||||
renderOverlay();
|
||||
|
@ -862,8 +869,14 @@ public class View {
|
|||
}
|
||||
|
||||
public void renderScene(ViewportConfiguration viewport) {
|
||||
// updateQuality(); // REMOVED BECAUSE NOT NECESSARY
|
||||
|
||||
//synchronized(this) {
|
||||
if(first) {
|
||||
fireViewFirstRender();
|
||||
first=false;
|
||||
}
|
||||
//}
|
||||
|
||||
BoundingBox3d scaling = computeScaledViewBounds();
|
||||
updateCamera(viewport, scaling);
|
||||
renderAxeBox();
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package org.jzy3d.plot3d.rendering.view;
|
||||
|
||||
import org.jzy3d.events.IViewEventListener;
|
||||
import org.jzy3d.events.ViewIsVerticalEvent;
|
||||
|
||||
public class ViewEventAdapter implements IViewEventListener{
|
||||
@Override
|
||||
public void viewFirstRender() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void viewVerticalReached(ViewIsVerticalEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void viewVerticalLeft(ViewIsVerticalEvent e) {
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ public class EmulGLAnimator implements IAnimator {
|
|||
loop = true;
|
||||
|
||||
while (loop) {
|
||||
canvas.doDisplay();
|
||||
canvas.doRender();
|
||||
|
||||
try {
|
||||
Thread.sleep(RENDERING_LOOP_PAUSE);
|
||||
|
|
|
@ -5,7 +5,12 @@ import org.jzy3d.chart.controllers.CameraThreadControllerWithTime;
|
|||
import org.jzy3d.chart.controllers.keyboard.camera.AWTCameraKeyController;
|
||||
import org.jzy3d.chart.controllers.keyboard.screenshot.AWTScreenshotKeyController;
|
||||
import org.jzy3d.chart.controllers.mouse.picking.IMousePickingController;
|
||||
import org.jzy3d.chart.factories.IFrame;
|
||||
import org.jzy3d.maths.Rectangle;
|
||||
import org.jzy3d.painters.IPainter.Font;
|
||||
import org.jzy3d.plot3d.primitives.axis.AxisBox;
|
||||
import org.jzy3d.plot3d.rendering.canvas.EmulGLCanvas;
|
||||
import org.jzy3d.plot3d.text.renderers.TextBitmapRenderer;
|
||||
|
||||
/**
|
||||
* {@link EmulGLSkin} is a chart facade that returns known subtypes of chart components already downcasted.
|
||||
|
@ -41,6 +46,24 @@ public class EmulGLSkin {
|
|||
return (EmulGLCanvas)chart.getCanvas();
|
||||
}
|
||||
|
||||
public IFrame open(int width, int height) {
|
||||
IFrame frame = chart.open(width, height);
|
||||
|
||||
triggerRenderAfterMili(30);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
public void triggerRenderAfterMili(long mili) {
|
||||
if (!chart.getQuality().isAnimated()) {
|
||||
try {
|
||||
Thread.sleep(30);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
chart.render();
|
||||
}
|
||||
}
|
||||
|
||||
public AdaptiveMouseController addMouseCameraController() {
|
||||
return (AdaptiveMouseController)chart.addMouseCameraController();
|
||||
|
@ -72,7 +95,12 @@ public class EmulGLSkin {
|
|||
}
|
||||
|
||||
|
||||
public CameraThreadControllerWithTime getSlaveThreadController() {
|
||||
public CameraThreadControllerWithTime getThread() {
|
||||
return getSlaveThreadController(getMouse());
|
||||
}
|
||||
|
||||
public TextBitmapRenderer getAxisTextRenderer() {
|
||||
return ((TextBitmapRenderer)((AxisBox)chart.getView().getAxis()).getTextRenderer());
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ public class AdaptiveMouseController extends AWTCameraMouseController {
|
|||
gl.setAutoAdaptToHiDPI(currentHiDPI);
|
||||
// this force the GL image to apply the new HiDPI setting immediatly
|
||||
gl.updatePixelScale(canvas.getGraphics());
|
||||
gl.resetViewport();
|
||||
gl.applyViewport();
|
||||
}
|
||||
|
||||
protected void disableWireframe(Chart chart) {
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.jzy3d.plot3d.rendering.view.Camera;
|
|||
* @author Martin Pernollet
|
||||
*/
|
||||
public class CameraThreadControllerWithTime extends CameraThreadController implements Runnable {
|
||||
private static final int TIME_TO_SPIN_DEFAULT = 10;
|
||||
|
||||
protected double speed = 10; // seconds to make a complete revolution
|
||||
|
||||
/**
|
||||
|
@ -40,19 +42,25 @@ public class CameraThreadControllerWithTime extends CameraThreadController imple
|
|||
/**
|
||||
* The interval between each rate limit verification in MS
|
||||
*/
|
||||
protected static final int RATE_CHECK_RATE = 100;
|
||||
|
||||
protected static final int RATE_CHECK_RATE = 40;
|
||||
/**
|
||||
* Rotation direction : Direction.LEFT makes negative azimuth increments, while Direction.RIGHT
|
||||
* make positive azimuth increments.
|
||||
*/
|
||||
protected Direction direction = Direction.LEFT;
|
||||
|
||||
public enum Direction {
|
||||
LEFT, RIGHT;
|
||||
}
|
||||
|
||||
|
||||
public CameraThreadControllerWithTime() {}
|
||||
|
||||
/**
|
||||
* Defaults time to spin to 10
|
||||
* @param chart
|
||||
*/
|
||||
public CameraThreadControllerWithTime(Chart chart) {
|
||||
this(chart, 10);
|
||||
this(chart, TIME_TO_SPIN_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.jzy3d.plot3d.rendering.canvas;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
@ -11,11 +13,14 @@ import java.awt.geom.AffineTransform;
|
|||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jzy3d.chart.IAnimator;
|
||||
import org.jzy3d.chart.factories.IChartFactory;
|
||||
import org.jzy3d.colors.AWTColor;
|
||||
import org.jzy3d.colors.Color;
|
||||
import org.jzy3d.maths.Coord2d;
|
||||
import org.jzy3d.maths.TicToc;
|
||||
|
@ -32,6 +37,15 @@ import jgl.GLCanvas;
|
|||
import jgl.GLUT;
|
||||
import jgl.context.gl_pointer;
|
||||
|
||||
/**
|
||||
* This canvas allows rendering charts with jGL as OpenGL backend which perform in CPU.
|
||||
*
|
||||
* The below schema depicts how this canvas does painting :
|
||||
*
|
||||
* <img src="doc-files/emulgl-canvas.png"/>
|
||||
*
|
||||
* @author Martin Pernollet
|
||||
*/
|
||||
public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorable {
|
||||
Logger log = Logger.getLogger(EmulGLCanvas.class);
|
||||
|
||||
|
@ -43,24 +57,29 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
*/
|
||||
public static final boolean TO_BE_CHOOSEN_REPAINT_WITH_FLUSH = false;
|
||||
|
||||
/** set to TRUE to overlay performance info on top left corner */
|
||||
protected boolean profileDisplayMethod = false;
|
||||
/** set to TRUE to show in console events of the component (to debug GLUT) */
|
||||
protected boolean debugEvents = false;
|
||||
|
||||
protected TicToc profileDisplayTimer = new TicToc();
|
||||
protected Font profileDisplayFont = new Font("Arial", Font.PLAIN, 12);
|
||||
protected int profileDisplayCount = 0;
|
||||
|
||||
protected Monitor monitor;
|
||||
|
||||
|
||||
// Fields used by the canvas to work
|
||||
protected View view;
|
||||
protected EmulGLPainter painter;
|
||||
protected IAnimator animator;
|
||||
|
||||
protected AtomicBoolean isRenderingFlag = new AtomicBoolean(false);
|
||||
|
||||
|
||||
// Profiling (display perf on screen)
|
||||
/** set to TRUE to show in console events of the component (to debug GLUT) */
|
||||
protected boolean debugEvents = false;
|
||||
/** set to TRUE to overlay performance info on top left corner */
|
||||
protected boolean profileDisplayMethod = false;
|
||||
protected TicToc profileDisplayTimer = new TicToc();
|
||||
protected Font profileDisplayFont = new Font("Arial", Font.PLAIN, 12);
|
||||
protected int profileDisplayCount = 0;
|
||||
protected List<ProfileInfo> profileInfo = new ArrayList<>();
|
||||
|
||||
// Monitor (export perf to something else, e.g. an XLS file)
|
||||
protected Monitor monitor;
|
||||
|
||||
|
||||
public EmulGLCanvas(IChartFactory factory, Scene scene, Quality quality) {
|
||||
super();
|
||||
view = scene.newView(this, quality);
|
||||
|
@ -71,14 +90,11 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
|
||||
animator = factory.getPainterFactory().newAnimator(this);
|
||||
|
||||
if (quality.isPreserveViewportSize()) {
|
||||
myGL.setAutoAdaptToHiDPI(false);
|
||||
} else {
|
||||
if (quality.isHiDPIEnabled()) {
|
||||
myGL.setAutoAdaptToHiDPI(true);
|
||||
} else {
|
||||
myGL.setAutoAdaptToHiDPI(false);
|
||||
}
|
||||
// FROM NATIVE
|
||||
// renderer = factory.newRenderer(view, traceGL, debugGL);
|
||||
// addGLEventListener(renderer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -103,7 +119,7 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
@Override
|
||||
public void processEvent(AWTEvent e) {
|
||||
if (debugEvents && shouldPrintEvent(e)) {
|
||||
System.out.println("EmulGLCanvas.processEvent:" + e);
|
||||
System.err.println("EmulGLCanvas.processEvent:" + e);
|
||||
}
|
||||
super.processEvent(e);
|
||||
}
|
||||
|
@ -112,7 +128,9 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
return !(e.getID() == MouseEvent.MOUSE_MOVED);
|
||||
}
|
||||
|
||||
// ******************* INIT ******************* //
|
||||
/* *********************************************************************** */
|
||||
/* ******************************* INIT ********************************** */
|
||||
/* *********************************************************************** */
|
||||
|
||||
/** Equivalent to registering a Renderer3d in native canvas. */
|
||||
protected void init(int width, int height) {
|
||||
|
@ -126,7 +144,7 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
myUT.glutInitWindowPosition(getX(), getY());
|
||||
|
||||
myUT.glutCreateWindow(this); // this canvas GLUT register this canvas
|
||||
myUT.glutDisplayFunc("doDisplay"); // on this canvas GLUT register this display method
|
||||
myUT.glutDisplayFunc("doRender"); // on this canvas GLUT register this display method
|
||||
myUT.glutReshapeFunc("doReshape"); // on ComponentEvent.RESIZE TODO: double render car
|
||||
// GLUT.resize invoque
|
||||
// reshape + display
|
||||
|
@ -143,29 +161,90 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
// pourquoi est il nécessaire de le faire pendant mouse dragged?
|
||||
}
|
||||
|
||||
/* *********************************************************************** */
|
||||
/* ***************************** DISPLAY ********************************* */
|
||||
/* *********************************************************************** */
|
||||
|
||||
// ******************* DISPLAY ******************* //
|
||||
/**
|
||||
* This overrides the {@link GLCanvas} hence {@link Canvas} methods to copy the image of the 3D
|
||||
* scene as generated while {@link GL#glFlush()}.
|
||||
*
|
||||
* It is called when the application needs to paint the canvas, which assume a rendering has
|
||||
* already been process by {@link #doRender()} which produce an image that the canvas can use for
|
||||
* fast pixel swap.
|
||||
*
|
||||
* {@link #doRender()} on its side is triggered when {@link GLUT} thinks it is relevant. This may
|
||||
* occur because {@link EmulGLCanvas} triggered a {@link ComponentEvent.COMPONENT_RESIZED} event.
|
||||
*/
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
if (profileDisplayMethod) {
|
||||
// Overrides GL swapping to retrieve the image and print performance info inside
|
||||
BufferedImage glImage = myGL.getRenderedImage();
|
||||
paintProfileInfo(glImage);
|
||||
g.drawImage(glImage, myGL.getStartX(), myGL.getStartY(), myGL.getDesiredWidth(),
|
||||
myGL.getDesiredHeight(), this);
|
||||
}
|
||||
// If not profiling invoke the default swapping method implemented in GLCanvas
|
||||
else {
|
||||
super.paint(g);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
forceRepaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to update image if camera has changed position. (usually called by
|
||||
* {@link View#shoot()})
|
||||
*
|
||||
* Warning if this is invoked by a thread external to AWT, this may redraw GL while GL is already
|
||||
* used by AWT, which would turn GL into an inconsistent state.
|
||||
*/
|
||||
@Override
|
||||
public void forceRepaint() {
|
||||
// This makes GLUT invoke the myReshape function
|
||||
|
||||
// SHOULD NOT BE CALLED IF ANIMATOR IS ACTIVE
|
||||
if (TO_BE_CHOOSEN_REPAINT_WITH_FLUSH) {
|
||||
painter.getGL().glFlush();
|
||||
|
||||
// This triggers copy of newly generated picture to the GLCanvas
|
||||
// repaint();
|
||||
} else {
|
||||
processEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED));
|
||||
// equivalent to view.clear(), view.render(), glFlush(), glXSwapBuffers
|
||||
}
|
||||
// INTRODUCE A UNDESIRED RESIZE EVENT (WE ARE NOT RESHAPING VIEWPORT
|
||||
// WAS JUST USED TO FORCE REPAINT
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an atomic rendering of a frame, measure rendering performance and update the status of
|
||||
* rendering (active or not).
|
||||
* rendering (active or not). This method is callback registered in with
|
||||
* {@link GLUT#glutDisplayFunc(String)} which will be called when OpenGL need to update display.
|
||||
* OpenGL updates as soon as the component that GLUT listen to (which is this {@link EmulGLCanvas}
|
||||
* triggers a {@link ComponentEvent.COMPONENT_RESIZED} event.
|
||||
*
|
||||
* Performance measurement can be seen on screen if {@link #setProfileDisplayMethod(boolean)} was
|
||||
* set to true OR can be collected by a {@link Monitor} defined by {@link #add(Monitor)}.
|
||||
*
|
||||
* Method is synchronized to avoid multiple concurrent calls to doDisplay which might make jGL get
|
||||
* crazy with GL state consistency : GL states must be consistent during a complete rendering
|
||||
* pass, and should not be modified by a second rendering pass in the middle of the first one.
|
||||
* This method is synchronized to prevent multiple concurrent calls to doDisplay which might make
|
||||
* jGL get crazy with GL state consistency : GL states must be consistent during a complete
|
||||
* rendering pass, and should not be modified by a second rendering pass in the middle of the
|
||||
* first one. Consistency may be on drawing a complete geometry in appropriate order (glBegin,
|
||||
* glVertex, glEnd) or in the way OpenGL 1.0 fixed pipeline is cleanly handled.
|
||||
*
|
||||
* In addition, the display method has a {@link #isRenderingFlag} so that external components may
|
||||
* known that the canvas is working or not. This allows ignoring a rendering query in case the
|
||||
* canvas is not ready for working. This is different from making use of <code>synchronized</code>
|
||||
* (which lead to a queue of calls to be resolved) in that one may simply not append work to do
|
||||
* according to the status of the canvas. This is used by mouse and thread controller which tend
|
||||
* to send lot of rendering queries faster than the frame rate.
|
||||
* known that the canvas is currently rendering or not. This allows ignoring a rendering query in
|
||||
* case the canvas is not ready for working. This is different from making use of
|
||||
* <code>synchronized</code> (which lead to a queue of calls to be resolved) in that one may
|
||||
* simply not append work to do according to the status of the canvas.
|
||||
*/
|
||||
public synchronized void doDisplay() {
|
||||
//System.out.println("IS RENDERING");
|
||||
public synchronized void doRender() {
|
||||
isRenderingFlag.set(true);
|
||||
|
||||
profileDisplayTimer.tic();
|
||||
|
@ -192,11 +271,11 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
// -------------------------------
|
||||
// PROFILE
|
||||
profileDisplayTimer.toc();
|
||||
|
||||
|
||||
lastRenderingTimeMs = profileDisplayTimer.elapsedMilisecond();
|
||||
|
||||
|
||||
if (profileDisplayMethod) {
|
||||
postRenderProfiling(lastRenderingTimeMs);
|
||||
profile(lastRenderingTimeMs);
|
||||
|
||||
}
|
||||
if (monitor != null) {
|
||||
|
@ -208,16 +287,16 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
|
||||
|
||||
isRenderingFlag.set(false);
|
||||
//System.out.println("DONE RENDERING");
|
||||
// System.out.println("DONE RENDERING");
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected double lastRenderingTimeMs = LAST_RENDER_TIME_UNDEFINED;
|
||||
|
||||
|
||||
public double getLastRenderingTime() {
|
||||
return lastRenderingTimeMs;
|
||||
}
|
||||
|
||||
|
||||
public static final double LAST_RENDER_TIME_UNDEFINED = -1;
|
||||
|
||||
/*
|
||||
|
@ -227,74 +306,15 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
* } }
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
forceRepaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to update image if camera has changed position. (usually called by
|
||||
* {@link View#shoot()})
|
||||
*
|
||||
* Warning if this is invoked by a thread external to AWT, this may redraw
|
||||
* GL while GL is already used by AWT, which would turn GL into an inconsistent state.
|
||||
*/
|
||||
@Override
|
||||
public void forceRepaint() {
|
||||
// This makes GLUT invoke the myReshape function
|
||||
|
||||
// SHOULD NOT BE CALLED IF ANIMATOR IS ACTIVE
|
||||
if (TO_BE_CHOOSEN_REPAINT_WITH_FLUSH) {
|
||||
painter.getGL().glFlush();
|
||||
|
||||
// This triggers copy of newly generated picture to the GLCanvas
|
||||
// repaint();
|
||||
}
|
||||
else {
|
||||
processEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED));
|
||||
// equivalent to view.clear(), view.render(), glFlush(), glXSwapBuffers
|
||||
}
|
||||
// INTRODUCE A UNDESIRED RESIZE EVENT (WE ARE NOT RESHAPING VIEWPORT
|
||||
// WAS JUST USED TO FORCE REPAINT
|
||||
}
|
||||
|
||||
|
||||
public AtomicBoolean getIsRenderingFlag() {
|
||||
return isRenderingFlag;
|
||||
}
|
||||
|
||||
protected void postRenderProfiling(double mili) {
|
||||
int x = 05;
|
||||
int y = 12;
|
||||
|
||||
int line = 1;
|
||||
|
||||
postRenderString("FrameID : " + profileDisplayCount, x, y*line++, Color.BLACK);
|
||||
postRenderString("Render in : " + mili + "ms", x, y*line++, Color.BLACK);
|
||||
postRenderString("Drawables : " + view.getScene().getGraph().getDecomposition().size(), x,
|
||||
y*line++, Color.BLACK);
|
||||
|
||||
for(Drawable d: view.getScene().getGraph().getAll()) {
|
||||
if(d instanceof Scatter) {
|
||||
Scatter s = (Scatter)d;
|
||||
postRenderString("Scatter : " + s.coordinates.length + " points", x,
|
||||
y*(line++), Color.BLACK);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
postRenderString("Canvas Size : " + getWidth() + "x" + getHeight(), x, y*line++, Color.BLACK);
|
||||
|
||||
GL gl = painter.getGL();
|
||||
postRenderString("Viewport Size : " + gl.getContext().Viewport.Width + "x" + gl.getContext().Viewport.Height, x, y * (line++), Color.BLACK);
|
||||
}
|
||||
|
||||
/** Draw a 2d text at the given position */
|
||||
protected void postRenderString(String message, int x, int y, Color color) {
|
||||
painter.getGL().appendTextToDraw(profileDisplayFont, message, x, y, color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
// ******************* RESIZE ******************* //
|
||||
/* *********************************************************************** */
|
||||
/* ****************************** RESIZE ********************************* */
|
||||
/* *********************************************************************** */
|
||||
|
||||
/**
|
||||
* Handle resize events emitted by GLUT.
|
||||
|
@ -314,18 +334,18 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
|
||||
}
|
||||
|
||||
// ******************* MOUSE MOTION ******************* //
|
||||
/* *************************** MOUSE MOTION ***************************** */
|
||||
|
||||
/**
|
||||
* Handle mouse events emitted by GLUT. Most probably not registered as mouse already handled by
|
||||
* Jzy3D.
|
||||
*/
|
||||
public synchronized void doMotion(int x, int y) {
|
||||
doDisplay();
|
||||
doRender();
|
||||
System.out.println("EmulGLCanvas.doMotion!" + profileDisplayCount);
|
||||
}
|
||||
|
||||
// ******************* SCREENSHOTS ******************* //
|
||||
/* *************************** SCREENSHOTS ***************************** */
|
||||
|
||||
@Override
|
||||
public BufferedImage screenshot() {
|
||||
|
@ -411,7 +431,100 @@ public class EmulGLCanvas extends GLCanvas implements IScreenCanvas, IMonitorabl
|
|||
return null;
|
||||
}
|
||||
|
||||
/* ******************* DEBUG ********************* */
|
||||
/* *********************************************************************** */
|
||||
/* ************************** PROFILE AND DEBUG ************************** */
|
||||
/* *********************************************************************** */
|
||||
|
||||
/**
|
||||
* Render profile on top of an image (probably the image of the GL scene) previously collected
|
||||
* while {@link EmulGLCanvas#doRender().
|
||||
*
|
||||
* Painting profile info is synchronized on the profile info list to ensure it is not modified
|
||||
* while drawing (which occurs if synchronization is disabled). Despite we did not observed any
|
||||
* lag due to such rendering, it is important to keep in mind that displaying profile information
|
||||
* requires a synchronized access to this info list which is on the other side synchronized to
|
||||
* protect exporting rendering info of the last call to {@link #doRender()}.
|
||||
*
|
||||
*/
|
||||
protected void paintProfileInfo(BufferedImage glImage) {
|
||||
Graphics2D g2d = (Graphics2D) glImage.getGraphics();
|
||||
g2d.setFont(profileDisplayFont);
|
||||
|
||||
synchronized (profileInfo) {
|
||||
for (ProfileInfo profile : profileInfo) {
|
||||
java.awt.Color awtColor = AWTColor.toAWT(profile.color);
|
||||
g2d.setColor(awtColor);
|
||||
g2d.drawString(profile.message, profile.x, profile.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void profile(double mili) {
|
||||
synchronized (profileInfo) {
|
||||
|
||||
profileClear();
|
||||
|
||||
int x = 10;
|
||||
int y = 12;
|
||||
int line = 1;
|
||||
Color c = Color.BLACK;
|
||||
|
||||
// Rendering info
|
||||
profile("FrameID : " + profileDisplayCount, x, y * line++, c);
|
||||
profile("Render in : " + mili + "ms", x, y * line++, c);
|
||||
|
||||
// Drawables size
|
||||
profile("Drawables : " + view.getScene().getGraph().getDecomposition().size(), x, y * line++,
|
||||
c);
|
||||
|
||||
// Scatters sizes
|
||||
for (Drawable d : view.getScene().getGraph().getAll()) {
|
||||
if (d instanceof Scatter) {
|
||||
Scatter s = (Scatter) d;
|
||||
profile("Scatter : " + s.coordinates.length + " points", x, y * (line++), c);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Canvas size
|
||||
profile("Canvas Size : " + getWidth() + "x" + getHeight(), x, y * line++, c);
|
||||
|
||||
// Viewport size
|
||||
GL gl = painter.getGL();
|
||||
int viewportWidth = gl.getContext().Viewport.Width;
|
||||
int viewportHeight = gl.getContext().Viewport.Height;
|
||||
|
||||
profile("Viewport Size : " + viewportWidth + "x" + viewportHeight, x, y * (line++), c);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Draw a 2d text at the given position */
|
||||
protected void profile(String message, int x, int y, Color c) {
|
||||
// painter.getGL().appendTextToDraw(profileDisplayFont, message, x, y, c.r, c.g, c.b);
|
||||
profileInfo.add(new ProfileInfo(message, x, y, c));
|
||||
}
|
||||
|
||||
protected void profileClear() {
|
||||
profileInfo.clear();
|
||||
}
|
||||
|
||||
class ProfileInfo {
|
||||
String message;
|
||||
int x;
|
||||
int y;
|
||||
Color color;
|
||||
|
||||
public ProfileInfo(String message, int x, int y, Color color) {
|
||||
super();
|
||||
this.message = message;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProfileDisplayMethod() {
|
||||
return profileDisplayMethod;
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 195 KiB |
|
@ -83,8 +83,8 @@ public class TestContinuousAndOnDemandRendering {
|
|||
if (false) {
|
||||
canvas.processEvent(event); // 2.5s
|
||||
canvas.processEvent(event); // 2.5s
|
||||
canvas.doDisplay(); // 10
|
||||
canvas.doDisplay(); // 10*/
|
||||
canvas.doRender(); // 10
|
||||
canvas.doRender(); // 10*/
|
||||
// canvas.doDisplay(); // 10
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.tools.JavaCompiler;
|
||||
import jgl.context.gl_context;
|
||||
import jgl.context.gl_list;
|
||||
import jgl.context.gl_object;
|
||||
|
@ -59,7 +60,7 @@ public class GL {
|
|||
protected gl_list List;
|
||||
|
||||
protected Component canvas;
|
||||
protected Image glImage;
|
||||
protected BufferedImage glImage;
|
||||
protected int StartX = 0;
|
||||
protected int StartY = 0;
|
||||
protected List<TextToDraw> textsToDraw = new ArrayList<>();
|
||||
|
@ -103,7 +104,7 @@ public class GL {
|
|||
return Context.CR;
|
||||
}
|
||||
|
||||
public Image getRenderedImage() {
|
||||
public BufferedImage getRenderedImage() {
|
||||
return glImage;
|
||||
}
|
||||
|
||||
|
@ -114,8 +115,10 @@ public class GL {
|
|||
public double getPixelScaleY() {
|
||||
return pixelScaleY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** the following functions are only for developpers **/
|
||||
/* the following functions are only for developpers
|
||||
public MemoryImageSource glJGetImageSource() {
|
||||
return new MemoryImageSource(Context.Viewport.Width, Context.Viewport.Height, Context.ColorBuffer.Buffer, 0,
|
||||
Context.Viewport.Width);
|
||||
|
@ -123,9 +126,25 @@ public class GL {
|
|||
|
||||
public Image glJGetImage(MemoryImageSource imagesource) {
|
||||
return canvas.createImage(imagesource);
|
||||
}
|
||||
}*/
|
||||
|
||||
public Component glJGetComponent() {
|
||||
public int getStartX() {
|
||||
return StartX;
|
||||
}
|
||||
|
||||
public int getStartY() {
|
||||
return StartY;
|
||||
}
|
||||
|
||||
public int getDesiredWidth() {
|
||||
return desiredWidth;
|
||||
}
|
||||
|
||||
public int getDesiredHeight() {
|
||||
return desiredHeight;
|
||||
}
|
||||
|
||||
public Component glJGetComponent() {
|
||||
return canvas;
|
||||
}
|
||||
|
||||
|
@ -158,11 +177,10 @@ public class GL {
|
|||
* <code>void glXSwapBuffers (Display *dpy, GLXDrawable drawable)</code>
|
||||
*/
|
||||
public void glXSwapBuffers(Graphics g, ImageObserver o) {
|
||||
updatePixelScale(g);
|
||||
|
||||
//System.out.println("UPDATE PIX SCALE");
|
||||
g.drawImage(glImage, StartX, StartY, desiredWidth, desiredHeight, o);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void updatePixelScale(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
|
@ -1764,31 +1782,28 @@ public class GL {
|
|||
desiredY = y;
|
||||
desiredWidth = width;
|
||||
desiredHeight = height;
|
||||
|
||||
// Update pixel scale to guess if HiDPI
|
||||
if(canvas.getGraphics()!=null)
|
||||
updatePixelScale(canvas.getGraphics());
|
||||
|
||||
resetViewport();
|
||||
/*
|
||||
* JavaImageSource = new MemoryImageSource (Context.Viewport.Width,
|
||||
* Context.Viewport.Height, Context.ColorBuffer.Buffer, 0,
|
||||
* Context.Viewport.Width); JavaImageSource.setAnimated (true);
|
||||
* JavaImageSource.setFullBufferUpdates (true); JavaImage =
|
||||
* JavaComponent.createImage (JavaImageSource);
|
||||
*/
|
||||
applyViewport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply viewport according to the latest known expected width/height
|
||||
* and the latest known pixel scales.
|
||||
*/
|
||||
public void resetViewport() {
|
||||
//System.out.println("Viewport : " + autoAdaptToHiDPI + pixelScaleX);
|
||||
|
||||
actualWidth = (int)(desiredWidth * pixelScaleX);
|
||||
actualHeight = (int)(desiredHeight * pixelScaleY);
|
||||
|
||||
if(pixelScaleX>0 && pixelScaleY>0)
|
||||
CC.gl_viewport(desiredX, desiredY, actualWidth, actualHeight);
|
||||
else
|
||||
CC.gl_viewport(desiredX, desiredY, desiredWidth, desiredHeight);
|
||||
public void applyViewport() {
|
||||
if(autoAdaptToHiDPI) {
|
||||
actualWidth = (int)(desiredWidth * pixelScaleX);
|
||||
actualHeight = (int)(desiredHeight * pixelScaleY);
|
||||
}
|
||||
else {
|
||||
actualWidth = desiredWidth;
|
||||
actualHeight = desiredHeight;
|
||||
}
|
||||
CC.gl_viewport(desiredX, desiredY, actualWidth, actualHeight);
|
||||
}
|
||||
|
||||
/** GLvoid glPushMatrix (GLvoid) */
|
||||
|
|
|
@ -39,7 +39,7 @@ public class FrameSwing extends JFrame implements IFrame {
|
|||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
FrameSwing.this.remove((java.awt.Component) FrameSwing.this.chart.getCanvas());
|
||||
FrameSwing.this.chart.stopAnimation();
|
||||
FrameSwing.this.chart.stopAllThreads();
|
||||
FrameSwing.this.chart.dispose();
|
||||
FrameSwing.this.chart = null;
|
||||
FrameSwing.this.dispose();
|
||||
|
|
|
@ -2,11 +2,11 @@ package org.jzy3d.demos.scatter;
|
|||
|
||||
import java.util.Random;
|
||||
import org.jzy3d.chart.Chart;
|
||||
import org.jzy3d.chart.EmulGLSkin;
|
||||
import org.jzy3d.chart.factories.EmulGLChartFactory;
|
||||
import org.jzy3d.colors.Color;
|
||||
import org.jzy3d.maths.Coord3d;
|
||||
import org.jzy3d.plot3d.primitives.Scatter;
|
||||
import org.jzy3d.plot3d.rendering.canvas.EmulGLCanvas;
|
||||
import org.jzy3d.plot3d.rendering.canvas.Quality;
|
||||
|
||||
public class ScatterDemoEmulGL {
|
||||
|
@ -16,15 +16,15 @@ public class ScatterDemoEmulGL {
|
|||
q.setPreserveViewportSize(false); // need java 9+ to enable HiDPI & Retina displays
|
||||
|
||||
Chart chart = new EmulGLChartFactory().newChart(q);
|
||||
chart.getScene().add(scatter());
|
||||
chart.add(scatter(500000));
|
||||
chart.open();
|
||||
chart.addMouseCameraController();
|
||||
|
||||
((EmulGLCanvas) chart.getCanvas()).setProfileDisplayMethod(true); // to print frame rate
|
||||
EmulGLSkin skin = EmulGLSkin.on(chart);
|
||||
skin.getCanvas().setProfileDisplayMethod(true);
|
||||
}
|
||||
|
||||
private static Scatter scatter() {
|
||||
int size = 50000;
|
||||
private static Scatter scatter(int size) {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.jzy3d.demos.surface;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import org.jzy3d.chart.Chart;
|
||||
import org.jzy3d.chart.EmulGLSkin;
|
||||
import org.jzy3d.chart.factories.EmulGLChartFactory;
|
||||
import org.jzy3d.colors.Color;
|
||||
import org.jzy3d.colors.ColorMapper;
|
||||
|
@ -13,10 +14,7 @@ import org.jzy3d.plot3d.builder.Mapper;
|
|||
import org.jzy3d.plot3d.builder.SurfaceBuilder;
|
||||
import org.jzy3d.plot3d.builder.concrete.OrthonormalGrid;
|
||||
import org.jzy3d.plot3d.primitives.Shape;
|
||||
import org.jzy3d.plot3d.primitives.axis.AxisBox;
|
||||
import org.jzy3d.plot3d.rendering.canvas.EmulGLCanvas;
|
||||
import org.jzy3d.plot3d.rendering.canvas.Quality;
|
||||
import org.jzy3d.plot3d.text.renderers.TextBitmapRenderer;
|
||||
import jgl.GLCanvas;
|
||||
|
||||
|
||||
|
@ -36,20 +34,17 @@ public class SurfaceDemoEmulGL {
|
|||
EmulGLChartFactory factory = new EmulGLChartFactory();
|
||||
|
||||
Quality q = Quality.Advanced;
|
||||
q.setAnimated(false); // leave CPU quiet if no need to re-render
|
||||
q.setHiDPIEnabled(true); // need java 9+ to enable HiDPI & Retina displays
|
||||
// (tutorials built with Java 8 for backward compatibility, update your runtime to get HiDPI)
|
||||
Chart chart = factory.newChart(q);
|
||||
chart.add(surface);
|
||||
|
||||
EmulGLCanvas c = (EmulGLCanvas) chart.getCanvas();
|
||||
c.setProfileDisplayMethod(true);
|
||||
c.getGL().setAutoAdaptToHiDPI(true); // need java 9+ to enable HiDPI & Retina displays
|
||||
|
||||
//chart.getAxisLayout().setFont(Font.Helvetica_18);
|
||||
((TextBitmapRenderer)((AxisBox)chart.getView().getAxis()).getTextRenderer()).setFont(Font.TimesRoman_10);
|
||||
chart.open();
|
||||
EmulGLSkin skin = EmulGLSkin.on(chart);
|
||||
skin.getCanvas().setProfileDisplayMethod(true);
|
||||
skin.getAxisTextRenderer().setFont(Font.TimesRoman_10);
|
||||
|
||||
// --------------------------------
|
||||
|
||||
chart.setAnimated(true);
|
||||
chart.open();
|
||||
chart.addMouseCameraController();
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue