org.ege.utils.ScreenUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.ege.utils.ScreenUtils.java

Source

/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package org.ege.utils;

import java.nio.ByteBuffer;

import org.ege.utils.exception.EasyGEngineRuntimeException;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.BufferUtils;

/** Class with static helper methods that provide access to the default OpenGL FrameBuffer. These methods can be used to get the
 * entire screen content or a portion thereof.
 * 
 * @author espitz */
public class ScreenUtils {

    /** Returns the default framebuffer contents as a {@link TextureRegion} with a width and height equal to the current screen
     * size. The base {@link Texture} always has {@link MathUtils#nextPowerOfTwo} dimensions and RGBA8888 {@link Format}. It can be
     * accessed via {@link TextureRegion#getTexture}. The texture is not managed and has to be reloaded manually on a context loss.
     * The returned TextureRegion is flipped along the Y axis by default. */
    public static TextureRegion getFrameBufferTexture() {
        final int w = Gdx.graphics.getWidth();
        final int h = Gdx.graphics.getHeight();
        return getFrameBufferTexture(0, 0, w, h);
    }

    /** Returns a portion of the default framebuffer contents specified by x, y, width and height as a {@link TextureRegion} with
     * the same dimensions. The base {@link Texture} always has {@link MathUtils#nextPowerOfTwo} dimensions and RGBA8888
     * {@link Format}. It can be accessed via {@link TextureRegion#getTexture}. This texture is not managed and has to be reloaded
     * manually on a context loss. If the width and height specified are larger than the framebuffer dimensions, the Texture will
     * be padded accordingly. Pixels that fall outside of the current screen will have RGBA values of 0.
     * 
     * @param x the x position of the framebuffer contents to capture
     * @param y the y position of the framebuffer contents to capture
     * @param w the width of the framebuffer contents to capture
     * @param h the height of the framebuffer contents to capture */
    public static TextureRegion getFrameBufferTexture(int x, int y, int w, int h) {
        Gdx.gl.glPixelStorei(GL10.GL_PACK_ALIGNMENT, 1);
        final int potW = MathUtils.nextPowerOfTwo(w);
        final int potH = MathUtils.nextPowerOfTwo(h);

        final Pixmap pixmap = new Pixmap(potW, potH, Format.RGBA8888);
        ByteBuffer pixels = pixmap.getPixels();
        Gdx.gl.glReadPixels(x, y, potW, potH, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels);

        Texture texture = new Texture(pixmap);
        TextureRegion textureRegion = new TextureRegion(texture, 0, h, w, -h);
        pixmap.dispose();

        return textureRegion;
    }

    /** Returns the default framebuffer contents as a byte[] array with a length equal to screen width * height * 4. The byte[] will
     * always contain RGBA8888 data. Because of differences in screen and image origins the framebuffer contents should be flipped
     * along the Y axis if you intend save them to disk as a bitmap. Flipping is not a cheap operation, so use this functionality
     * wisely.
     * 
     * @param flipY whether to flip pixels along Y axis */
    public static byte[] getFrameBufferPixels(boolean flipY) {
        final int w = Gdx.graphics.getWidth();
        final int h = Gdx.graphics.getHeight();
        return getFrameBufferPixels(0, 0, w, h, flipY);
    }

    /** Returns a portion of the default framebuffer contents specified by x, y, width and height, as a byte[] array with a length
     * equal to the specified width * height * 4. The byte[] will always contain RGBA8888 data. If the width and height specified
     * are larger than the framebuffer dimensions, the Texture will be padded accordingly. Pixels that fall outside of the current
     * screen will have RGBA values of 0. Because of differences in screen and image origins the framebuffer contents should be
     * flipped along the Y axis if you intend save them to disk as a bitmap. Flipping is not cheap operation, so use this
     * functionality wisely.
     * 
     * @param flipY whether to flip pixels along Y axis */
    public static byte[] getFrameBufferPixels(int x, int y, int w, int h, boolean flipY) {
        Gdx.gl.glPixelStorei(GL10.GL_PACK_ALIGNMENT, 1);
        final ByteBuffer pixels = BufferUtils.newByteBuffer(w * h * 4);
        Gdx.gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels);
        final int numBytes = w * h * 4;
        byte[] lines = new byte[numBytes];
        if (flipY) {
            final int numBytesPerLine = w * 4;
            for (int i = 0; i < h; i++) {
                pixels.position((h - i - 1) * numBytesPerLine);
                pixels.get(lines, i * numBytesPerLine, numBytesPerLine);
            }
        } else {
            pixels.clear();
            pixels.get(lines);
        }
        return lines;

    }

    /** Returns the default framebuffer contents as a byte[] array with a length equal to screen width * height * 4. The byte[] will
     * always contain RGBA8888 data. Because of differences in screen and image origins the framebuffer contents should be flipped
     * along the Y axis if you intend save them to disk as a bitmap. Flipping is not a cheap operation, so use this functionality
     * wisely.
     * 
     * @param flipY whether to flip pixels along Y axis */
    public static byte[] getFrameBufferPixels(byte[] lines, boolean flipY) {
        final int w = Gdx.graphics.getWidth();
        final int h = Gdx.graphics.getHeight();
        return getFrameBufferPixels(lines, 0, 0, w, h, flipY);
    }

    /** Returns a portion of the default framebuffer contents specified by x, y, width and height, as a byte[] array with a length
     * equal to the specified width * height * 4. The byte[] will always contain RGBA8888 data. If the width and height specified
     * are larger than the framebuffer dimensions, the Texture will be padded accordingly. Pixels that fall outside of the current
     * screen will have RGBA values of 0. Because of differences in screen and image origins the framebuffer contents should be
     * flipped along the Y axis if you intend save them to disk as a bitmap. Flipping is not cheap operation, so use this
     * functionality wisely.
     * 
     * @param flipY whether to flip pixels along Y axis */
    public static byte[] getFrameBufferPixels(byte[] lines, int x, int y, int w, int h, boolean flipY) {
        final int numBytes = w * h * 4;

        if (lines.length != numBytes)
            throw new EasyGEngineRuntimeException("Your byte array must have the lenght: w*h*4");

        Gdx.gl.glPixelStorei(GL10.GL_PACK_ALIGNMENT, 1);
        final ByteBuffer pixels = BufferUtils.newByteBuffer(numBytes);
        Gdx.gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels);

        if (flipY) {
            final int numBytesPerLine = w * 4;
            for (int i = 0; i < h; i++) {
                pixels.position((h - i - 1) * numBytesPerLine);
                pixels.get(lines, i * numBytesPerLine, numBytesPerLine);
            }
        } else {
            pixels.clear();
            pixels.get(lines);
        }
        return lines;
    }

    /** Returns the default framebuffer contents as a byte[] array with a length equal to screen width * height * 4. The byte[] will
     * always contain RGBA8888 data. Because of differences in screen and image origins the framebuffer contents should be flipped
     * along the Y axis if you intend save them to disk as a bitmap. Flipping is not a cheap operation, so use this functionality
     * wisely.
     * 
     * @param flipY whether to flip pixels along Y axis */
    public static byte[] getFrameBufferPixels(final ByteBuffer pixels, byte[] lines, boolean flipY) {
        final int w = Gdx.graphics.getWidth();
        final int h = Gdx.graphics.getHeight();
        return getFrameBufferPixels(pixels, lines, 0, 0, w, h, flipY);
    }

    /** Returns a portion of the default framebuffer contents specified by x, y, width and height, as a byte[] array with a length
     * equal to the specified width * height * 4. The byte[] will always contain RGBA8888 data. If the width and height specified
     * are larger than the framebuffer dimensions, the Texture will be padded accordingly. Pixels that fall outside of the current
     * screen will have RGBA values of 0. Because of differences in screen and image origins the framebuffer contents should be
     * flipped along the Y axis if you intend save them to disk as a bitmap. Flipping is not cheap operation, so use this
     * functionality wisely.
     * 
     * @param flipY whether to flip pixels along Y axis */
    public static byte[] getFrameBufferPixels(final ByteBuffer pixels, byte[] lines, int x, int y, int w, int h,
            boolean flipY) {
        final int numBytes = w * h * 4;

        if (lines.length != numBytes || pixels.limit() != numBytes)
            throw new EasyGEngineRuntimeException("Your byte array and byte buffer must have the lenght: w*h*4");

        final int limit = pixels.limit();
        for (int i = 0; i < limit; i++)
            pixels.put(i, (byte) 0);
        pixels.rewind();

        Gdx.gl.glPixelStorei(GL10.GL_PACK_ALIGNMENT, 1);
        Gdx.gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels);

        if (flipY) {
            final int numBytesPerLine = w * 4;
            for (int i = 0; i < h; i++) {
                pixels.position((h - i - 1) * numBytesPerLine);
                pixels.get(lines, i * numBytesPerLine, numBytesPerLine);
            }
        } else {
            pixels.clear();
            pixels.get(lines);
        }
        return lines;
    }

}