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
Java Network
Java Forums
Java 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: 4093
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Collision detection - NeHe Tutorial JOGL Port E-mail
User Rating: / 9
PoorBest 

This example shows the basics of collision detection, collision response, and physically based modelling effects.

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.lesson30;

import demos.common.GLDisplay;

/*--.          .-"-.
/   o_O        / O o \
\_  (__\       \_ v _/
//   \\        //   \\
((     ))      ((     ))
¤¤¤¤¤¤¤¤¤¤¤¤¤¤--""---""--¤¤¤¤--""---""--¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
¤                 |||            |||                             ¤
¤                  |              |                              ¤
¤                                                                ¤
¤ Programmer:Abdul Bezrati                                       ¤
¤ Program   :Nehe's 30th lesson port to JOGL                     ¤
¤ Comments  :None                                                ¤
¤    _______                                                     ¤
¤  /` _____ `\;,     This e-mail address is being protected from spam bots, you need JavaScript enabled to view it                          ¤
¤ (__(^===^)__)';,                                 ___           ¤
¤   /  :::  \   ,;                               /^   ^\         ¤
¤  |   :::   | ,;'                              ( Ö   Ö )        ¤
¤¤¤'._______.'`¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ --°oOo--(_)--oOo°--¤¤*/

/**
 @author Abdul Bezrati
 */
public class Lesson30 {
    public static void main(String[] args) {
        GLDisplay neheGLDisplay = GLDisplay.createGLDisplay(
                "Lesson 30: Collision detection");
        Renderer renderer = new Renderer();
        InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
        neheGLDisplay.addGLEventListener(renderer);
        neheGLDisplay.addKeyListener(inputHandler);
        neheGLDisplay.start();
    }
}


package demos.nehe.lesson30;

import demos.common.GLDisplay;

import javax.swing.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

class InputHandler extends KeyAdapter {
    private Renderer renderer;

    public InputHandler(Renderer renderer, GLDisplay glDisplay) {
        this.renderer = renderer;
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0)"Zoom in");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0)"Zoom out");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)"Rotate scene left");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0)"Rotate scene right");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD8, 0)"Increase speed");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, 0)"Decrease speed");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)"Track ball");
        
        glDisplay.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0)"Toggle sound");
    }

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

    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_F3:
                renderer.toggleSounds();
                break;
            case KeyEvent.VK_F2:
                renderer.toggleCameraAttachedToBall();
                break;
            default:
                processKeyEvent(e, false);
        }
    }

    private void processKeyEvent(KeyEvent e, boolean pressed) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_DOWN:
                renderer.zoomOut(pressed);
                break;
            case KeyEvent.VK_UP:
                renderer.zoomIn(pressed);
                break;
            case KeyEvent.VK_LEFT:
                renderer.increaseCameraRotation(pressed);
                break;
            case KeyEvent.VK_RIGHT:
                renderer.decreaseCameraRotation(pressed);
                break;
            case KeyEvent.VK_NUMPAD8:
                renderer.increaseTimeStep(pressed);
                break;
            case KeyEvent.VK_NUMPAD2:
                renderer.decreaseTimeStep(pressed);
                break;
        }
    }
}


package demos.nehe.lesson30;

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.lesson30;

import demos.common.ResourceRetriever;
import demos.common.TextureReader;
import demos.nehe.lesson30.math.Tuple3d;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLUquadric;
import javax.media.opengl.glu.GLU;

import java.io.IOException;

class Renderer implements GLEventListener {
    private static final float EPSILON = 1e-8f;

    private Tuple3d[] arrayVel = new Tuple3d[10]// holds velocity of balls
    private Tuple3d[] arrayPos = new Tuple3d[10]// position of balls
    private Tuple3d[] oldPos = new Tuple3d[10];   // old position of balls
    private Tuple3d veloc = new Tuple3d(.5, -.1.5);  // initial velocity of balls
    private Tuple3d accel = new Tuple3d(0, -.050);  // acceleration ie. gravity of balls
    private Tuple3d dir = new Tuple3d(00, -10);  // initial direction of camera
    
    // initial position of cameraT
    private Tuple3d cameraPosition = new Tuple3d(0, -501000);  
    private boolean increaseCameraZ;
    private boolean decreaseCameraZ;

    private double timeStep = .6;      // timestep of simulation
    private boolean increaseTimeStep;
    private boolean decreaseTimeStep;

    private float cameraRotation = 0// holds rotation around the Y axis
    private boolean increaseCameraRotation;
    private boolean decreaseCameraRotation;

    private float[] spec = {1.0f1.0f1.0f1.0f}// sets specular highlight of balls
    private float[] posl = {0.0f400f0.0f1.0f}// position of ligth source
    private float[] amb2 = {0.3f0.3f0.3f1.0f}// ambient of lightsource
    private float[] amb = {0.2f0.2f0.2f1.0f};  // global ambient

    private int dlist;                       // stores display list
    private int[][] texture = new int[2][2]// stores texture objects
    private int nrOfBalls;                   // sets the number of balls,
    // hook camera on ball, and sound on/off
    private boolean cameraAttachedToBall = false;  
    private boolean soundsEnabled = true;  // hook camera on ball, and sound on/off

    private Plane pl1,pl2,pl3,pl4,pl5;                  // the 5 planes of the room
    private Cylinder cyl1,cyl2,cyl3;                    // the 2 cylinders of the room
    private Explosion[] explosions = new Explosion[20]// holds max 20 explosions at once
    private GLUquadric cylinder;               // Quadratic object to render the cylinders

    private AudioSample audioSample;

    private GLU glu = new GLU();

    public void zoomOut(boolean increase) {
        increaseCameraZ = increase;
    }

    public void zoomIn(boolean decrease) {
        decreaseCameraZ = decrease;
    }

    public void increaseTimeStep(boolean increase) {
        increaseTimeStep = increase;
    }

    public void decreaseTimeStep(boolean decrease) {
        decreaseTimeStep = decrease;
    }

    public boolean isSoundsEnabled() {
        return soundsEnabled;
    }

    public void toggleSounds() {
        this.soundsEnabled = !soundsEnabled;
    }

    public boolean isCameraAttachedToBall() {
        return cameraAttachedToBall;
    }

    public void toggleCameraAttachedToBall() {
        this.cameraAttachedToBall = !cameraAttachedToBall;
        cameraRotation = 0;
    }

    public void increaseCameraRotation(boolean increase) {
        increaseCameraRotation = increase;
    }

    public void decreaseCameraRotation(boolean decrease) {
        decreaseCameraRotation = decrease;
    }

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

        float df[] {100f};

        gl.glClearDepth(1.0f);                // Depth Buffer Setup
        gl.glEnable(GL.GL_DEPTH_TEST);        // Enables Depth Testing
        gl.glDepthFunc(GL.GL_LEQUAL);         // The Type Of Depth Testing To Do
        
        // Really Nice Perspective Calculations
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST)

        gl.glClearColor(0000);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glEnable(GL.GL_CULL_FACE);
        gl.glEnable(GL.GL_DEPTH_TEST);

        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, spec, 0);
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, df, 0);

        gl.glEnable(GL.GL_LIGHTING);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, posl, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, amb2, 0);
        gl.glEnable(GL.GL_LIGHT0);

        gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, amb, 0);
        gl.glEnable(GL.GL_COLOR_MATERIAL);
        gl.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE);

        gl.glEnable(GL.GL_BLEND);
        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);

        gl.glEnable(GL.GL_TEXTURE_2D);
        loadGLTextures(gl);

        //Construct billboarded explosion primitive as display list
        //4 quads at right angles to each other
        gl.glNewList(dlist = gl.glGenLists(1), GL.GL_COMPILE);
        gl.glBegin(GL.GL_QUADS);
        gl.glRotatef(-45010);
        gl.glNormal3f(001);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(-50, -400);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(50, -400);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(50400);
        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(-50400);
        gl.glNormal3f(00, -1);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(-50400);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(50400);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(50, -400);
        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(-50, -400);

        gl.glNormal3f(100);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(0, -4050);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(0, -40, -50);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(040, -50);
        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(04050);
        gl.glNormal3f(-100);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(04050);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(040, -50);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(0, -40, -50);
        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(0, -4050);
        gl.glEnd();
        gl.glEndList();

        try {
            audioSample = new AudioSample(
                    ResourceRetriever.getResourceAsStream(
                    "demos/data/samples/Explode.wav")
            );
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        initVars(glu);
    }

    private void loadGLTextures(GL gl) {
        TextureReader.Texture image1 = null;
        TextureReader.Texture image2 = null;
        TextureReader.Texture image3 = null;
        TextureReader.Texture image4 = null;
        try {
            image1 = TextureReader.readTexture("demos/data/images/Marble.bmp");
            image2 = TextureReader.readTexture("demos/data/images/Spark.bmp");
            image3 = TextureReader.readTexture("demos/data/images/Boden.bmp");
            image4 = TextureReader.readTexture("demos/data/images/Wand.bmp");
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        /* Create Texture  *****************************************/
        gl.glGenTextures(2, texture[0]0);
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0][0]);   /* 2d texture (x and y size)*/

        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image bigger than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image smalled than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);

        /* 2d texture, level of detail 0 (normal), 3 components 
         (red, green, blue), x size from image, y size from image, */
        /* border 0 (normal), rgb color data, unsigned byte data, 
         and finally the data itself.*/
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 03, image1.getWidth()
                image1.getHeight()0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, 
                image1.getPixels());

        /* Create Texture  ******************************************/
        /* 2d texture (x and y size)*/
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0][1]);           

        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image bigger than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image smalled than texture*/
        
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);

        /* 2d texture, level of detail 0 (normal), 3 components 
         (red, green, blue), x size from image, y size from image, */
        /* border 0 (normal), rgb color data, unsigned byte data, 
         and finally the data itself.*/
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 03, image2.getWidth()
                image2.getHeight()0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, 
                image2.getPixels());


        /* Create Texture  ********************************************/
        gl.glGenTextures(2, texture[1]0);
        /* 2d texture (x and y size)*/
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[1][0]);   

        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image bigger than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image smalled than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);

        /* 2d texture, level of detail 0 (normal), 3 components 
         (red, green, blue), x size from image, y size from image, */
        /* border 0 (normal), rgb color data, unsigned byte data, 
         and finally the data itself.*/
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 03, image3.getWidth()
                image3.getHeight()0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, 
                image3.getPixels());

        /* Create Texture  *********************************************/
        /* 2d texture (x and y size)*/
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[1][1]);   

        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image bigger than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, 
                GL.GL_LINEAR)/* scale linearly when image smalled than texture*/
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
        gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);

        /* 2d texture, level of detail 0 (normal), 3 components 
         (red, green, blue), x size from image, y size from image, */
        /* border 0 (normal), rgb color data, unsigned byte data, 
         and finally the data itself.*/
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 03, image4.getWidth()
                image4.getHeight()0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, 
                image4.getPixels());
    }

    private void initVars(GLU glu) {
        //create palnes
        pl1 = new Plane();
        pl1.position = new Tuple3d(0, -3000);
        pl1.normal = new Tuple3d(010);

        pl2 = new Plane();
        pl2.position = new Tuple3d(30000);
        pl2.normal = new Tuple3d(-100);

        pl3 = new Plane();
        pl3.position = new Tuple3d(-30000);
        pl3.normal = new Tuple3d(100);

        pl4 = new Plane();
        pl4.position = new Tuple3d(00300);
        pl4.normal = new Tuple3d(00, -1);

        pl5 = new Plane();
        pl5.position = new Tuple3d(00, -300);
        pl5.normal = new Tuple3d(001);

        cyl1 = new Cylinder();
        cyl1.position = new Tuple3d(000);
        cyl1.axis = new Tuple3d(010);
        cyl1.radius = 60 20;

        cyl2 = new Cylinder();
        cyl2.position = new Tuple3d(200, -3000);
        cyl2.axis = new Tuple3d(001);
        cyl2.radius = 60 20;

        cyl3 = new Cylinder();
        cyl3.position = new Tuple3d(-20000);
        cyl3.axis = new Tuple3d(011);
        cyl3.axis.normalize();
        cyl3.radius = 30 20;

        //create quadratic object to render cylinders
        cylinder = glu.gluNewQuadric();
        glu.gluQuadricTexture(cylinder, true);

        //Set initial positions and velocities of balls
        //also initialize array which holds explosions
        nrOfBalls = 10;
        arrayVel[0new Tuple3d(veloc);
        arrayPos[0new Tuple3d(19918010);

        explosions[0new Explosion();
        explosions[0].alpha = 0;
        explosions[0].scale = 1;
        arrayVel[1new Tuple3d(veloc);
        arrayPos[1new Tuple3d(0150100);

        explosions[1new Explosion();
        explosions[1].alpha = 0;
        explosions[1].scale = 1;
        arrayVel[2new Tuple3d(veloc);
        arrayPos[2new Tuple3d(-100180, -100);

        explosions[2new Explosion();
        explosions[2].alpha = 0;
        explosions[2].scale = 1;

        for (int i = 3; i < 10; i++) {
            arrayVel[inew Tuple3d(veloc);
            arrayPos[inew Tuple3d(-500 + i * 75300, -500 + i * 50);

            explosions[inew Explosion();
            explosions[i].alpha = 0;
            explosions[i].scale = 1;
        }

        for (int i = 10; i < 20; i++) {
            explosions[inew Explosion();
            explosions[i].alpha = 0;
            explosions[i].scale = 1;
        }
    }

    private void update() {
        if (decreaseCameraZ)
            cameraPosition.z -= 10;
        if (increaseCameraZ)
            cameraPosition.z += 10;
        if (increaseCameraRotation)
            cameraRotation += 10;
        if (decreaseCameraRotation)
            cameraRotation -= 10;
        if (increaseTimeStep)
            timeStep += 0.1;
        if (decreaseTimeStep)
            timeStep -= 0.1;
    }

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

        int i;
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

        //set camera in hookmode
        if (cameraAttachedToBall)
            glu.gluLookAt(arrayPos[0].x + 250, arrayPos[0].y + 250, arrayPos[0].z,
                    arrayPos[0].x + arrayVel[0].x, arrayPos[0].y + arrayVel[0].y, 
                    arrayPos[0].z + arrayVel[0].z
                    010);
        else
            glu.gluLookAt(cameraPosition.x, cameraPosition.y, cameraPosition.z,
                    cameraPosition.x + dir.x, cameraPosition.y + dir.y, 
                    cameraPosition.z + dir.z,
                    01.00.0);

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glRotatef(cameraRotation, 010);

        //render balls
        for (i = 0; i < nrOfBalls; i++) {
            switch (i) {
                case 1:
                    gl.glColor3f(1.0f1.0f1.0f);
                    break;
                case 2:
                    gl.glColor3f(1.0f1.0f0.0f);
                    break;
                case 3:
                    gl.glColor3f(0.0f1.0f1.0f);
                    break;
                case 4:
                    gl.glColor3f(0.0f1.0f0.0f);
                    break;
                case 5:
                    gl.glColor3f(0.0f0.0f1.0f);
                    break;
                case 6:
                    gl.glColor3f(0.65f0.2f0.3f);
                    break;
                case 7:
                    gl.glColor3f(1.0f0.0f1.0f);
                    break;
                case 8:
                    gl.glColor3f(0.0f0.7f0.4f);
                    break;
                default:
                    gl.glColor3f(1.0f00);
            }

            gl.glPushMatrix();
            gl.glTranslated(arrayPos[i].x, arrayPos[i].y, arrayPos[i].z);
            glu.gluSphere(cylinder, 202020);
            gl.glPopMatrix();
        }

        gl.glEnable(GL.GL_TEXTURE_2D);
        //render walls(planes) with texture
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[1][1]);
        gl.glColor3f(111);
        gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(320320320);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(320, -320320);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(-320, -320320);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(-320320320);

        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(-320320, -320);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(-320, -320, -320);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(320, -320, -320);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(320320, -320);

        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(320320, -320);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(320, -320, -320);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(320, -320320);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(320320320);

        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(-320320320);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(-320, -320320);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(-320, -320, -320);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(-320320, -320);
        gl.glEnd();

        //render floor (plane) with colours
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[1][0]);
        gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(1.0f0.0f);
        gl.glVertex3f(-320, -320320);
        gl.glTexCoord2f(1.0f1.0f);
        gl.glVertex3f(320, -320320);
        gl.glTexCoord2f(0.0f1.0f);
        gl.glVertex3f(320, -320, -320);
        gl.glTexCoord2f(0.0f0.0f);
        gl.glVertex3f(-320, -320, -320);
        gl.glEnd();

        //render columns(cylinders)
        /* choose the texture to use.*/
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0][0]);   
        gl.glColor3f(.5f.5f.5f);
        gl.glPushMatrix();
        gl.glRotatef(90100);
        gl.glTranslatef(00, -500);
        glu.gluCylinder(cylinder, 60601000202);
        gl.glPopMatrix();

        gl.glPushMatrix();
        gl.glTranslatef(200, -300, -500);
        glu.gluCylinder(cylinder, 60601000202);
        gl.glPopMatrix();

        gl.glPushMatrix();
        gl.glTranslatef(-20000);
        gl.glRotatef(135100);
        gl.glTranslatef(00, -500);
        glu.gluCylinder(cylinder, 30301000202);
        gl.glPopMatrix();

        //render/blend explosions
        gl.glEnable(GL.GL_BLEND);
        gl.glDepthMask(false);
        gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0][1]);

        for (i = 0; i < 20; i++) {
            if (explosions[i].alpha >= 0) {
                gl.glPushMatrix();
                explosions[i].alpha -= 0.01f;
                explosions[i].scale += 0.03f;
                gl.glColor4f(110, explosions[i].alpha);
                gl.glScalef(explosions[i].scale, explosions[i].scale, explosions[i].scale);
                gl.glTranslatef((floatexplosions[i].position.x / explosions[i].scale,
                        (floatexplosions[i].position.y / explosions[i].scale,
                        (floatexplosions[i].position.z / explosions[i].scale);
                gl.glCallList(dlist);
                gl.glPopMatrix();
            }
        }
        gl.glDepthMask(true);
        gl.glDisable(GL.GL_BLEND);
        gl.glDisable(GL.GL_TEXTURE_2D);
        idle();
    }

    /**
     * Main loop of the simulation. Moves, finds the collisions and responses 
     * of the objects in the current time step.
     */
    private void idle() {
        Tuple3d uveloc = new Tuple3d(),
                normal = new Tuple3d(),
                point = new Tuple3d(),
                norm = new Tuple3d(),
                Pos2 = new Tuple3d(),
                Nc = new Tuple3d();

        double rt2,
                rt4,
                rt[] {0},
                lamda[] {10000},
                RestTime[] {0},
                BallTime[] {0};

        int BallNr = 0,
                BallColNr1[] {0},
                BallColNr2[] {0};

        if (!cameraAttachedToBall) {
            cameraRotation += 0.1f;
            if (cameraRotation > 360)
                cameraRotation = 0;
        }

        RestTime[0this.timeStep;
        lamda[01000;

        //Compute velocity for next timestep using Euler equations
        for (int j = 0; j < nrOfBalls; j++)
            arrayVel[j].scaleAdd(RestTime[0], accel, arrayVel[j]);

        //While timestep not over
        while (RestTime[0> EPSILON) {

            lamda[010000;   //initialize to very large value
            //For all the balls find closest intersection between balls and 
            //planes/cylinders
            for (int i = 0; i < nrOfBalls; i++) {
                //compute new position and distance
                oldPos[inew Tuple3d();
                oldPos[i].set(arrayPos[i]);
                uveloc.set(arrayVel[i]);
                uveloc.normalize();
                arrayPos[i].scaleAdd(RestTime[0], arrayVel[i], arrayPos[i]);
                rt2 = oldPos[i].distance(arrayPos[i]);
                //Test if collision occured between ball and all 5 planes

                if (TestIntersionPlane(pl1, oldPos[i], uveloc, rt, norm)) {
                    //Find intersection time
                    rt4 = rt[0* RestTime[0/ rt2;
                    //if smaller than the one already stored replace and in timestep
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.scaleAdd(rt[0], uveloc, oldPos[i]);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                if (TestIntersionPlane(pl2, oldPos[i], uveloc, rt, norm)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.scaleAdd(rt[0], uveloc, oldPos[i]);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                if (TestIntersionPlane(pl3, oldPos[i], uveloc, rt, norm)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.scaleAdd(rt[0], uveloc, oldPos[i]);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                if (TestIntersionPlane(pl4, oldPos[i], uveloc, rt, norm)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.scaleAdd(rt[0], uveloc, oldPos[i]);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                if (TestIntersionPlane(pl5, oldPos[i], uveloc, rt, norm)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.scaleAdd(rt[0], uveloc, oldPos[i]);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                //Now test intersection with the 3 cylinders
                if (TestIntersionCylinder(cyl1, oldPos[i], uveloc, rt, norm, Nc)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.set(Nc);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                if (TestIntersionCylinder(cyl2, oldPos[i], uveloc, rt, norm, Nc)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.set(Nc);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }

                if (TestIntersionCylinder(cyl3, oldPos[i], uveloc, rt, norm, Nc)) {
                    rt4 = rt[0* RestTime[0/ rt2;
                    if (rt4 <= lamda[0]) {
                        if (rt4 <= RestTime[0+ EPSILON)
                            if (!((rt[0<= EPSILON&& 
                            (uveloc.dot(norm> EPSILON))) {
                                normal.set(norm);
                                point.set(Nc);
                                lamda[0= rt4;
                                BallNr = i;
                            }
                    }
                }
            }

            //After all balls were tested with planes/cylinders test for collision
            //between them and replace if collision time smaller
            if (findBallCol(Pos2, BallTime, RestTime, BallColNr1, BallColNr2== 1) {
                if (soundsEnabled)
                    audioSample.play();

                if ((lamda[0== 10000|| (lamda[0> BallTime[0])) {
                    RestTime[0= RestTime[0- BallTime[0];
                    Tuple3d pb1 = new Tuple3d(),
                            pb2 = new Tuple3d(),
                            xaxis = new Tuple3d(),
                            U1x = new Tuple3d(),
                            U1y = new Tuple3d(),
                            U2x = new Tuple3d(),
                            U2y = new Tuple3d(),
                            V1x = new Tuple3d(),
                            V1y = new Tuple3d(),
                            V2x = new Tuple3d(),
                            V2y = new Tuple3d();
                    double a,b;

                    pb1.scaleAdd(BallTime[0], arrayVel[BallColNr1[0]]
                            oldPos[BallColNr1[0]]);
                    pb2.scaleAdd(BallTime[0], arrayVel[BallColNr2[0]]
                            oldPos[BallColNr2[0]]);
                    xaxis.sub(pb2, pb1);
                    xaxis.normalize();

                    a = xaxis.dot(arrayVel[BallColNr1[0]]);
                    U1x.scaleAdd(a, xaxis);
                    U1y.sub(arrayVel[BallColNr1[0]], U1x);

                    xaxis.sub(pb1, pb2);
                    xaxis.normalize();

                    b = xaxis.dot(arrayVel[BallColNr2[0]]);
                    U2x.scaleAdd(b, xaxis);
                    U2y.sub(arrayVel[BallColNr2[0]], U2x);

                    V1x.add(U1x, U2x);
                    V1x.sub(new Tuple3d(U1x.x - U2x.x, U1x.y - U2x.y, U1x.z - U2x.z));
                    V1x.scale(.5);

                    V2x.add(U1x, U2x);
                    V2x.sub(new Tuple3d(U2x.x - U1x.x, U2x.y - U1x.y, U2x.z - U1x.z));
                    V2x.scale(.5);

                    V1y.set(U1y);
                    V2y.set(U2y);

                    for (int j = 0; j < nrOfBalls; j++)
                        arrayPos[j].scaleAdd(BallTime[0], arrayVel[j], oldPos[j]);

                    arrayVel[BallColNr1[0]].add(V1x, V1y);
                    arrayVel[BallColNr2[0]].add(V2x, V2y);

                    //Update explosion array
                    for (int j = 0; j < 20; j++) {
                        if (explosions[j].alpha <= 0) {
                            explosions[j].alpha = 1;
                            explosions[j].position = arrayPos[BallColNr1[0]];
                            explosions[j].scale = 1;
                            break;
                        }
                    }
                    continue;
                }
            }
            //End of tests
            //If test occured move simulation for the correct timestep
            //and compute response for the colliding ball
            if (lamda[0!= 10000) {
                RestTime[0-= lamda[0];

                for (int j = 0; j < nrOfBalls; j++)
                    arrayPos[j].scaleAdd(lamda[0], arrayVel[j], oldPos[j]);

                rt2 = arrayVel[BallNr].length();
                arrayVel[BallNr].normalize();

                normal.scale(-* normal.dot(arrayVel[BallNr]));
                arrayVel[BallNr].add(normal, arrayVel[BallNr]);
                arrayVel[BallNr].normalize();
                arrayVel[BallNr].scale(rt2);

                // Update explosion array
                for (int j = 0; j < 20; j++) {
                    if (explosions[j].alpha <= 0) {
                        explosions[j].alpha = 1;
                        explosions[j].position = point;
                        explosions[j].scale = 1;
                        break;
                    }
                }
            else
                RestTime[00;
        }
    }

    public void reshape(GLAutoDrawable drawable,
                        int xstart,
                        int ystart,
                        int width,
                        int height) {
        GL gl = drawable.getGL();

        height = (height == 0: height;

        gl.glViewport(00, width, height);      // Reset The Current Viewport
        gl.glMatrixMode(GL.GL_PROJECTION);       // Select The Projection Matrix
        gl.glLoadIdentity();                     // Reset The Projection Matrix

        // Calculate The Aspect Ratio Of The Window
        glu.gluPerspective(50.0f(floatwidth / height, 10.f1700.0f);

        gl.glMatrixMode(GL.GL_MODELVIEW);        // Select The Modelview Matrix
        gl.glLoadIdentity();
    }

    public void displayChanged(GLAutoDrawable drawable,
                               boolean modeChanged,
                               boolean deviceChanged) {
    }

    /*
     * Intersetion tests
     */

    /**
     * Fast Intersection Function between ray/plane
     */
    private boolean TestIntersionPlane(Plane plane, Tuple3d position, Tuple3d direction,
                                       double[] lamda, Tuple3d pNormal) {

        double dotProduct = direction.dot(plane.normal);
        double l2;

        //determine if ray paralle to plane
        if ((dotProduct < EPSILON&& (dotProduct > -EPSILON))
            return false;

        Tuple3d substract = new Tuple3d(plane.position);
        substract.sub(position);
        l2 = (plane.normal.dot(substract)) / dotProduct;

        if (l2 < -EPSILON)
            return false;

        pNormal.set(plane.normal);
        lamda[0= l2;
        return true;
    }

    /**
     * Fast Intersection Function between ray/cylinder
     */
    private boolean TestIntersionCylinder(Cylinder cylinder, Tuple3d position,
                                          Tuple3d direction, double[] lamda,
                                          Tuple3d pNormal, Tuple3d newposition) {
        Tuple3d RC = new Tuple3d(),
                HB = new Tuple3d(),
                n = new Tuple3d(),
                O = new Tuple3d();
        double d,t,s,
                ln,in,out;

        RC.sub(position, cylinder.position);
        n.cross(direction, cylinder.axis);

        ln = n.length();

        if ((ln < EPSILON&& (ln > -EPSILON))
            return false;

        n.normalize();
        d = Math.abs(RC.dot(n));

        if (d <= cylinder.radius) {

            O.cross(RC, cylinder.axis);
            t = -O.dot(n/ ln;
            O.cross(n, cylinder.axis);
            O.normalize();
            s = Math.abs(Math.sqrt(cylinder.radius * cylinder.radius - d * d
                    direction.dot(O));

            in = t - s;
            out = t + s;

            if (in < -EPSILON) {
                if (out < -EPSILON)
                    return false;
                else
                    lamda[0= out;
            else if (out < -EPSILON) {
                lamda[0= in;
            else if (in < out)
                lamda[0= in;
            else
                lamda[0= out;

            newposition.scaleAdd(lamda[0], direction, position);
            HB.sub(newposition, cylinder.position);
            pNormal.scaleAdd(-HB.dot(cylinder.axis), cylinder.axis, HB);
            pNormal.normalize();
            return true;
        }
        return false;
    }

    /**
     * Find if any of the current balls intersect with each other in the current timestep.
     @return the index of the 2 itersecting balls, the point and time of intersection
     */
    private int findBallCol(Tuple3d point, double[] TimePoint,
                            double[] Time2, int[] BallNr1, int[] BallNr2) {

        Tuple3d RelativeVClone = new Tuple3d(),
                RelativeV = new Tuple3d(),
                posi = new Tuple3d();

        double Timedummy = 10000,
                MyTime = 0,
                Add = Time2[0150;
        TRay rays;

        //Test all balls against eachother in 150 small steps
        for (int i = 0; i < nrOfBalls - 1; i++) {
            for (int j = i + 1; j < nrOfBalls; j++) {

                RelativeV.sub(arrayVel[i], arrayVel[j]);
                RelativeVClone.set(RelativeV);
                RelativeVClone.normalize();
                rays = new TRay(oldPos[i], RelativeVClone);
                MyTime = 0;

                if ((rays.dist(oldPos[j])) 40)
                    continue;

                while (MyTime < Time2[0]) {

                    MyTime += Add;
                    posi.scaleAdd(MyTime, RelativeV, oldPos[i]);
                    if (posi.distance(oldPos[j]) <= 40) {
                        point.set(posi);
                        if (Timedummy > (MyTime - Add))
                            Timedummy = MyTime - Add;

                        BallNr1[0= i;
                        BallNr2[0= j;
                        break;
                    }
                }
            }
        }

        if (Timedummy != 10000) {
            TimePoint[0= Timedummy;
            return 1;
        }
        return 0;
    }

    private static class Explosion {
        public Tuple3d position = new Tuple3d();
        public float alpha;
        public float scale;
    }

    private static class Cylinder {
        public Tuple3d position;
        public Tuple3d axis;
        public double radius;
    }

    private static class Plane {
        public Tuple3d position;
        public Tuple3d normal;
    }

    private static class TRay {
        public Tuple3d p;                     // Any point on the line
        public Tuple3d v;                     // Direction of the line

        public TRay(Tuple3d p,
                    Tuple3d v) {
            this.p = new Tuple3d(p);
            this.v = new Tuple3d(v);
        }

        public double dist(Tuple3d point) {
            double lambda = v.dot(new Tuple3d(point.x - p.x,
                    point.y - p.y,
                    point.z - p.z));
            Tuple3d point2 = new Tuple3d();
            point2.scaleAdd(lambda, v, p);
            return point.distance(point2);
        }
    }
}

--> The classes inside math sub-package are available in the source distribution.


 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.