com.golden.gamedev.engine.lwjgl.LWJGLGraphics.java Source code

Java tutorial

Introduction

Here is the source code for com.golden.gamedev.engine.lwjgl.LWJGLGraphics.java

Source

/*
 * Copyright (c) 2008 Golden T Studios.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.golden.gamedev.engine.lwjgl;

// JFC
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.WeakHashMap;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;

import com.golden.gamedev.engine.graphics.NullGraphics;
import com.golden.gamedev.object.GameFont;
import com.golden.gamedev.object.font.AdvanceBitmapFont;
import com.golden.gamedev.util.FontUtil;
import com.golden.gamedev.util.ImageUtil;
import com.golden.gamedev.util.Utility;

/**
 * Fake Graphics2D for OpenGL LWJGL.
 */
public class LWJGLGraphics extends NullGraphics {

    // used to convert from a AffineTransform to a OpenGL matrix
    private static double affineMatrix[] = new double[3 * 3];

    // OpenGL matrix
    private static FloatBuffer glMatrix = BufferUtils.createFloatBuffer(16);

    // display dimension
    private static IntBuffer display = BufferUtils.createIntBuffer(16);

    /** ************************************************************************* */
    /** ***************************** CONSTRUCTOR ******************************* */
    /** ************************************************************************* */

    public LWJGLGraphics() {
        this.textureLoader = new TextureLoader();

        this.fontMap = new WeakHashMap();
    }

    /**
     * Returns texture loader used to load textures by this OpenGL renderer.
     */
    public TextureLoader getTextureLoader() {
        return this.textureLoader;
    }

    /** ************************************************************************* */
    /** ************************* CLASS VARIABLES ******************************* */
    /** ************************************************************************* */

    private static final Rectangle NULL_RECTANGLE = new Rectangle();

    private TextureLoader textureLoader;

    private Color color = Color.BLACK;
    private Color background = Color.BLACK;

    private Composite composite;

    private Font font;
    private WeakHashMap fontMap;
    private Graphics2D g;
    private int gap;

    private Rectangle clipArea;

    /** ************************************************************************* */
    /** ************************** OPENGL RENDERING ***************************** */
    /** ************************************************************************* */

    /** ************************************************************************* */
    /** ************************* IMAGE RENDERING ******************************* */
    /** ************************************************************************* */

    public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
        this.startPainting();

        // store the current model matrix
        GL11.glPushMatrix();

        // bind to the appropriate texture for this sprite
        Texture texture = this.textureLoader.getTexture((BufferedImage) img);
        texture.bind();

        // translate to the right location and prepare to draw
        GL11.glTranslatef(x, y, 0);

        // draw a quad textured to match the sprite
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex2f(0, 0);

        GL11.glTexCoord2f(0, texture.getHeight());
        GL11.glVertex2f(0, texture.getImageHeight());

        GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());
        GL11.glVertex2f(texture.getImageWidth(), texture.getImageHeight());

        GL11.glTexCoord2f(texture.getWidth(), 0);
        GL11.glVertex2f(texture.getImageWidth(), 0);
        GL11.glEnd();

        // restore the model view matrix to prevent contamination
        GL11.glPopMatrix();

        this.endPainting();

        return true;
    }

    public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
        this.startPainting();

        GL11.glPushMatrix();

        Texture texture = this.textureLoader.getTexture((BufferedImage) img);
        texture.bind();

        GL11.glTranslatef(x, y, 0);

        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex2f(0, 0);

        GL11.glTexCoord2f(0, texture.getHeight());
        GL11.glVertex2f(0, height);

        GL11.glTexCoord2f(texture.getWidth(), texture.getHeight());
        GL11.glVertex2f(width, height);

        GL11.glTexCoord2f(texture.getWidth(), 0);
        GL11.glVertex2f(width, 0);
        GL11.glEnd();

        GL11.glPopMatrix();

        this.endPainting();

        return true;
    }

    public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
            ImageObserver observer) {
        this.startPainting();

        Texture texture = this.textureLoader.getTexture((BufferedImage) img);
        texture.bind();

        float tx0 = ((float) sx1 / texture.getTextureWidth());
        float tx1 = ((float) sx2 / texture.getTextureWidth());
        float ty0 = ((float) sy1 / texture.getTextureHeight());
        float ty1 = ((float) sy2 / texture.getTextureHeight());

        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(tx0, ty0);
        GL11.glVertex2f(dx1, dy1);

        GL11.glTexCoord2f(tx1, ty0);
        GL11.glVertex2f(dx2, dy1);

        GL11.glTexCoord2f(tx1, ty1);
        GL11.glVertex2f(dx2, dy2);

        GL11.glTexCoord2f(tx0, ty1);
        GL11.glVertex2f(dx1, dy2);
        GL11.glEnd();

        this.endPainting();

        return true;
    }

    public boolean drawImage(Image img, AffineTransform transform, ImageObserver obs) {
        transform.getMatrix(LWJGLGraphics.affineMatrix);

        LWJGLGraphics.glMatrix.rewind();
        LWJGLGraphics.glMatrix.put((float) LWJGLGraphics.affineMatrix[0]).put((float) LWJGLGraphics.affineMatrix[1])
                .put(0).put(0);
        LWJGLGraphics.glMatrix.put((float) LWJGLGraphics.affineMatrix[2]).put((float) LWJGLGraphics.affineMatrix[3])
                .put(0).put(0);
        LWJGLGraphics.glMatrix.put(0).put(0).put(1).put(0);
        LWJGLGraphics.glMatrix.put((float) LWJGLGraphics.affineMatrix[4]).put((float) LWJGLGraphics.affineMatrix[5])
                .put(0).put(1);
        LWJGLGraphics.glMatrix.rewind();

        GL11.glPushMatrix();
        GL11.glMultMatrix(LWJGLGraphics.glMatrix);

        this.drawImage(img, 0, 0, null);

        GL11.glPopMatrix();

        return true;
    }

    /** ************************************************************************* */
    /** ************************** TEXT RENDERING ******************************* */
    /** ************************************************************************* */

    public void drawString(String str, int x, int y) {
        GameFont font = this.getGameFont();

        font.drawString(this, str, x, y + this.gap);
    }

    /** ************************************************************************* */
    /** ************************ PRIMITIVE RENDERING **************************** */
    /** ************************************************************************* */

    public void fillRect(int x, int y, int width, int height) {
        this.drawRect(x, y, width, height, GL11.GL_QUADS, this.color);
    }

    public void drawRect(int x, int y, int width, int height) {
        this.drawRect(x, y, width, height, GL11.GL_LINE_LOOP, this.color);
    }

    public void clearRect(int x, int y, int width, int height) {
        this.drawRect(x, y, width, height, GL11.GL_QUADS, this.background);
    }

    public void drawLine(int x1, int y1, int x2, int y2) {
        GL11.glDisable(GL11.GL_TEXTURE_2D);

        GL11.glColor4f((float) this.color.getRed() / 255f, (float) this.color.getGreen() / 255f,
                (float) this.color.getBlue() / 255f, (float) this.color.getAlpha() / 255f);
        GL11.glLineWidth(1.0f);

        GL11.glBegin(GL11.GL_LINES);
        GL11.glVertex2f(x1, y1);
        GL11.glVertex2f(x2, y2);
        GL11.glEnd();

        GL11.glColor3f(1.0f, 1.0f, 1.0f);

        GL11.glEnable(GL11.GL_TEXTURE_2D);
    }

    /** ************************************************************************* */
    /** ************************ GET / SET OPERATION **************************** */
    /** ************************************************************************* */

    public void setColor(Color c) {
        this.color = c;
    }

    public Color getColor() {
        return this.color;
    }

    public void setBackground(Color color) {
        this.background = color;
    }

    public Color getBackground() {
        return this.background;
    }

    public void setComposite(Composite comp) {
        this.composite = comp;
    }

    public Composite getComposite() {
        return this.composite;
    }

    public Font getFont() {
        if (this.font == null) {
            this.setFont(new Font("Dialog", Font.PLAIN, 12));
        }

        return this.font;
    }

    public void setFont(Font font) {
        if (font != null) {
            this.font = font;

            FontMetrics fm = this.getFontMetrics(font);
            this.gap = fm.getDescent() - fm.getMaxAscent() - fm.getMaxDescent() - fm.getLeading();
        }
    }

    public FontMetrics getFontMetrics() {
        return this.getFontMetrics(this.getFont());
    }

    public FontMetrics getFontMetrics(Font f) {
        if (this.g == null) {
            // dummy graphics only to get system font metrics
            this.g = ImageUtil.createImage(1, 1).createGraphics();
        }

        return this.g.getFontMetrics(f);
    }

    public void dispose() {
    }

    /** ************************************************************************* */
    /** *********************** GRAPHICS OPERATION ****************************** */
    /** ************************************************************************* */

    public void clipRect(int x, int y, int width, int height) {
        this.setClip(x, y, width, height);
    }

    public void setClip(int x, int y, int width, int height) {
        GL11.glGetInteger(GL11.GL_VIEWPORT, LWJGLGraphics.display);

        GL11.glEnable(GL11.GL_SCISSOR_TEST);
        GL11.glScissor(x, LWJGLGraphics.display.get(3) - y - height, width, height);

        if (this.clipArea == null) {
            this.clipArea = LWJGLGraphics.NULL_RECTANGLE;
        }

        this.clipArea.setBounds(x, y, width, height);
    }

    public Shape getClip() {
        return this.clipArea;
    }

    public void setClip(Shape clip) {
        this.clipArea = (Rectangle) clip;

        if (this.clipArea == null) {
            GL11.glDisable(GL11.GL_SCISSOR_TEST);

        } else {
            this.setClip(this.clipArea.x, this.clipArea.y, this.clipArea.width, this.clipArea.height);
        }
    }

    /** ************************************************************************* */
    /** ************************** PRIVATE METHODS ****************************** */
    /** ************************************************************************* */

    private void startPainting() {
        if (this.composite != null) {
            try {
                GL11.glColor4f(1.0f, 1.0f, 1.0f, ((AlphaComposite) this.composite).getAlpha());
            } catch (ClassCastException e) {
            }
        }
    }

    private void endPainting() {
        if (this.composite != null) {
            GL11.glColor3f(1.0f, 1.0f, 1.0f);
        }
    }

    private void drawRect(int x, int y, int width, int height, int type, Color col) {
        GL11.glDisable(GL11.GL_TEXTURE_2D);

        GL11.glColor4f((float) col.getRed() / 255f, (float) col.getGreen() / 255f, (float) col.getBlue() / 255f,
                (float) col.getAlpha() / 255f);
        GL11.glLineWidth(1.0f);

        GL11.glBegin(type);
        GL11.glVertex2f(x, y);
        GL11.glVertex2f(x + width, y);
        GL11.glVertex2f(x + width, y + height);
        GL11.glVertex2f(x, y + height);
        GL11.glEnd();

        GL11.glColor3f(1.0f, 1.0f, 1.0f);

        GL11.glEnable(GL11.GL_TEXTURE_2D);
    }

    private GameFont getGameFont() {
        Font f = this.getFont();
        GameFont gameFont = (GameFont) this.fontMap.get(f);

        if (gameFont == null) {
            BufferedImage bitmap = FontUtil.createBitmapFont(f, Color.BLACK);

            int delimiter = bitmap.getRGB(0, 0); // pixel <0,0> : delimiter
            int[] width = new int[100]; // assumption : 100 letter
            int ctr = 0;
            int last = 0; // last width point

            for (int i = 1; i < bitmap.getWidth(); i++) {
                if (bitmap.getRGB(i, 0) == delimiter) {
                    // found delimiter
                    width[ctr++] = i - last;
                    last = i;

                    if (ctr >= width.length) {
                        width = (int[]) Utility.expand(width, 50);
                    }
                }
            }

            // create bitmap font
            BufferedImage[] imagefont = new BufferedImage[ctr];
            int height = bitmap.getHeight() - 1;
            int w = 0;
            for (int i = 0; i < imagefont.length; i++) {
                imagefont[i] = bitmap.getSubimage(w, 1, width[i], height);

                w += width[i];
            }

            gameFont = new AdvanceBitmapFont(imagefont);

            this.fontMap.put(f, gameFont);
        }

        return gameFont;
    }

}