4

I am trying to convert a Texture to a Pixmap in LibGDX so I can get all of the pixel data into a ByteBuffer for some experiments, and from what I can tell, I should be able to do this by doing the following :

Pixmap pixmap = textureName.getTexture().getTextureData().consumePixmap();
ByteBuffer data = pixmap.getPixels();

This does seem to return a properly sized Pixmap, and the ByteBuffer does seem to be created just fine, but it is filled entirely with zeros, resulting in a blank, transparent image. This, and a couple other tests, lead me to believe that the Pixmap itself is simply being created as a fully transparent image like that, but I cannot find what may be causing that to happen. Is there some sort of limitation preventing this from working, or am I simply missing something obvious?

Shamrock
  • 436
  • 1
  • 8
  • 17

2 Answers2

7

I believe that API (consumePixmap()) is meant for the Texture class to extract data out of a Pixmap when pushing the Pixmap up to the GPU.
A Libgdx Texture object represents texture data on the GPU, so getting the underlying data to the CPU isn't generally trivial (its the "wrong" direction for a rendering API). See http://code.google.com/p/libgdx/wiki/GraphicsPixmap

Additionally, the documentation on consumePixmap() says it requires a prepare() call before it will work.

To extract pixel information from a texture, you build a FrameBuffer object, render the texture to it, and then extract the pixels (see ScreenUtils).

Its not clear what you're trying to accomplish, but going the other direction (byte array -> Pixmap -> Texture) and then modifying the byte array and re-doing the transformation might work.

P.T.
  • 24,557
  • 7
  • 64
  • 95
  • The texture is created by the user within the application in a simple paint-like interface, so I don't have any of the data before hand. If I could extract the information from the FrameBuffer that I use to create the texture that would be perfect, however I was under the impression that you could only do this from the default FrameBuffer that draws to the screen. In my case it is possible for the texture to go beyond the resolution of the screen, so it would cut off or distort the image going this route. Unfortunately, using Pixmaps themselves for the drawing is not an option either. – Shamrock Feb 25 '13 at 02:33
7

I ran into a similar issue when I wanted to create a PNG of a level made in my level editor. The level is made out of tiles placed by the creator, the entire level is then saved as a .png to be used in the game.

Solved it the way P.T. explains. I hope it is useful for others that run into the same problem.

And in your application configuration: cfg.useGL20 = true; GL20 is required to be able to build the FrameBuffer

        public boolean exportLevel(){   

            //width and height in pixels
            int width = (int)lba.getPrefWidth();
            int height = (int)lba.getPrefHeight();

            //Create a SpriteBatch to handle the drawing.
            SpriteBatch sb = new SpriteBatch();

            //Set the projection matrix for the SpriteBatch.
            Matrix4 projectionMatrix = new Matrix4();

            //because Pixmap has its origin on the topleft and everything else in LibGDX has the origin left bottom
            //we flip the projection matrix on y and move it -height. So it will end up side up in the .png
            projectionMatrix.setToOrtho2D(0, -height, width, height).scale(1,-1,1); 

            //Set the projection matrix on the SpriteBatch
            sb.setProjectionMatrix(projectionMatrix);

            //Create a frame buffer.
            FrameBuffer fb = new FrameBuffer(Pixmap.Format.RGBA8888, width, height, false);

            //Call begin(). So all next drawing will go to the new FrameBuffer.
            fb.begin();

            //Set up the SpriteBatch for drawing.
            sb.begin();

            //Draw all the tiles.
            BuildTileActor[][] btada = lba.getTiles();
            for(BuildTileActor[] btaa: btada){
                for(BuildTileActor bta: btaa){
                    bta.drawTileOnly(sb);
                }
            }

            //End drawing on the SpriteBatch. This will flush() any sprites remaining to be drawn as well.
            sb.end();

            //Then retrieve the Pixmap from the buffer.
            Pixmap pm = ScreenUtils.getFrameBufferPixmap(0, 0, width, height);

            //Close the FrameBuffer. Rendering will resume to the normal buffer.
            fb.end();

            //Save the pixmap as png to the disk.
            FileHandle levelTexture = Gdx.files.local("levelTexture.png");
            PixmapIO.writePNG(levelTexture, pm);

            //Dispose of the resources.
            fb.dispose();
            sb.dispose();

Note: I am new to LibGDX so this may not be the neatest way to do this.

Toast
  • 93
  • 1
  • 6