mirror of https://github.com/rusefi/jzy3d-api.git
Add exporter to swing and awt native canvas. Let drawable text have a point on the value and smart layout according to camera
This commit is contained in:
parent
4ff9276764
commit
787e9c27be
|
@ -5,11 +5,25 @@ package org.jzy3d.io;
|
|||
import java.awt.image.BufferedImage;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.jzy3d.maths.TicToc;
|
||||
|
||||
/**
|
||||
* The {@link AbstractImageExporter} can receive {@link BufferedImage} image from a renderer to
|
||||
* export them somewhere.
|
||||
*
|
||||
* The exporter as a target frame rate. If it receive images at a higher rate, exceeding images will
|
||||
* be dropped. If it receive images as a lower rate, it will repeat the last known image until the
|
||||
* new one arrives.
|
||||
*
|
||||
* The exporter uses its own thread to handle export image queries without slowing down the caller
|
||||
* thread.
|
||||
*
|
||||
*
|
||||
* @author Martin Pernollet
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractImageExporter implements AWTImageExporter {
|
||||
protected static int DEFAULT_FRAME_RATE_MS = 1000;
|
||||
|
||||
|
@ -137,35 +151,36 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
|
|||
}
|
||||
|
||||
protected void scheduleImageExport(BufferedImage image, boolean isLastImage) {
|
||||
//try {
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// try {
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
numberSubmittedImages.incrementAndGet();
|
||||
numberOfPendingImages.incrementAndGet();
|
||||
numberSubmittedImages.incrementAndGet();
|
||||
numberOfPendingImages.incrementAndGet();
|
||||
|
||||
// System.out.println("Adding image to GIF (pending tasks " + pendingTasks.get() + ")");
|
||||
// pendingTasks.incrementAndGet();
|
||||
// System.out.println("Adding image to GIF (pending tasks " + pendingTasks.get() + ")");
|
||||
// pendingTasks.incrementAndGet();
|
||||
|
||||
/*
|
||||
* Graphics2D graphics = (Graphics2D)image.getGraphics();
|
||||
* AWTGraphicsUtils.configureRenderingHints(graphics);
|
||||
* graphics.setColor(java.awt.Color.GRAY);
|
||||
* graphics.drawString("Powered by Jzy3D (martin@jzy3d.org)", image.getWidth()/2+40,
|
||||
* image.getHeight()-20); graphics.dispose();
|
||||
*/
|
||||
/*
|
||||
* Graphics2D graphics = (Graphics2D)image.getGraphics();
|
||||
* AWTGraphicsUtils.configureRenderingHints(graphics);
|
||||
* graphics.setColor(java.awt.Color.GRAY);
|
||||
* graphics.drawString("Powered by Jzy3D (martin@jzy3d.org)", image.getWidth()/2+40,
|
||||
* image.getHeight()-20); graphics.dispose();
|
||||
*/
|
||||
|
||||
doAddFrameByRunnable(image, isLastImage);
|
||||
doAddFrameByRunnable(image, isLastImage);
|
||||
|
||||
numberOfPendingImages.decrementAndGet();
|
||||
numberOfPendingImages.decrementAndGet();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
/*} catch (RejectedExecutionException e) {
|
||||
System.err.println("AbstractImageExporter : should stop appending image (unregister me from canvas!");
|
||||
}*/
|
||||
});
|
||||
/*
|
||||
* } catch (RejectedExecutionException e) { System.err.
|
||||
* println("AbstractImageExporter : should stop appending image (unregister me from canvas!"); }
|
||||
*/
|
||||
}
|
||||
|
||||
protected abstract void doAddFrameByRunnable(BufferedImage image, boolean isLastImage);
|
||||
|
@ -191,7 +206,7 @@ public abstract class AbstractImageExporter implements AWTImageExporter {
|
|||
public AtomicInteger getNumberOfSkippedImages() {
|
||||
return numberOfSkippedImages;
|
||||
}
|
||||
|
||||
|
||||
public AtomicInteger getNumberOfSavedImages() {
|
||||
return numberOfSavedImages;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.jzy3d.maths.TicToc;
|
|||
public class GifExporter extends AbstractImageExporter implements AWTImageExporter {
|
||||
protected File outputFile;
|
||||
protected AnimatedGifEncoder encoder;
|
||||
|
||||
protected TicToc timer = new TicToc();
|
||||
|
||||
public GifExporter(File outputFile) {
|
||||
this(outputFile, DEFAULT_FRAME_RATE_MS); // 1 frame per sec
|
||||
|
@ -25,15 +27,25 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
|
|||
this.encoder.setDelay(gifFrameRateMs);
|
||||
this.encoder.setRepeat(1000);
|
||||
this.encoder.setQuality(8);
|
||||
|
||||
this.timer.tic();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAddFrameByRunnable(BufferedImage image, boolean isLastImage) {
|
||||
if (debug)
|
||||
System.out.println("GifExporter : Adding image to GIF " + numberSubmittedImages.get());
|
||||
|
||||
|
||||
if (debug) {
|
||||
timer.toc();
|
||||
System.out.println("GifExporter : Adding image to GIF " + numberSubmittedImages.get() + " at " + timer.elapsedSecond());
|
||||
}
|
||||
|
||||
encoder.addFrame(image);
|
||||
|
||||
if (debug) {
|
||||
timer.toc();
|
||||
System.out.println("GifExporter : Adding image to GIF " + numberSubmittedImages.get() + " at " + timer.elapsedSecond());
|
||||
}
|
||||
|
||||
if (isLastImage) {
|
||||
closeOutput();
|
||||
}
|
||||
|
@ -41,6 +53,7 @@ public class GifExporter extends AbstractImageExporter implements AWTImageExport
|
|||
numberOfSavedImages.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeOutput() {
|
||||
encoder.finish();
|
||||
|
||||
|
|
|
@ -332,7 +332,7 @@ public class Chart {
|
|||
canvas.screenshot(file);
|
||||
}
|
||||
|
||||
public Object screenshot() throws IOException {
|
||||
public Object screenshot() {
|
||||
return canvas.screenshot();
|
||||
}
|
||||
|
||||
|
|
|
@ -142,5 +142,7 @@ public interface ICanvas {
|
|||
*/
|
||||
@Deprecated
|
||||
public static boolean ALLOW_WATCH_PIXEL_SCALE = true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ import org.jzy3d.maths.Coord3d;
|
|||
import org.jzy3d.painters.Font;
|
||||
import org.jzy3d.painters.IPainter;
|
||||
import org.jzy3d.plot3d.primitives.Drawable;
|
||||
import org.jzy3d.plot3d.primitives.Point;
|
||||
import org.jzy3d.plot3d.primitives.axis.layout.AxisLayout;
|
||||
import org.jzy3d.plot3d.text.ITextRenderer;
|
||||
import org.jzy3d.plot3d.text.align.Horizontal;
|
||||
import org.jzy3d.plot3d.text.align.Vertical;
|
||||
import org.jzy3d.plot3d.text.renderers.TextRenderer;
|
||||
import org.jzy3d.plot3d.transform.Transform;
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,12 @@ public class DrawableTextWrapper extends Drawable {
|
|||
|
||||
protected AxisLayout axisLayout;
|
||||
protected Font defaultFont = Font.Helvetica_12;
|
||||
|
||||
protected boolean pointDisplayed = false;
|
||||
protected Point point;
|
||||
|
||||
protected boolean flipHorizontalAlignWithViewpoint = false;
|
||||
|
||||
|
||||
public DrawableTextWrapper(ITextRenderer renderer) {
|
||||
this("", new Coord3d(), Color.BLACK, renderer);
|
||||
|
@ -42,8 +48,14 @@ public class DrawableTextWrapper extends Drawable {
|
|||
public DrawableTextWrapper(String txt, Coord3d position, Color color, ITextRenderer renderer) {
|
||||
super();
|
||||
this.renderer = renderer;
|
||||
this.point = new Point();
|
||||
|
||||
configure(txt, position, color, Horizontal.CENTER, Vertical.CENTER);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************************/
|
||||
|
||||
|
@ -56,12 +68,34 @@ public class DrawableTextWrapper extends Drawable {
|
|||
font = axisLayout.getFont();
|
||||
}
|
||||
|
||||
BoundingBox3d box = renderer.drawText(painter, font, txt, position, rotation, halign, valign,
|
||||
|
||||
Horizontal fixedHAlign = flipHorizontalAlignIfEnabled(painter);
|
||||
//Coord3d fixedSceneOffset = flipHorizontalAlignWithViewpoint?sceneOffset/*.mul(-1)*/:sceneOffset;
|
||||
|
||||
BoundingBox3d box = renderer.drawText(painter, font, txt, position, rotation, fixedHAlign, valign,
|
||||
color, screenOffset, sceneOffset);
|
||||
if (box != null)
|
||||
bbox = box.scale(new Coord3d(1 / 10, 1 / 10, 1 / 10));
|
||||
else
|
||||
bbox = null;
|
||||
|
||||
point.draw(painter);
|
||||
}
|
||||
|
||||
public Horizontal flipHorizontalAlignIfEnabled(IPainter painter) {
|
||||
boolean left = painter.getCamera().side(position);
|
||||
|
||||
Horizontal fixedHAlign = halign;
|
||||
if(left && flipHorizontalAlignWithViewpoint) {
|
||||
if(halign==Horizontal.LEFT) {
|
||||
fixedHAlign = Horizontal.RIGHT;
|
||||
}
|
||||
else if(halign==Horizontal.RIGHT) {
|
||||
fixedHAlign = Horizontal.LEFT;
|
||||
}
|
||||
|
||||
}
|
||||
return fixedHAlign;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,6 +121,7 @@ public class DrawableTextWrapper extends Drawable {
|
|||
|
||||
public void setPosition(Coord3d position) {
|
||||
this.position = position;
|
||||
this.point.setCoord(position);
|
||||
}
|
||||
|
||||
public Coord3d getPosition() {
|
||||
|
@ -96,6 +131,14 @@ public class DrawableTextWrapper extends Drawable {
|
|||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public boolean isFlipHorizontalAlignWithViewpoint() {
|
||||
return flipHorizontalAlignWithViewpoint;
|
||||
}
|
||||
|
||||
public void setFlipHorizontalAlignWithViewpoint(boolean flipHorizontalAlignWithViewpoint) {
|
||||
this.flipHorizontalAlignWithViewpoint = flipHorizontalAlignWithViewpoint;
|
||||
}
|
||||
|
||||
public Horizontal getHalign() {
|
||||
return halign;
|
||||
|
@ -161,6 +204,18 @@ public class DrawableTextWrapper extends Drawable {
|
|||
public void setDefaultFont(Font defaultFont) {
|
||||
this.defaultFont = defaultFont;
|
||||
}
|
||||
|
||||
public Point getPoint() {
|
||||
return point;
|
||||
}
|
||||
|
||||
public boolean isPointDisplayed() {
|
||||
return pointDisplayed;
|
||||
}
|
||||
|
||||
public void setPointDisplayed(boolean pointDisplayed) {
|
||||
this.pointDisplayed = pointDisplayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
@ -9,6 +9,10 @@ public class OffscreenChartFactory extends AWTChartFactory {
|
|||
int width;
|
||||
int height;
|
||||
|
||||
public OffscreenChartFactory() {
|
||||
this(800,600);
|
||||
}
|
||||
|
||||
public OffscreenChartFactory(int width, int height) {
|
||||
super(new OffscreenWindowFactory());
|
||||
this.width = width;
|
||||
|
|
|
@ -13,11 +13,13 @@ import org.jzy3d.awt.AWTHelper;
|
|||
import org.jzy3d.chart.IAnimator;
|
||||
import org.jzy3d.chart.factories.IChartFactory;
|
||||
import org.jzy3d.chart.factories.NativePainterFactory;
|
||||
import org.jzy3d.io.AWTImageExporter;
|
||||
import org.jzy3d.maths.Coord2d;
|
||||
import org.jzy3d.maths.Dimension;
|
||||
import org.jzy3d.painters.IPainter;
|
||||
import org.jzy3d.plot3d.GPUInfo;
|
||||
import org.jzy3d.plot3d.rendering.scene.Scene;
|
||||
import org.jzy3d.plot3d.rendering.view.AWTRenderer3d;
|
||||
import org.jzy3d.plot3d.rendering.view.Renderer3d;
|
||||
import org.jzy3d.plot3d.rendering.view.View;
|
||||
import com.jogamp.nativewindow.ScalableSurface;
|
||||
|
@ -343,5 +345,20 @@ public class CanvasAWT extends GLCanvas implements IScreenCanvas, INativeCanvas
|
|||
return true;
|
||||
}
|
||||
|
||||
public AWTImageExporter getExporter() {
|
||||
if(renderer!=null && renderer instanceof AWTRenderer3d) {
|
||||
AWTRenderer3d r = (AWTRenderer3d)renderer;
|
||||
return r.getExporter();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setExporter(AWTImageExporter exporter) {
|
||||
if(renderer!=null && renderer instanceof AWTRenderer3d) {
|
||||
AWTRenderer3d r = (AWTRenderer3d)renderer;
|
||||
r.setExporter(exporter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.jzy3d.plot3d.rendering.view;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import org.jzy3d.io.AWTImageExporter;
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GLEventListener;
|
||||
import com.jogamp.opengl.GLProfile;
|
||||
|
@ -14,6 +15,8 @@ import com.jogamp.opengl.util.awt.AWTGLReadBufferUtil;
|
|||
public class AWTRenderer3d extends Renderer3d {
|
||||
|
||||
protected BufferedImage bufferedImage;
|
||||
protected AWTImageExporter exporter;
|
||||
protected AWTGLReadBufferUtil screenshotMaker;
|
||||
|
||||
public AWTRenderer3d() {
|
||||
super();
|
||||
|
@ -25,6 +28,9 @@ public class AWTRenderer3d extends Renderer3d {
|
|||
|
||||
public AWTRenderer3d(View view, boolean traceGL, boolean debugGL) {
|
||||
super(view, traceGL, debugGL);
|
||||
|
||||
screenshotMaker = new AWTGLReadBufferUtil(GLProfile.getGL2GL3(), true);
|
||||
|
||||
}
|
||||
|
||||
/********************* SCREENSHOTS ***********************/
|
||||
|
@ -36,13 +42,33 @@ public class AWTRenderer3d extends Renderer3d {
|
|||
@Override
|
||||
protected void renderScreenshotIfRequired(GL gl) {
|
||||
if (doScreenshotAtNextDisplay) {
|
||||
AWTGLReadBufferUtil screenshot = new AWTGLReadBufferUtil(GLProfile.getGL2GL3(), true);
|
||||
screenshot.readPixels(gl, true);
|
||||
image = screenshot.getTextureData();
|
||||
bufferedImage = screenshot.readPixelsToBufferedImage(gl, true);
|
||||
screenshotMaker.readPixels(gl, true);
|
||||
image = screenshotMaker.getTextureData();
|
||||
bufferedImage = screenshotMaker.readPixelsToBufferedImage(gl, true);
|
||||
|
||||
doScreenshotAtNextDisplay = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportImageIfRequired(GL gl) {
|
||||
if(exporter!=null) {
|
||||
|
||||
screenshotMaker.readPixels(gl, true);
|
||||
|
||||
exporter.export(screenshotMaker.readPixelsToBufferedImage(gl, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public AWTImageExporter getExporter() {
|
||||
return exporter;
|
||||
}
|
||||
|
||||
public void setExporter(AWTImageExporter exporter) {
|
||||
this.exporter = exporter;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -97,9 +97,10 @@ public class Renderer3d implements GLEventListener {
|
|||
view.clear();
|
||||
view.render();
|
||||
|
||||
exportImageIfRequired(canvas.getGL());
|
||||
|
||||
renderScreenshotIfRequired(canvas.getGL());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,6 +108,7 @@ public class Renderer3d implements GLEventListener {
|
|||
lastRenderingTimeMs = profileDisplayTimer.elapsedMilisecond();
|
||||
}
|
||||
|
||||
|
||||
/** Called when the {@link GLAutoDrawable} is resized. */
|
||||
@Override
|
||||
public void reshape(GLAutoDrawable canvas, int x, int y, int width, int height) {
|
||||
|
@ -163,6 +165,11 @@ public class Renderer3d implements GLEventListener {
|
|||
doScreenshotAtNextDisplay = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void exportImageIfRequired(GL gl) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,12 +15,14 @@ import org.jzy3d.awt.AWTHelper;
|
|||
import org.jzy3d.chart.IAnimator;
|
||||
import org.jzy3d.chart.factories.IChartFactory;
|
||||
import org.jzy3d.chart.factories.NativePainterFactory;
|
||||
import org.jzy3d.io.AWTImageExporter;
|
||||
import org.jzy3d.maths.Coord2d;
|
||||
import org.jzy3d.maths.Dimension;
|
||||
import org.jzy3d.painters.IPainter;
|
||||
import org.jzy3d.painters.NativeDesktopPainter;
|
||||
import org.jzy3d.plot3d.GPUInfo;
|
||||
import org.jzy3d.plot3d.rendering.scene.Scene;
|
||||
import org.jzy3d.plot3d.rendering.view.AWTRenderer3d;
|
||||
import org.jzy3d.plot3d.rendering.view.Renderer3d;
|
||||
import org.jzy3d.plot3d.rendering.view.View;
|
||||
import com.jogamp.nativewindow.ScalableSurface;
|
||||
|
@ -329,4 +331,22 @@ public class CanvasSwing extends GLJPanel implements IScreenCanvas, INativeCanva
|
|||
public boolean isNative() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public AWTImageExporter getExporter() {
|
||||
if(renderer!=null && renderer instanceof AWTRenderer3d) {
|
||||
AWTRenderer3d r = (AWTRenderer3d)renderer;
|
||||
return r.getExporter();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setExporter(AWTImageExporter exporter) {
|
||||
if(renderer!=null && renderer instanceof AWTRenderer3d) {
|
||||
AWTRenderer3d r = (AWTRenderer3d)renderer;
|
||||
r.setExporter(exporter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -191,11 +191,7 @@ public class MultiChartPanel extends JPanel {
|
|||
}
|
||||
|
||||
public JPanel getChartScreenshotAsComponent(Chart chart) {
|
||||
try {
|
||||
chart.screenshot();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
AWTRenderer3d renderer = (AWTRenderer3d) ((INativeCanvas) chart.getCanvas()).getRenderer();
|
||||
BufferedImage i = renderer.getLastScreenshotImage();
|
||||
JPanel component = new ImagePanel(i);
|
||||
|
|
Loading…
Reference in New Issue