game.engine.frame.handlers.FlashMessageHandler.java Source code

Java tutorial

Introduction

Here is the source code for game.engine.frame.handlers.FlashMessageHandler.java

Source

/**
 * Copyright (c) 2010 Martin Geisse
 * <p>
 * This file is distributed under the terms of the MIT license.
 */

package game.engine.frame.handlers;

import game.engine.frame.AbstractFrameHandler;
import game.engine.frame.BreakFrameLoopException;
import game.engine.gfx.Font;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;

import java.util.concurrent.ConcurrentLinkedQueue;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL14.glWindowPos2i;

/**
 * Displays one or more messages for a certain time. Messages are rendered
 * using a {@link Font}. Each message will stay for the same configurable
 * time. Multiple messages will be stacked vertically if necessary.
 *
 * Stacked messages will be drawn downwards, starting at a configurable
 * raster position. Subclasses might want to implement {@link #prepareOpenGlState()}
 * since there is no way to predict OpenGL state in a frame handler.
 */
public class FlashMessageHandler extends AbstractFrameHandler {

    /**
     * the font
     */
    private Font font;

    /**
     * the displayTime
     */
    private long displayTime;

    /**
     * the fadeTime
     */
    private long fadeTime;

    /**
     * the leftOffset
     */
    private int leftOffset;

    /**
     * the topOffset
     */
    private int topOffset;

    /**
     * the queue
     */
    private final ConcurrentLinkedQueue<Entry> queue;

    /**
     * Constructor.
     * @param font the font to use
     */
    public FlashMessageHandler(final Font font) {
        this.font = font;
        this.displayTime = 3000;
        this.fadeTime = 1000;
        this.leftOffset = 0;
        this.topOffset = 0;
        this.queue = new ConcurrentLinkedQueue<FlashMessageHandler.Entry>();
    }

    /**
     * Getter method for the font.
     * @return the font
     */
    public final Font getFont() {
        return font;
    }

    /**
     * Setter method for the font.
     * @param font the font to set
     */
    public final void setFont(final Font font) {
        this.font = font;
    }

    /**
     * Getter method for the displayTime.
     * @return the displayTime
     */
    public final long getDisplayTime() {
        return displayTime;
    }

    /**
     * Setter method for the displayTime.
     * @param displayTime the displayTime to set
     */
    public final void setDisplayTime(final long displayTime) {
        this.displayTime = displayTime;
    }

    /**
     * Getter method for the fadeTime.
     * @return the fadeTime
     */
    public final long getFadeTime() {
        return fadeTime;
    }

    /**
     * Setter method for the fadeTime.
     * @param fadeTime the fadeTime to set
     */
    public final void setFadeTime(final long fadeTime) {
        this.fadeTime = fadeTime;
    }

    /**
     * Getter method for the leftOffset.
     * @return the leftOffset
     */
    public int getLeftOffset() {
        return leftOffset;
    }

    /**
     * Setter method for the leftOffset.
     * @param leftOffset the leftOffset to set
     */
    public void setLeftOffset(final int leftOffset) {
        this.leftOffset = leftOffset;
    }

    /**
     * Getter method for the topOffset.
     * @return the topOffset
     */
    public int getTopOffset() {
        return topOffset;
    }

    /**
     * Setter method for the topOffset.
     * @param topOffset the topOffset to set
     */
    public void setTopOffset(final int topOffset) {
        this.topOffset = topOffset;
    }

    /**
     * Adds a message to show to the user.
     * @param message the message to add
     */
    public final void addMessage(final String message) {
        queue.add(new Entry(System.currentTimeMillis(), message));
    }

    /**
     * This method may be implemented to prepare the necessary OpenGL
     * state, such as the current raster position, drawing color, and so on.
     */
    protected void prepareOpenGlState() {
    }

    /* (non-Javadoc)
     * @see game.engine.frame.AbstractFrameHandler#draw()
     */
    @Override
    public void draw() {
        prepareOpenGlState();
        int height = Display.getHeight();
        final long now = System.currentTimeMillis();
        int i = 0;
        glBindTexture(GL_TEXTURE_2D, 0);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        GL11.glPixelTransferf(GL11.GL_RED_SCALE, 0.0f);
        GL11.glPixelTransferf(GL11.GL_GREEN_SCALE, 0.0f);
        GL11.glPixelTransferf(GL11.GL_BLUE_SCALE, 0.0f);
        GL11.glPixelTransferf(GL11.GL_RED_BIAS, 1.0f);
        GL11.glPixelTransferf(GL11.GL_GREEN_BIAS, 1.0f);
        GL11.glPixelTransferf(GL11.GL_BLUE_BIAS, 1.0f);
        GL11.glPixelTransferf(GL11.GL_ALPHA_BIAS, 0.0f);
        for (final Entry entry : queue) {
            // fading doesn't work yet
            final long age = (now - entry.publishTime);
            float brightness;
            if (age < displayTime) {
                brightness = 1.0f;
            } else {
                brightness = 1.0f - ((age - displayTime) / (float) fadeTime);
            }
            GL11.glPixelTransferf(GL11.GL_ALPHA_SCALE, brightness);
            glWindowPos2i(leftOffset, height - topOffset - i * (2 * font.getCharacterHeight() + 4));
            font.drawText(entry.message, 2, Font.ALIGN_LEFT, Font.ALIGN_TOP);
            i++;
        }
        GL11.glPixelTransferf(GL11.GL_RED_SCALE, 1.0f);
        GL11.glPixelTransferf(GL11.GL_GREEN_SCALE, 1.0f);
        GL11.glPixelTransferf(GL11.GL_BLUE_SCALE, 1.0f);
        GL11.glPixelTransferf(GL11.GL_ALPHA_SCALE, 1.0f);
        GL11.glPixelTransferf(GL11.GL_RED_BIAS, 0.0f);
        GL11.glPixelTransferf(GL11.GL_GREEN_BIAS, 0.0f);
        GL11.glPixelTransferf(GL11.GL_BLUE_BIAS, 0.0f);
        GL11.glPixelTransferf(GL11.GL_ALPHA_BIAS, 0.0f);
    }

    /* (non-Javadoc)
     * @see name.martingeisse.stackd.client.frame.AbstractFrameHandler#handleStep()
     */
    @Override
    public final void handleStep() throws BreakFrameLoopException {
        final long now = System.currentTimeMillis();
        final long totalTimeToLive = (displayTime + fadeTime);
        while (!queue.isEmpty()) {
            final Entry next = queue.peek();
            final long age = (now - next.publishTime);
            if (age < totalTimeToLive) {
                break;
            }
            queue.remove();
        }
    }

    /**
     * Used to represent messages being displayed.
     */
    final static class Entry {

        /**
         * the publishTime
         */
        final long publishTime;

        /**
         * the message
         */
        final String message;

        /**
         * Constructor.
         * @param publishTime the time at which this message was published
         * @param message the message text
         */
        Entry(final long publishTime, final String message) {
            this.publishTime = publishTime;
            this.message = message;
        }

    }

}