Taking screenshots and saving them

Started by WiESi, December 29, 2004, 13:08:53

Previous topic - Next topic

WiESi

Hi!

How do I take a screenshot and save it using DevIL?

WiESi

spasi

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).

WiESi

glReadPixels works but I don't know how to copy the pixels into DevIL.

WiESi


WiESi

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.

Chman

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

Matzon

yeah - cept those aren't implemented yet ;)

have you called ilTexImage before copying/setting pixels ?

Matzon

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;
    }
	}

WiESi

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);
	}
}

Chman

Pretty useful, this should be a lot faster than using ImageIO to save the image !

Chman

Matzon

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);
	}

knoggly

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

WiESi

Seems like Matzon used GL_BYTE instead of GL_UNSIGNED_BYTE.

WiESi

knoggly

hey thanks, now my screenshots are as bright as they should be  :D

knoggly

grayfuse

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