* OGLESShaderRenderer.readFrameBuffer() can now read from the main framebuffer in RGBA format.
* Add JmeSystem.writeImageFile() for a platform independent image writing method. Desktop and Android implementations are available. * ScreenshotAppState no longer depends on AWT or Desktop Java, instead it uses JmeSystem.writeImageFile() which will run on Android as well. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9571 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
a3255e4f45
commit
c7186886bc
@ -1271,8 +1271,21 @@ public class OGLESShaderRenderer implements Renderer {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the Color Buffer from OpenGL and stores into the ByteBuffer.
|
||||||
|
* Since jME for Android does not support Frame Buffers yet, make sure the FrameBuffer
|
||||||
|
* passed in is NULL (default) or an exception will be thrown.
|
||||||
|
* Also, make sure to call setViewPort with the appropriate viewport size before
|
||||||
|
* calling readFrameBuffer.
|
||||||
|
* @param fb FrameBuffer (must be NULL)
|
||||||
|
* @param byteBuf ByteBuffer to store the Color Buffer from OpenGL
|
||||||
|
*/
|
||||||
public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) {
|
public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) {
|
||||||
logger.warning("readFrameBuffer is not supported.");
|
if (fb != null) {
|
||||||
|
throw new IllegalArgumentException("FrameBuffer is not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
GLES20.glReadPixels(vpX, vpY, vpW, vpH, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuf);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf){
|
public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf){
|
||||||
|
@ -2,19 +2,21 @@ package com.jme3.system.android;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import com.jme3.asset.AndroidAssetManager;
|
import com.jme3.asset.AndroidAssetManager;
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.audio.AudioRenderer;
|
import com.jme3.audio.AudioRenderer;
|
||||||
import com.jme3.audio.android.AndroidAudioRenderer;
|
import com.jme3.audio.android.AndroidAudioRenderer;
|
||||||
import com.jme3.system.AppSettings;
|
import com.jme3.system.*;
|
||||||
import com.jme3.system.JmeContext;
|
|
||||||
import com.jme3.system.JmeContext.Type;
|
import com.jme3.system.JmeContext.Type;
|
||||||
import com.jme3.system.JmeSystemDelegate;
|
import com.jme3.util.AndroidScreenshots;
|
||||||
import com.jme3.system.Platform;
|
|
||||||
import com.jme3.util.JmeFormatter;
|
import com.jme3.util.JmeFormatter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.logging.Handler;
|
import java.util.logging.Handler;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -23,6 +25,22 @@ public class JmeAndroidSystem extends JmeSystemDelegate {
|
|||||||
|
|
||||||
private static Activity activity;
|
private static Activity activity;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
|
||||||
|
Bitmap bitmapImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
AndroidScreenshots.convertScreenShot(imageData, bitmapImage);
|
||||||
|
Bitmap.CompressFormat compressFormat;
|
||||||
|
if (format.equals("png")) {
|
||||||
|
compressFormat = Bitmap.CompressFormat.PNG;
|
||||||
|
} else if (format.equals("jpg")) {
|
||||||
|
compressFormat = Bitmap.CompressFormat.JPEG;
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Only 'png' and 'jpg' formats are supported on Android");
|
||||||
|
}
|
||||||
|
bitmapImage.compress(compressFormat, 95, outStream);
|
||||||
|
bitmapImage.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("bulletjme");
|
System.loadLibrary("bulletjme");
|
||||||
|
42
engine/src/android/com/jme3/util/AndroidScreenshots.java
Normal file
42
engine/src/android/com/jme3/util/AndroidScreenshots.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.jme3.util;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public final class AndroidScreenshots {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AndroidScreenshots.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert OpenGL GLES20.GL_RGBA to Bitmap.Config.ARGB_8888 and store result
|
||||||
|
* in a Bitmap
|
||||||
|
*
|
||||||
|
* @param buf ByteBuffer that has the pixel color data from OpenGL
|
||||||
|
* @param bitmapImage Bitmap to be used after converting the data
|
||||||
|
*/
|
||||||
|
public static void convertScreenShot(ByteBuffer buf, Bitmap bitmapImage) {
|
||||||
|
int width = bitmapImage.getWidth();
|
||||||
|
int height = bitmapImage.getHeight();
|
||||||
|
int size = width * height;
|
||||||
|
|
||||||
|
// Grab data from ByteBuffer as Int Array to manipulate data and send to image
|
||||||
|
int[] data = new int[size];
|
||||||
|
buf.asIntBuffer().get(data);
|
||||||
|
|
||||||
|
// convert from GLES20.GL_RGBA to Bitmap.Config.ARGB_8888
|
||||||
|
// ** need to swap RED and BLUE **
|
||||||
|
for (int idx = 0; idx < data.length; idx++) {
|
||||||
|
int initial = data[idx];
|
||||||
|
int pb = (initial >> 16) & 0xff;
|
||||||
|
int pr = (initial << 16) & 0x00ff0000;
|
||||||
|
int pix1 = (initial & 0xff00ff00) | pr | pb;
|
||||||
|
data[idx] = pix1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenGL and Bitmap have opposite starting points for Y axis (top vs bottom)
|
||||||
|
// Need to write the data in the image from the bottom to the top
|
||||||
|
// Use size-width to indicate start with last row and increment by -width for each row
|
||||||
|
bitmapImage.setPixels(data, size - width, -width, 0, 0, width, height);
|
||||||
|
}
|
||||||
|
}
|
@ -35,8 +35,11 @@ import com.jme3.asset.AssetManager;
|
|||||||
import com.jme3.audio.AudioRenderer;
|
import com.jme3.audio.AudioRenderer;
|
||||||
import com.jme3.input.SoftTextDialogInput;
|
import com.jme3.input.SoftTextDialogInput;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -93,6 +96,11 @@ public class JmeSystem {
|
|||||||
return systemDelegate.getSoftTextDialogInput();
|
return systemDelegate.getSoftTextDialogInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
|
||||||
|
checkDelegate();
|
||||||
|
systemDelegate.writeImageFile(outStream, format, imageData, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
public static AssetManager newAssetManager(URL configFile) {
|
public static AssetManager newAssetManager(URL configFile) {
|
||||||
checkDelegate();
|
checkDelegate();
|
||||||
return systemDelegate.newAssetManager(configFile);
|
return systemDelegate.newAssetManager(configFile);
|
||||||
|
@ -35,8 +35,11 @@ import com.jme3.asset.AssetManager;
|
|||||||
import com.jme3.audio.AudioRenderer;
|
import com.jme3.audio.AudioRenderer;
|
||||||
import com.jme3.input.SoftTextDialogInput;
|
import com.jme3.input.SoftTextDialogInput;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -96,6 +99,8 @@ public abstract class JmeSystemDelegate {
|
|||||||
return softTextDialogInput;
|
return softTextDialogInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
|
||||||
|
|
||||||
public abstract AssetManager newAssetManager(URL configFile);
|
public abstract AssetManager newAssetManager(URL configFile);
|
||||||
|
|
||||||
public abstract AssetManager newAssetManager();
|
public abstract AssetManager newAssetManager();
|
||||||
|
@ -10,17 +10,17 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.Renderer;
|
import com.jme3.renderer.Renderer;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.renderer.queue.RenderQueue;
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.system.JmeSystem;
|
||||||
import com.jme3.texture.FrameBuffer;
|
import com.jme3.texture.FrameBuffer;
|
||||||
import com.jme3.util.BufferUtils;
|
import com.jme3.util.BufferUtils;
|
||||||
import com.jme3.util.Screenshots;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
public class ScreenshotAppState extends AbstractAppState implements ActionListener, SceneProcessor {
|
public class ScreenshotAppState extends AbstractAppState implements ActionListener, SceneProcessor {
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
|
|||||||
private ByteBuffer outBuf;
|
private ByteBuffer outBuf;
|
||||||
private String appName;
|
private String appName;
|
||||||
private int shotIndex = 0;
|
private int shotIndex = 0;
|
||||||
private BufferedImage awtImage;
|
private int width, height;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize(AppStateManager stateManager, Application app) {
|
public void initialize(AppStateManager stateManager, Application app) {
|
||||||
@ -66,8 +66,9 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void reshape(ViewPort vp, int w, int h) {
|
public void reshape(ViewPort vp, int w, int h) {
|
||||||
outBuf = BufferUtils.createByteBuffer(w*h*4);
|
outBuf = BufferUtils.createByteBuffer(w * h * 4);
|
||||||
awtImage = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
|
width = w;
|
||||||
|
height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void preFrame(float tpf) {
|
public void preFrame(float tpf) {
|
||||||
@ -82,12 +83,21 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
|
|||||||
shotIndex++;
|
shotIndex++;
|
||||||
|
|
||||||
renderer.readFrameBuffer(out, outBuf);
|
renderer.readFrameBuffer(out, outBuf);
|
||||||
Screenshots.convertScreenShot(outBuf, awtImage);
|
File file = new File(appName + shotIndex + ".png").getAbsoluteFile();
|
||||||
|
OutputStream outStream = null;
|
||||||
try {
|
try {
|
||||||
ImageIO.write(awtImage, "png", new File(appName + shotIndex + ".png"));
|
outStream = new FileOutputStream(file);
|
||||||
} catch (IOException ex){
|
JmeSystem.writeImageFile(outStream, "png", outBuf, width, height);
|
||||||
|
} catch (IOException ex) {
|
||||||
logger.log(Level.SEVERE, "Error while saving screenshot", ex);
|
logger.log(Level.SEVERE, "Error while saving screenshot", ex);
|
||||||
|
} finally {
|
||||||
|
if (outStream != null){
|
||||||
|
try {
|
||||||
|
outStream.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error while saving screenshot", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,17 @@ import com.jme3.asset.AssetNotFoundException;
|
|||||||
import com.jme3.asset.DesktopAssetManager;
|
import com.jme3.asset.DesktopAssetManager;
|
||||||
import com.jme3.audio.AudioRenderer;
|
import com.jme3.audio.AudioRenderer;
|
||||||
import com.jme3.system.JmeContext.Type;
|
import com.jme3.system.JmeContext.Type;
|
||||||
|
import com.jme3.util.Screenshots;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
@ -58,6 +63,13 @@ public class JmeDesktopSystem extends JmeSystemDelegate {
|
|||||||
return new DesktopAssetManager(configFile);
|
return new DesktopAssetManager(configFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {
|
||||||
|
BufferedImage awtImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
|
Screenshots.convertScreenShot(imageData, awtImage);
|
||||||
|
ImageIO.write(awtImage, format, outStream);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AssetManager newAssetManager() {
|
public AssetManager newAssetManager() {
|
||||||
return new DesktopAssetManager(null);
|
return new DesktopAssetManager(null);
|
||||||
|
@ -33,6 +33,12 @@ public final class Screenshots {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flips the image along the Y axis and converts BGRA to ABGR
|
||||||
|
*
|
||||||
|
* @param bgraBuf
|
||||||
|
* @param out
|
||||||
|
*/
|
||||||
public static void convertScreenShot(ByteBuffer bgraBuf, BufferedImage out){
|
public static void convertScreenShot(ByteBuffer bgraBuf, BufferedImage out){
|
||||||
WritableRaster wr = out.getRaster();
|
WritableRaster wr = out.getRaster();
|
||||||
DataBufferByte db = (DataBufferByte) wr.getDataBuffer();
|
DataBufferByte db = (DataBufferByte) wr.getDataBuffer();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user