java left logo
java middle logo
java right logo
 

Home arrow Other API Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Sitemap
Java Network
Java Forums
Java Tips Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 769
Java SE Tips: 614
Java ME Tips: 201
Java EE Tips: 184
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Line, antialiasing, timing, ortho view and simple sounds - NeHe Tutorial JOGL Port E-mail
User Rating: / 0
PoorBest 

This example shows Lines, Anti-Aliasing, Orthographic Projection, Timing, Basic Sound Effects, and Simple Game Logic.

This is the Java port of the one of the NeHe OpenGL tutorials.

You can get complete IntelliJ IDEA project structure (all source, resources, build script, …) by downloading the source distribution from here.

The original post of the programmer who ported the examples can be found here.


Image

package demos.nehe.lesson21;

import demos.common.GLDisplay;

import javax.swing.*;

public class Lesson21 {
    public static void main(String[] args) {
        try {
            Class.forName("com.dnsalias.java.timer.AdvancedTimer");
        catch (ClassNotFoundException e) {
            JOptionPane.showMessageDialog(
                    null,
                    "The GAGETimer API could not be found in the classpath.\n" +
                    "This API is required by this lesson.\n" +
                    "It can be downloaded at http://java.dnsalias.com/.",
                    "Could not find GAGETimer",
                    JOptionPane.ERROR_MESSAGE
            );
            System.exit(0);
        }

        GLDisplay neheGLDisplay = GLDisplay.createGLDisplay(
                "Lesson 21: Lines, timing, sound");
        
        Renderer renderer = new Renderer();
        InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
        neheGLDisplay.addGLEventListener(renderer);
        neheGLDisplay.addKeyListener(inputHandler);
        neheGLDisplay.start();
    }
}


package demos.nehe.lesson21;

import demos.common.GLDisplay;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

class InputHandler extends KeyAdapter {
    private Renderer renderer;

    public InputHandler(Renderer renderer, GLDisplay display) {
        this.renderer = renderer;
//  display.registerKeyStrokeForHelp(KeyStroke.getKeyStroke(KeyEvent.VK_, 0), "");
    }

    public void keyPressed(KeyEvent e) {
        // Set flags
        processKeyEvent(e, true);
    }

    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            // Toggle properties
            case KeyEvent.VK_SPACE:
                renderer.resetGame();
                break;
            default:
                // Unset flags
                processKeyEvent(e, false);
        }
    }

    private void processKeyEvent(KeyEvent e, boolean pressed) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_UP:
                renderer.moveUp(pressed);
                break;
            case KeyEvent.VK_DOWN:
                renderer.moveDown(pressed);
                break;
            case KeyEvent.VK_LEFT:
                renderer.moveLeft(pressed);
                break;
            case KeyEvent.VK_RIGHT:
                renderer.moveRight(pressed);
                break;
        }
    }
}


package demos.nehe.lesson21;

import demos.common.ResourceRetriever;

import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;

class AudioSample {
    private final Clip clip;

    public AudioSample(InputStream inputStreamthrows IOException {
        /* Load Sound*/
        try {
            // The inputstreams that we get by loading files from jars do not support
            // mark() and reset(), which are required by AudioSystem.getAudioInputStream().
            // To work around this problem, we first read the entire contents
            // of the inputstream to a byte array and wrap it in a ByteArrayInputStream.
            // This class does support mark() and reset().
            InputStream in = ensureMarkResetAvailable(inputStream);
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(in);
            AudioFormat audioFormat = audioInputStream.getFormat();

            int size = (int) (audioFormat.getFrameSize() 
                    audioInputStream.getFrameLength());
            
            byte[] audio = new byte[size];
            audioInputStream.read(audio, 0, size);
            DataLine.Info info = new DataLine.Info(Clip.class, audioFormat, size);
            clip = (Clip)AudioSystem.getLine(info);
            clip.open(audioFormat, audio, 0, size);
        catch (UnsupportedAudioFileException e) {
            throw new RuntimeException(e);
        catch (LineUnavailableException e) {
            throw new RuntimeException(e);
        }
    }

    private static InputStream ensureMarkResetAvailable(InputStream inputStream
            throws IOException {
        
        if (inputStream.markSupported()) {
            return inputStream;
        else {
            return new ByteArrayInputStream(readEntireStream(inputStream));
        }
    }

    private static byte[] readEntireStream(InputStream inputStreamthrows IOException {
        byte[] buffer = new byte[8];
        byte[] data = null;
        int dataLength = 0;

        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            data = append(buffer, bytesRead, data, dataLength);
            dataLength += bytesRead;
        }

        return trim(data, dataLength);
    }

    private static byte[] append(byte[] data, int amount, byte[] array, int offset) {
        if (array == null) {
            array = new byte[amount];
        }

        if (offset + amount >= array.length) {
            byte[] newArray = new byte[array.length * 2];
            System.arraycopy(array, 0, newArray, 0, offset);
            array = newArray;
        }

        System.arraycopy(data, 0, array, offset, amount);
        return array;
    }

    private static byte[] trim(byte[] data, int amount) {
        if (data == null) {
            return new byte[amount];
        else if (data.length == amount) {
            return data;
        else {
            byte[] newArray = new byte[amount];
            System.arraycopy(data, 0, newArray, 0, amount);
            return newArray;
        }
    }

    public void play() {
        play(false, false);
    }

    public void play(boolean wait, boolean loop) {
        if (wait) {
            WaitUntilFinishedLineListener waitUntilFinishedLineListener = 
                    new WaitUntilFinishedLineListener();
            
            clip.addLineListener(waitUntilFinishedLineListener);
            synchronized (clip) {
                play(loop);
                try {
                    clip.wait();
                catch (InterruptedException e) {
                }
            }
            clip.removeLineListener(waitUntilFinishedLineListener);
        else {
            play(loop);
        }
    }

    private void play(boolean loop) {
        clip.stop();
        clip.setFramePosition(0);
        if (loop) {
            clip.loop(Clip.LOOP_CONTINUOUSLY);
        else {
            clip.start();
        }
    }

    private class WaitUntilFinishedLineListener implements LineListener {
        public WaitUntilFinishedLineListener() {
        }

        public void update(LineEvent event) {
            if (event.getType().equals(LineEvent.Type.STOP||
                    event.getType().equals(LineEvent.Type.CLOSE)) {
                synchronized (clip) {
                    clip.notify();
                }
            }
        }
    }

    public void stop() {
        clip.stop();
    }
}


package demos.nehe.lesson21;

import com.sun.opengl.util.BufferUtil;
import demos.common.ResourceRetriever;
import demos.common.TextureReader;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Random;

class Renderer implements GLEventListener {
    private Random random = new Random();
    private boolean[][] vline = new boolean[11][11];  // Keeps Track Of Verticle Lines
    private boolean[][] hline = new boolean[11][11];  // Keeps Track Of Horizontal Lines
    private boolean filled;        // Done Filling In The Grid?
    private boolean gameover;    // Is The Game Over?
    private boolean anti = true;      // Antialiasing?

    private float delay;        // Enemy Delay
    private int adjust = 3;  // Speed Adjustment For Really Slow Video Cards
    private int lives = 5;  // Player Lives
    private int level = 1;  // Internal Game Level
    private int level2 = level;  // Displayed Game Level
    private int stage = 1;  // Game Stage

    private GameObject player = new GameObject();  // Player Information
    private GameObject[] enemy = new GameObject[9];  // Enemy Information
    private GameObject hourglass = new GameObject();  // Hourglass Information

    // Stepping Values For Slow Video Adjustment
    private int steps[] {12451020};  

    private int textures[] new int[2];    // Font Texture Storage Space
    private int base;
    private boolean resetGame = false;
    private boolean moveRight = false;
    private boolean moveLeft = false;
    private boolean moveDown = false;
    private boolean moveUp = false;
    private AudioSample dieSample;
    private AudioSample hourglassSample;
    private AudioSample freezeSample;
    private AudioSample completerSample;

    private ByteBuffer stringBuffer = BufferUtil.newByteBuffer(256);

    private long lastUpdateTime;

    public void moveUp(boolean move) {
        moveUp = move;
    }

    public void moveDown(boolean move) {
        moveDown = move;
    }

    public void moveLeft(boolean move) {
        moveLeft = move;
    }

    public void moveRight(boolean move) {
        moveRight = move;
    }

    public void resetGame() {
        resetGame = true;
    }

    private void resetObjects() {  // Reset Player And Enemies
        player.x = 0;  // Reset Player X Position To Far Left Of The Screen
        player.y = 0;  // Reset Player Y Position To The Top Of The Screen
        player.fx = 0;  // Set Fine X Position To Match
        player.fy = 0;  // Set Fine Y Position To Match

        // Loop Through All The Enemies
        for (int i = 0; i < (stage * level); i++) {  
            enemy[inew GameObject();
            enemy[i].x = (int) (Math.random() 6);  // Select A Random X Position
            enemy[i].y = (intMath.random() 11;  // Select A Random Y Position
            enemy[i].fx = enemy[i].x * 60;    // Set Fine X To Match
            enemy[i].fy = enemy[i].y * 40;    // Set Fine Y To Match
        }
    }

    private void loadGLTextures(GL glthrows IOException {
        String tileNames [] {"demos/data/images/font.png""demos/data/images/Image.png"};

        gl.glGenTextures(2, textures, 0);

        for (int i = 0; i < 2; i++) {
            TextureReader.Texture texture = TextureReader.readTexture(tileNames[i]);
            //Create Nearest Filtered Texture
            gl.glBindTexture(GL.GL_TEXTURE_2D, textures[i]);

            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);

            gl.glTexImage2D(GL.GL_TEXTURE_2D,
                    0,
                    3,
                    texture.getWidth(),
                    texture.getHeight(),
                    0,
                    GL.GL_RGB,
                    GL.GL_UNSIGNED_BYTE,
                    texture.getPixels());
        }
    }

    void buildFont(GL gl) {  // Build Our Font Display List
        base = gl.glGenLists(256);  // Creating 256 Display Lists
        for (int i = 0; i < 256; i++)  // Loop Through All 256 Lists
        {
            float cx = (float) (i % 1616.0f;  // X Position Of Current Character
            float cy = (float) (i / 1616.0f;  // Y Position Of Current Character

            gl.glNewList(base + i, GL.GL_COMPILE);  // Start Building A List
            gl.glBegin(GL.GL_QUADS);      // Use A Quad For Each Character
            gl.glTexCoord2f(cx, 1.0f - cy - 0.0625f);  // Texture Coord (Bottom Left)
            gl.glVertex2d(016);      // Vertex Coord (Bottom Left)
            
            // Texture Coord (Bottom Right)
            gl.glTexCoord2f(cx + 0.0625f1.0f - cy - 0.0625f);  
            gl.glVertex2i(1616);      // Vertex Coord (Bottom Right)
            gl.glTexCoord2f(cx + 0.0625f1.0f - cy);  // Texture Coord (Top Right)
            gl.glVertex2i(160);      // Vertex Coord (Top Right)
            gl.glTexCoord2f(cx, 1.0f - cy);    // Texture Coord (Top Left)
            gl.glVertex2i(00);      // Vertex Coord (Top Left)
            
            // Done Building Our Quad (Character)
            gl.glEnd();          
            
            // Move To The Right Of The Character
            gl.glTranslated(1500);      
            gl.glEndList();    // Done Building The Display List
        // Loop Until All 256 Are Built
    }

    // Where The Printing Happens
    private void glPrint(GL gl, int x, int y, int set, String message)  
    {
        if (set > 1) {  // Did User Choose An Invalid Character Set?
            set = 1;  // If So, Select Set 1 (Italic)
        }
        gl.glEnable(GL.GL_TEXTURE_2D);  // Enable Texture Mapping
        gl.glLoadIdentity();    // Reset The Modelview Matrix
        gl.glTranslated(x, y, 0);  // Position The Text (0,0 - Bottom Left)
        gl.glListBase(base - 32 (128 * set));  // Choose The Font Set (0 or 1)

        if (set == 0) {  // If Set 0 Is Being Used Enlarge Font
            gl.glScalef(1.5f2.0f1.0f);  // Enlarge Font Width And Height
        }

        if (stringBuffer.capacity() < message.length()) {
            stringBuffer = BufferUtil.newByteBuffer(message.length());
        }

        stringBuffer.clear();
        stringBuffer.put(message.getBytes());
        stringBuffer.flip();
        
        // Write The Text To The Screen
        gl.glCallLists(message.length(), GL.GL_UNSIGNED_BYTE, stringBuffer);    
        gl.glDisable(GL.GL_TEXTURE_2D);  // Disable Texture Mapping
    }

    public void init(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        for (int i = 0; i < 9; i++)
            enemy[inew GameObject();

        try {
            loadGLTextures(gl);
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        buildFont(gl);

        gl.glShadeModel(GL.GL_SMOOTH);    // Enables Smooth Color Shading
        
        // This Will Clear The Background Color To Black
        gl.glClearColor(0.0f0.0f0.0f0.0f);               
        gl.glClearDepth(1.0);  // Enables Clearing Of The Depth Buffer
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDepthFunc(GL.GL_LEQUAL)//T he Type Of Depth Test To Do
        
        // Really Nice Perspective Calculations
        gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST);  
        gl.glEnable(GL.GL_BLEND);  // Enable Blending
        
        // Type Of Blending To Use
        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);  
        gl.glEnable(GL.GL_TEXTURE_2D);  // Enable 2D Texture Mapping
        resetObjects();      // Reset Player / Enemy Positions

        try {
            dieSample = new AudioSample(
                    ResourceRetriever.getResourceAsStream("demos/data/samples/Die.wav"));
            
            completerSample = new AudioSample(
                    ResourceRetriever.getResourceAsStream("demos/data/samples/Complete.wav"));
            
            freezeSample = new AudioSample(
                    ResourceRetriever.getResourceAsStream("demos/data/samples/Freeze.wav"));
            
            hourglassSample = new AudioSample(
                    ResourceRetriever.getResourceAsStream("demos/data/samples/Hourglass.wav"));
            
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void update() {
        if (!gameover)  // If Game Isn't Over And Programs Active Move Objects
        {
            
            // Loop Through The Different Stages
            for (int loop1 = 0; loop1 < (stage * level); loop1++)    
            {
                if ((enemy[loop1].x < player.x&& (enemy[loop1].fy == 
                        enemy[loop1].y * 40)) {
                    enemy[loop1].x++;  // Move The Enemy Right
                }

                if ((enemy[loop1].x > player.x&& (enemy[loop1].fy == 
                        enemy[loop1].y * 40)) {
                    enemy[loop1].x--;  // Move The Enemy Left
                }

                if ((enemy[loop1].y < player.y&& (enemy[loop1].fx == 
                        enemy[loop1].x * 60)) {
                    enemy[loop1].y++;  // Move The Enemy Down
                }

                if ((enemy[loop1].y > player.y&& (enemy[loop1].fx == 
                        enemy[loop1].x * 60)) {
                    enemy[loop1].y--;  // Move The Enemy Up
                }

                // If Our Delay Is Done And Player Doesn't Have Hourglass
                if (delay > (- level&& (hourglass.fx != 2))  
                {
                    delay = 0;    // Reset The Delay Counter Back To Zero
                    
                    // Loop Through All The Enemies
                    for (int loop2 = 0; loop2 < (stage * level); loop2++)  
                    {
                        // Is Fine Position On X Axis Lower Than Intended Position?
                        if (enemy[loop2].fx < enemy[loop2].x * 60)  
                        {
                            // If So, Increase Fine Position On X Axis
                            enemy[loop2].fx += steps[adjust];  
                            enemy[loop2].spin += steps[adjust];  // Spin Enemy Clockwise
                        }
                        
<