white/inverted textures when using glCopyTexImage2D [SOLVED]

Started by manji, August 26, 2009, 21:12:15

Previous topic - Next topic

manji

I am trying to copy my screen(everything rendered in the display, or part of it) to a texture. I use this function:
public void screenToTexture(){
    GL11.glViewport(0, 0, 512, 512);    
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
    GL11.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, 0, 0, 512, 512, 0);
    GL11.glViewport(0, 0, 1024, 768);
}

When later I bind this texture and map it on a square, all I get is a white texture. I know I am doing something wrong, could someone plz guide me?
toyWars game blog: http://toywars.wordpress.com/

bobjob

you could always try testing glReadPixels instead. I have had problems with glCopyTestImage2D in the past

manji

toyWars game blog: http://toywars.wordpress.com/

broumbroum

Quote from: manji on August 26, 2009, 21:12:15
(...)
   GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
    GL11.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, 0, 0, 512, 512, 0);

When later I bind this texture and map it on a square, all I get is a white texture. I know I am doing something wrong, could someone plz guide me?
You may have to invert textureID with the copyTexImage2D name, which is 0 i guess. Is that the screen you want to copy ? screen is 0, then must be bound instead.

manji

@broumbroum I am sorry, but I didn't get what you suggest. If you say that I should bind the right texture, I already do that. Before rendering a cube, I am sure I bind the texture that this textureID refers to. textureID is defined by:
public int createTextureID(){ 
   IntBuffer tmp = createIntBuffer(1); 
   GL11.glGenTextures(tmp);
   return tmp.get(0);
}

and before drawing the cube, I do:
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);


@bobjob I tried the function I saw here http://lwjgl.org/forum/index.php/topic,867.0.html that uses glReadPixels to copy the screen to BufferedImage and then I copy it to a texture. I did saw an inverted texture of my screen once, so there is a hope here. I will check it more thoroughly later and will post the results.
toyWars game blog: http://toywars.wordpress.com/

broumbroum

I might explain further : What you want to do is copy the screen and render with a texture. 
Quote from: glcopyteximage2d-docglCopyTexImage2D defines a two-dimensional texture image
     with pixels from the current GL_READ_BUFFER.
that is you have to generate a buffer name, bind it : glbindbuffer to gl_pixel_pack_buffer and then read your screen frame buffer :
Quote from: glreadpixelsIf a non-zero named buffer object is bound to the GL_PIXEL_PACK_BUFFER target (see glBindBuffer) while a block of pixels is requested, data is treated as a byte offset into the buffer object's data store rather than a pointer to client memory.
then obviously the pixel data will stay in the newly created buffer for which it can be requested the copy to a texture.
genbuffer > bindbuffer > readpixels > copyteximage2d > bindtexture > render the cube :P

manji

@broumbroum I really thank very much for your time, but I am not so sure how to implement this right now ???. So, for the time being I'll stick to the following.

I have gathered some functions I have found here and there, and the best I can do is copy the screen to a texture, but inverted. The procedure is the following:
At first, I take a screenshot in a BufferedImage object:
public BufferedImage screenShot(int width, int height){
    BufferedImage screenshot = null;
     // allocate space for RBG pixels
     ByteBuffer fb = GLApp.allocBytes(width * height * 3);
     int[] pixels = new int[width * height];
     int bindex;
     // grab a copy of the current frame contents as RGB
     GL11.glReadPixels(0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, fb);
     // convert RGB data in ByteBuffer to integer array
     for (int i=0; i < pixels.length; i++) {
         bindex = i * 3;
         pixels[i] =
             ((fb.get(bindex) << 16))  +
             ((fb.get(bindex+1) << 8))  +
             ((fb.get(bindex+2) << 0));
     }
     // Create a BufferedImage with the RGB pixels then save as PNG
     try {
         screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
         screenshot.setRGB(0, 0, width, height, pixels, 0, width);
         //javax.imageio.ImageIO.write(screenshot, "png", new File("screenshot_test.png"));
     }
     catch (Exception e) {
         System.out.println("ScreenShot() exception: " +e);
     }
     return screenshot;
}

Then I convert this byteBuffer to a Texture(from spaceinvaders source) object:
public Texture getTexture(BufferedImage image,
                          int target,
                          int dstPixelFormat,
                          int minFilter,
                          int magFilter) throws IOException
{
    int srcPixelFormat = 0;

    // create the texture ID for this texture
    int textureID = createTextureID();
    Texture texture = new Texture(target,textureID);

    // bind this texture
    GL11.glBindTexture(target, textureID);

    BufferedImage bufferedImage = image;
    texture.setWidth(bufferedImage.getWidth());
    texture.setHeight(bufferedImage.getHeight());

    if (bufferedImage.getColorModel().hasAlpha()) {
        srcPixelFormat = GL11.GL_RGBA;
    } else {
        srcPixelFormat = GL11.GL_RGB;
    }

    // convert that image into a byte buffer of texture data
    ByteBuffer textureBuffer = convertImageData(bufferedImage,texture);

    if (target == GL11.GL_TEXTURE_2D)
    {
        GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
        GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);

    }

    // produce a texture from the byte buffer
    GL11.glTexImage2D(target,
                  0,
                  dstPixelFormat,
                  get2Fold(bufferedImage.getWidth()),
                  get2Fold(bufferedImage.getHeight()),
                  0,
                  srcPixelFormat,
                  GL11.GL_UNSIGNED_BYTE,
                  textureBuffer );

    return texture;
}

And finally I bind the texture before rendering. The weird thing is that the texture is rendered fire, but inverted. Any clue?
toyWars game blog: http://toywars.wordpress.com/

bobjob

the java co-ordinate system is different to the OpenGL one.

so it may be that you are copying pixels from the bottom left in opengl
then drawing them from the top-right in bufferedImage object.

broumbroum

Quote from: manji on August 27, 2009, 15:51:00
@broumbroum I really thank very much for your time, but I am not so sure how to implement this right now ???. So, for the time being I'll stick to the following.
And finally I bind the texture before rendering. The weird thing is that the texture is rendered fire, but inverted. Any clue?
It's alright, yet I think openGL has some issues where it is hard to find your way out because opengl is not as handy as java. 8)
Quote
so it may be that you are copying pixels from the bottom left in opengl
then drawing them from the top-right in bufferedImage object.
then it might be the case to flip the buffer returned by converttobufferedimage.

manji

I guess you mean flipping the BufferedImage object. I did that, using things from here, http://www.exampledepot.com/egs/java.awt.image/Flip.html and here http://www.java2s.com/Code/Java/Advanced-Graphics/FlippingaBufferedImage.htm, and also using GLImage class http://potatoland.org/code/gl/javadoc/glapp/GLImage.html#flipY(java.awt.image.BufferedImage . The same inverted image appears. If I make any progress, I will post again.

Update: No wait, my mistake, this thing actually works! :
// Flip the image vertically
AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
tx.translate(0, -img.getHeight(null));
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
img = op.filter(img, null);

Thank you very much both of you! There is still an anomaly in the lower side of the texture(smth like clamping), but I hope I will fix it.
toyWars game blog: http://toywars.wordpress.com/