org.jmangos.tools.openGL.TextureLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.jmangos.tools.openGL.TextureLoader.java

Source

/*******************************************************************************
 * Copyright (C) 2013 JMaNGOS <http://jmangos.org/>
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package org.jmangos.tools.openGL;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import org.lwjgl.Sys;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.GLU;

/**
 * Modified from code originally written by:
 * 
 * @author Kevin Glass
 * @author Brian Matzon
 * 
 */
public class TextureLoader {

    /** The table of textures that have been loaded in this loader */
    private final HashMap<String, Texture> table = new HashMap<String, Texture>();

    /** The colour model including alpha for the GL image */
    public ColorModel glAlphaColorModel;

    /** The colour model for the GL image */
    private final ColorModel glColorModel;

    private final int target = GL11.GL_TEXTURE_2D;
    private final int dstPixelFormat = GL11.GL_RGBA;
    // private int dstPixelFormat = GL13.GL_COMPRESSED_RGBA;
    private final int minFilter = GL11.GL_LINEAR;
    private final int magFilter = GL11.GL_LINEAR;

    /**
     * Create a new texture loader based on the game panel
     * 
     * @param gl
     *        The GL content in which the textures should be loaded
     */
    public TextureLoader() {

        // dstPixelFormat = 4;

        this.glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                new int[] { 8, 8, 8, 8 }, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);

        this.glColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
                new int[] { 8, 8, 8, 0 }, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
    }

    /**
     * Create a new texture ID
     * 
     * @return A new texture ID
     */
    private int createTextureID() {

        final IntBuffer tmp = createIntBuffer(1);
        try {
            GL11.glGenTextures(tmp);
        } catch (final NullPointerException e) {
            // e.printStackTrace();
            Sys.alert("Error",
                    "Your system is not capable of running this game.\nPlease make sure your video drivers are current.");
            System.exit(0);
        }
        return tmp.get(0);
    }

    /**
     * Load a texture
     * 
     * @param resourceName
     *        The location of the resource to load
     * @return The loaded texture
     * @throws IOException
     *         Indicates a failure to access the resource
     */
    public Texture getTexture(final String resourceName, final boolean injar) throws IOException {

        Texture tex = this.table.get(resourceName);

        if (tex != null) {
            return tex;
        }

        tex = getTexture(resourceName, injar, this.target, // target
                this.dstPixelFormat, // dst pixel format
                this.minFilter, // min filter (unused)
                this.magFilter);

        this.table.put(resourceName, tex);

        return tex;
    }

    /**
     * Load a texture into OpenGL from a image reference on disk.
     * 
     * @param resourceName
     *        The location of the resource to load
     * @param target
     *        The GL target to load the texture against
     * @param dstPixelFormat
     *        The pixel format of the screen
     * @param minFilter
     *        The minimising filter
     * @param magFilter
     *        The magnification filter
     * @return The loaded texture
     * @throws IOException
     *         Indicates a failure to access the resource
     */
    public Texture getTexture(final String resourceName, final boolean injar, final int target,
            final int dstPixelFormat, final int minFilter, final int magFilter) throws IOException {

        int srcPixelFormat = 0;

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

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

        final BufferedImage bufferedImage = loadImage(resourceName, injar);
        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
        final ByteBuffer textureBuffer = convertImageData(bufferedImage, texture);

        if (target == GL11.GL_TEXTURE_2D) {
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
            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 );
         */

        GLU.gluBuild2DMipmaps(target, dstPixelFormat, get2Fold(bufferedImage.getWidth()),
                get2Fold(bufferedImage.getHeight()), srcPixelFormat, GL11.GL_UNSIGNED_BYTE, textureBuffer);

        return texture;
    }

    /**
     * Get the closest greater power of 2 to the fold number
     * 
     * @param fold
     *        The target number
     * @return The power of 2
     */
    private int get2Fold(final int fold) {

        int ret = 2;
        while (ret < fold) {
            ret *= 2;
        }
        return ret;
    }

    /**
     * Convert the buffered image to a texture
     * 
     * @param bufferedImage
     *        The image to convert to a texture
     * @param texture
     *        The texture to store the data into
     * @return A buffer containing the data
     */
    @SuppressWarnings("rawtypes")
    private ByteBuffer convertImageData(final BufferedImage bufferedImage, final Texture texture) {

        ByteBuffer imageBuffer = null;
        WritableRaster raster;
        BufferedImage texImage;

        int texWidth = 2;
        int texHeight = 2;

        // find the closest power of 2 for the width and height
        // of the produced texture
        while (texWidth < bufferedImage.getWidth()) {
            texWidth *= 2;
        }
        while (texHeight < bufferedImage.getHeight()) {
            texHeight *= 2;
        }

        texture.setTextureHeight(texHeight);
        texture.setTextureWidth(texWidth);

        // create a raster that can be used by OpenGL as a source
        // for a texture
        if (bufferedImage.getColorModel().hasAlpha()) {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 4, null);
            texImage = new BufferedImage(this.glAlphaColorModel, raster, false, new Hashtable());
        } else {
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 3, null);
            texImage = new BufferedImage(this.glColorModel, raster, false, new Hashtable());
        }

        // copy the source image into the produced image
        final Graphics g = texImage.getGraphics();
        g.setColor(new Color(0f, 0f, 0f, 0f));
        g.fillRect(0, 0, texWidth, texHeight);
        g.drawImage(bufferedImage, 0, 0, null);

        // build a byte buffer from the temporary image
        // that be used by OpenGL to produce a texture.
        final byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();

        imageBuffer = ByteBuffer.allocateDirect(data.length);
        imageBuffer.order(ByteOrder.nativeOrder());
        imageBuffer.put(data, 0, data.length);
        imageBuffer.flip();

        return imageBuffer;
    }

    /**
     * Load a given resource as a buffered image
     * 
     * @param ref
     *        The location of the resource to load
     * @return The loaded buffered image
     * @throws IOException
     *         Indicates a failure to find a resource
     */
    private BufferedImage loadImage(final String ref, final boolean injar) throws IOException {

        // URL url = TextureLoader.class.getClassLoader().getResource(ref);

        // if (url == null) {
        // throw new IOException("Cannot find: "+ref);
        // }

        if (injar) {
            final BufferedImage bufferedImage = ImageIO
                    .read(new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(ref)));
            return bufferedImage;
        } else {
            final File file = new File(ref);
            BufferedImage bufferedImage = null;
            try {
                bufferedImage = ImageIO.read(file);
            } catch (final IOException e) {
                System.out.println("Could not load texture: " + ref);
            }
            return bufferedImage;
        }

    }

    /**
     * Creates an integer buffer to hold specified ints - strictly a utility
     * method
     * 
     * @param size
     *        how many int to contain
     * @return created IntBuffer
     */
    protected IntBuffer createIntBuffer(final int size) {

        final ByteBuffer temp = ByteBuffer.allocateDirect(4 * size);
        temp.order(ByteOrder.nativeOrder());

        return temp.asIntBuffer();
    }

    // ////////////////////////////////////////////////
    // // Added for BufferedImage Support /////////////
    // ////////////////////////////////////////////////
    /**
     * Load a texture
     * 
     * @param resourceName
     *        The location of the resource to load
     * @return The loaded texture
     * @throws IOException
     *         Indicates a failure to access the resource
     */
    public Texture getTexture(final String resourceName, final BufferedImage resourceImage) throws IOException {

        Texture tex = this.table.get(resourceName);

        if (tex != null) {
            return tex;
        }

        tex = getTexture(resourceImage, this.target, // target
                this.dstPixelFormat, // dst pixel format
                this.minFilter, // min filter (unused)
                this.magFilter);

        this.table.put(resourceName, tex);

        return tex;
    }

    /**
     * Load a texture into OpenGL from a BufferedImage
     * 
     * @param resourceName
     *        The location of the resource to load
     * @param target
     *        The GL target to load the texture against
     * @param dstPixelFormat
     *        The pixel format of the screen
     * @param minFilter
     *        The minimising filter
     * @param magFilter
     *        The magnification filter
     * @return The loaded texture
     * @throws IOException
     *         Indicates a failure to access the resource
     */
    public Texture getTexture(final BufferedImage resourceimage, final int target, final int dstPixelFormat,
            final int minFilter, final int magFilter) throws IOException {

        int srcPixelFormat = 0;

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

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

        final BufferedImage bufferedImage = resourceimage;
        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
        final ByteBuffer textureBuffer = convertImageData(bufferedImage, texture);

        if (target == GL11.GL_TEXTURE_2D) {
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
            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 );
         */

        GLU.gluBuild2DMipmaps(target, dstPixelFormat, get2Fold(bufferedImage.getWidth()),
                get2Fold(bufferedImage.getHeight()), srcPixelFormat, GL11.GL_UNSIGNED_BYTE, textureBuffer);

        return texture;
    }

    // ////////////////////////////////////////////////////////////////
    // ////////////////////////////////////////////////////////////////
    // ////////////////////////////////////////////////////////////////

    // ////////////////////////////////////////////////
    // // Added for No MipMapping Support /////////////
    // ////////////////////////////////////////////////
    /**
     * Load a texture
     * 
     * @param resourceName
     *        The location of the resource to load
     * @return The loaded texture
     * @throws IOException
     *         Indicates a failure to access the resource
     */
    public Texture getNMMTexture(final String resourceName, final BufferedImage resourceImage) throws IOException {

        Texture tex = this.table.get(resourceName);

        if (tex != null) {
            return tex;
        }

        tex = getNMMTexture(resourceImage, this.target, // target
                this.dstPixelFormat, // dst pixel format
                GL11.GL_NEAREST, // min filter (unused)
                GL11.GL_LINEAR);

        this.table.put(resourceName, tex);

        return tex;
    }

    /**
     * Load a texture into OpenGL from a BufferedImage
     * 
     * @param resourceName
     *        The location of the resource to load
     * @param target
     *        The GL target to load the texture against
     * @param dstPixelFormat
     *        The pixel format of the screen
     * @param minFilter
     *        The minimising filter
     * @param magFilter
     *        The magnification filter
     * @return The loaded texture
     * @throws IOException
     *         Indicates a failure to access the resource
     */
    public Texture getNMMTexture(final BufferedImage resourceimage, final int target, final int dstPixelFormat,
            final int minFilter, final int magFilter) throws IOException {

        int srcPixelFormat = 0;

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

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

        final BufferedImage bufferedImage = resourceimage;
        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
        final ByteBuffer textureBuffer = convertImageData(bufferedImage, texture);

        if (target == GL11.GL_TEXTURE_2D) {
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
            GL11.glTexParameteri(target, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
            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;
    }

    // ////////////////////////////////////////////////////////////////
    // ////////////////////////////////////////////////////////////////
    // ////////////////////////////////////////////////////////////////

}