I made an improved version of the ScreenshotAppState. Instead of the app name and a shot index being used to name the files, the app name and the current time is used. Also, when two images have the same name, a suffix similar to what windows does is added to the file.
When trying to take screenshots in the game I am currently making, it would always annoy me when screenshots would overwrite each other, so I decided to improve it so that doesn’t happen. Tell me what you think!
package org.mseal.jme3.states;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.post.SceneProcessor;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import com.jme3.texture.FrameBuffer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.BufferUtils;
/**
*
* @author Matthew Seal
*/
public class ScreenshotAppState extends AbstractAppState implements SceneProcessor {
private File dir;
private boolean capture = false;
private String appName;
private String imgFormat = "png";
//render
private Renderer renderer;
private RenderManager rm;
private int width, height;
private ByteBuffer outBuf;
/**
* Set the current path for saving screenshots
*
* @param dir the file directory
*/
public void setPath(File dir) {
this.dir = dir;
}
public File getPath() {
return dir;
}
/**
* Set the current image format and extension, without the period
*
* @param format a string
*/
public void setImageFormat(String format) {
imgFormat = format;
}
public String getImageFormat() {
return imgFormat;
}
/**
* Set the current app name used when naming saved images
*
* @param name the name to use
*/
public void setAppName(String name) {
appName = name;
}
public String getAppName() {
return appName;
}
private final ActionListener listener = new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) {
if (isPressed) {
takeScreenshot();
}
}
};
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
if (appName == null) {
AppSettings settings = app.getContext().getSettings();
appName = settings.getTitle();
}
InputManager inputManager = app.getInputManager();
inputManager.addMapping("takescreenshot", new KeyTrigger(KeyInput.KEY_SYSRQ));
inputManager.addListener(listener, "takescreenshot");
List<ViewPort> vps = app.getRenderManager().getPostViews();
ViewPort last = vps.get(vps.size() - 1);
last.addProcessor(this);
}
@Override
public void update(float tpf) {
}
@Override
public void cleanup() {
super.cleanup();
}
public void takeScreenshot() {
capture = true;
}
public void initialize(RenderManager rm, ViewPort vp) {
this.rm = rm;
this.renderer = rm.getRenderer();
Camera cam = vp.getCamera();
reshape(vp, cam.getWidth(), cam.getHeight());
}
@Override
public boolean isInitialized() {
return super.isInitialized() && renderer != null;
}
public void reshape(ViewPort vp, int w, int h) {
outBuf = BufferUtils.createByteBuffer(w * h * 4);
width = w;
height = h;
}
public void preFrame(float tpf) {
}
public void postQueue(RenderQueue rq) {
}
public void postFrame(FrameBuffer out) {
if (capture) {
capture = false;
Camera cam = rm.getCurrentCamera();
int viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
int viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
int viewW = (int) (cam.getViewPortRight() - cam.getViewPortLeft())
* cam.getWidth();
int viewH = (int) (cam.getViewPortTop() - cam.getViewPortBottom())
* cam.getHeight();
renderer.setViewPort(0, 0, width, height);
renderer.readFrameBuffer(out, outBuf);
renderer.setViewPort(viewX, viewY, viewW, viewH);
File file;
String time = getTime();
if (dir == null) {
file = new File(appName + "-" + time + "." + imgFormat);
} else {
file = new File(dir + File.separator + appName
+ "-" + time + "." + imgFormat);
}
if (file.exists()) {
file = nextFile(file);
}
file.getParentFile().mkdirs();
try {
OutputStream outStream = new FileOutputStream(file);
JmeSystem.writeImageFile(outStream, imgFormat, outBuf, width, height);
outStream.close();
} catch (IOException ex) {
Logger.getLogger(ScreenshotAppState.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
File nextFile(File f) {
File file = f;
int i = 1;
while (file.exists()) {
file = new File(f.getParent() + File.separator
+ filename(f) + " (" + i++ + ")." + imgFormat);
}
return file;
}
String filename(File f) {
String name = f.getName();
int index = name.lastIndexOf(".");
if (index != -1) {
return name.substring(0, index);
} else {
return name;
}
}
String getTime() {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
return dateFormat.format(date);
}
}