Hi!
How do I take a screenshot and save it using DevIL?
WiESi
I don't know about the DevIL part (haven't explored it yet), but to grab the framebuffer you need to use glReadPixels, preferably using the ARB/EXT_pixel_buffer_object (which I also haven't explored in detail, but I know it allows asynchronous reads).
glReadPixels works but I don't know how to copy the pixels into DevIL.
WiESi
ilSetPixels ?
http://openil.sourceforge.net/docs/il/f00180.htm
Yeah, good, but what are the following parameters good for?
- ZOff
- Depth
I think format is IL_RGB but I have a problem with the type. In GL there is GL_UNSIGNED_BYTE, but there isn't IL_UNSIGNED_BYTE, only IL_BYTE. And if I use glReadPixels with GL_BYTE and ilSetPixels with IL_BYTE it doesn't work too.
Taken fro mthe OpenIL tutorials...
Quote
Screenshots
Sometimes you want to take a screenshot, such as an in-game shot. ilutOglScreen can perform this for you.
ILboolean ilutOglScreen(ILvoid);
ilutOglScreen loads the viewport's data into the current bound image, for you to decide what to do with it. If you want to automate the process even further and save the viewport's data directly to disk, use:
ILboolean ilutOglScreenie(ILvoid);
ilutOglScreenie does not modify the current bound image at all. This function is very specialized and saves the image to a Targa file with the filename format of screen%d.tga, where %d is a number from 0 to 126. This function will probably not be suited to most developers' preferences.
This might help you...
Chman
yeah - cept those aren't implemented yet ;)
have you called ilTexImage before copying/setting pixels ?
here ya go:
/**
*
*/
public static void takeScreenShot() {
int error = 0;
// create new image and bind it
scratchInt.rewind().limit(1);
IL.ilGenImages(1, scratchInt);
IL.ilBindImage(scratchInt.get(0));
// assert no error
if((error = IL.ilGetError()) != IL.IL_NO_ERROR) {
System.out.println("Error creating devil image for screenshot: " + IL.ilGetString(error));
return;
}
// grap a copy of the current ogl contents
ByteBuffer fb = BufferUtils.createByteBuffer(Display.getDisplayMode().getWidth() * Display.getDisplayMode().getHeight()*3);
GL11.glReadPixels(0, 0, Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight(), GL11.GL_RGB, GL11.GL_BYTE, fb);
// assert no error
if(GL11.glGetError() != GL11.GL_NO_ERROR) {
System.out.println("Error grabing frame buffer: " + GL11.glGetString(error));
IL.ilDeleteImages(1, scratchInt);
return;
}
// copy the contents to the resized devil image
fb.flip();
IL.ilTexImage(Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight(), 1, (byte) 3, IL.IL_RGB, IL.IL_BYTE, fb);
IL.ilSetData(fb);
// assert no error
if((error = IL.ilGetError()) != IL.IL_NO_ERROR) {
System.out.println("Error setting data: " + IL.ilGetString(error));
IL.ilDeleteImages(1, scratchInt);
return;
}
// save the image
IL.ilSaveImage(ssCounter++ +".png");
// assert no error
if((error = IL.ilGetError()) != IL.IL_NO_ERROR) {
System.out.println("Error setting data: " + IL.ilGetString(error));
IL.ilDeleteImages(1, scratchInt);
return;
}
}
Thx, finally I managed to get that stuff running, here the code:
BufferUtils.createBufferT(new int[1]);
ilGenImages(1, BufferUtils.tmpIntB);
ilBindImage(BufferUtils.tmpIntB.get(0));
BufferUtils.createBufferT(new byte[
Display.getDisplayMode().getWidth() *
Display.getDisplayMode().getHeight() * 3]);
glReadPixels(0, 0, Display.getDisplayMode().getWidth(),
Display.getDisplayMode().getHeight(), GL_RGB,
GL11.GL_UNSIGNED_BYTE, BufferUtils.tmpByteB);
ilTexImage(Display.getDisplayMode().getWidth(),
Display.getDisplayMode().getHeight(), 1, (byte)3,
IL_RGB, IL_BYTE, BufferUtils.tmpByteB);
ilEnable(IL_FILE_OVERWRITE);
ilSaveImage("screenshot.bmp");
Here the BufferUtils-class:
import java.nio.*;
public class BufferUtils {
public static ByteBuffer tmpByteB;
public static FloatBuffer tmpFloatB;
public static IntBuffer tmpIntB;
public static ByteBuffer createBuffer(byte... b) {
ByteBuffer a = ByteBuffer.allocateDirect(b.length);
a.order(ByteOrder.nativeOrder());
a.put(b);
a.flip();
return a;
}
public static void createBufferT(byte... b) {
tmpByteB = createBuffer(b);
}
public static FloatBuffer createBuffer(float... f) {
ByteBuffer a = ByteBuffer.allocateDirect(f.length * 4);
a.order(ByteOrder.nativeOrder());
FloatBuffer b = a.asFloatBuffer();
b.put(f);
b.flip();
return b;
}
public static void createBufferT(float... f) {
tmpFloatB = createBuffer(f);
}
public static IntBuffer createBuffer(int... i) {
ByteBuffer a = ByteBuffer.allocateDirect(i.length * 4);
a.order(ByteOrder.nativeOrder());
IntBuffer b = a.asIntBuffer();
b.put(i);
b.flip();
return b;
}
public static void createBufferT(int... i) {
tmpIntB = createBuffer(i);
}
}
Pretty useful, this should be a lot faster than using ImageIO to save the image !
Chman
updated my code, and now uses the overwrite thingy too like Wiesi's.
/** Integer counter for screen shots */
private static int ssCounter = 1;
/** 256 Scratch IntBuffer */
public static final IntBuffer scratchInt = BufferUtils.createIntBuffer(256);
/**
* Creates a screenshot of the current OpenGL buffer
*
* @param overwrite Whether to overwrite existing files
*/
public static void takeScreenShot(boolean overwrite) {
// create new image and bind it
scratchInt.rewind().limit(1);
IL.ilGenImages(1, scratchInt);
IL.ilBindImage(scratchInt.get(0));
// grap a copy of the current ogl contents
ByteBuffer fb =
BufferUtils.createByteBuffer(Display.getDisplayMode().getWidth() *
Display.getDisplayMode().getHeight() *
3);
GL11.glReadPixels(0, 0, Display.getDisplayMode().getWidth(),
Display.getDisplayMode().getHeight(),
GL11.GL_RGB, GL11.GL_BYTE, fb);
// resize image and supply data
IL.ilTexImage(Display.getDisplayMode().getWidth(),
Display.getDisplayMode().getHeight(),
1, (byte) 3, IL.IL_RGB, IL.IL_BYTE, fb);
// save the image
if(overwrite) {
IL.ilEnable(IL.IL_FILE_OVERWRITE);
} else {
IL.ilDisable(IL.IL_FILE_OVERWRITE);
}
IL.ilSaveImage(ssCounter++ + ".png");
// nuke image
IL.ilDeleteImages(1, scratchInt);
}
Hi,
can anybody tell me why the picture that i take with this code is about only half as bright as the original image ??
knoggly
Seems like Matzon used GL_BYTE instead of GL_UNSIGNED_BYTE.
WiESi
hey thanks, now my screenshots are as bright as they should be :D
knoggly
So, I'm still really new to this library. I've been trying to place this code into a dummy project to test out the screen cap functionality.
The datatypes don't seem to match, and I've had to do a bunch of casting etc etc. Is there something I'm missing? I tried creating a local BufferUtils and use the existing, both without success.
can you guys post an example of code that runs with the existing classes and possibly give me some pointers???? I'm a real big fan of LWJGL, but I still have a lot to learn!
Thanks
Jeff