java left logo
java middle logo
java right logo
 

Home arrow Other API Tips arrow JOGL arrow 3D lens flare with occlusion testing - NeHe Tutorial JOGL Port
 
 
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:
 
 
 
3D lens flare with occlusion testing - NeHe Tutorial JOGL Port E-mail
User Rating: / 2
PoorBest 

This example shows how to do lens flares by extending a glCamera class.

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

import demos.common.GLDisplay;
                  /*--.          .-"-.
                 /   o_O        / O o \
                 \_  (__\       \_ v _/
                 //   \\        //   \\
                ((     ))      ((     ))
 ¤¤¤¤¤¤¤¤¤¤¤¤¤¤--""---""--¤¤¤¤--""---""--¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
 ¤                 |||            |||                             ¤
 ¤                  |              |                              ¤
 ¤                                                                ¤
 ¤ Programmer:Abdul Bezrati                                       ¤
 ¤ Program   :Nehe's 44th 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°--¤¤*/
public class Lesson44 {
    public static void main(String[] args) {
        GLDisplay neheGLDisplay = GLDisplay.createGLDisplay("Lesson 44: Lens flare");
        Renderer renderer = new Renderer();
        InputHandler inputHandler = new InputHandler(renderer, neheGLDisplay);
        neheGLDisplay.addGLEventListener(renderer);
        neheGLDisplay.addKeyListener(inputHandler);
        neheGLDisplay.start();
    }
}


package demos.nehe.lesson44;

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 display) {
        this.renderer = renderer;
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_1, 0)"Show info");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_2, 0)"Hide info");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_W, 0)"Pitch camera up");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_S, 0)"Pitch camera down");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_A, 0)"Yaw camera right");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_D, 0)"Yaw camera left");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_Q, 0)"Move camera forward");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_E, 0)"Move camera backward");
        
        display.registerKeyStrokeForHelp(
                KeyStroke.getKeyStroke(KeyEvent.VK_X, 0)"Stop camera movement");
    }

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

    public void keyReleased(KeyEvent e) {
        switch (e.getKeyCode()) {
            // Toggle properties
            case KeyEvent.VK_1:
                renderer.setInfoDisplayed(true);
                break;
            case KeyEvent.VK_2:
                renderer.setInfoDisplayed(false);
                break;
            case KeyEvent.VK_Q:
                renderer.moveCameraForward();
                break;
            case KeyEvent.VK_E:
                renderer.moveCameraBackward();
                break;
            case KeyEvent.VK_X:
                renderer.stopCamera();
                break;
            default:
                // Unset flags
                processKeyEvent(e, false);
        }
    }

    private void processKeyEvent(KeyEvent e, boolean pressed) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_W:
                renderer.pitchCameraUp(pressed);
                break;
            case KeyEvent.VK_S:
                renderer.pitchCameraDown(pressed);
                break;
            case KeyEvent.VK_A:
                renderer.yawCameraLeft(pressed);
                break;
            case KeyEvent.VK_D:
                renderer.yawCameraRight(pressed);
                break;
        }
    }
}


package demos.nehe.lesson44;

import com.sun.opengl.util.BufferUtil;

import javax.media.opengl.GL;
import java.nio.ByteBuffer;

/**
 * I don't mind if you use this class in your own code. All I ask is
 * that you give me and Giuseppe D'Agata credit for it if you do.
 * And plug NeHe while your at it! :P  Thanks go to Giuseppe D'Agata
 * for the code that this class is based off of. Thanks Enjoy.
 @author Vic Hollis
 @author Abdul Bezrati
 */
class Font {
    private double m_WindowHeight;
    private double m_WindowWidth;
    private int m_FontTexture;
    private int m_ListBase;
    private ByteBuffer stringBuffer = BufferUtil.newByteBuffer(512);

    public Font() {
        m_FontTexture = 0;    // Initalize the texture to 0
        m_ListBase = 0;    // Initalize the List base to 0
    }

    public void setFontTexture(int tex) {
        if (tex != 0) {          // If the texture is valid
            m_FontTexture = tex; // Set the font texture
        }
    }

    public void buildFont(GL gl, float scale) {
        m_ListBase = gl.glGenLists(256);  // Creating 256 Display Lists
        if (m_FontTexture != 0) {
            // Select Our Font Texture
            gl.glBindTexture(GL.GL_TEXTURE_2D, m_FontTexture)
            for (int loop = 0; loop < 256; loop++) {   // Loop Through All 256 Lists
                float cx = (float) (loop % 1616.0f;  // X Position Of Current Character
                float cy = (float) (loop / 1616.0f;  // Y Position Of Current Character

                gl.glNewList(m_ListBase + loop, GL.GL_COMPILE)// Start Building A List
                gl.glBegin(GL.GL_QUADS)// Use A Quad For Each Character
                gl.glTexCoord2f(cx, - cy - 0.0625f)// Texture Coord (Bottom Left)
                gl.glVertex2f(00);   // Vertex Coord (Bottom Left)
                // Texture Coord (Bottom Right)
                gl.glTexCoord2f(cx + 0.0625f- cy - 0.0625f)
                gl.glVertex2f(16 * scale, 0);           // Vertex Coord (Bottom Right)
                gl.glTexCoord2f(cx + 0.0625f- cy);  // Texture Coord (Top Right)
                gl.glVertex2f(16 * scale, 16 * scale);  // Vertex Coord (Top Right)
                gl.glTexCoord2f(cx, - cy);            // Texture Coord (Top Left)
                gl.glVertex2f(016 * scale);           // Vertex Coord (Top Left)
                // Done Building Our Quad (Character)
                gl.glEnd();                             
                // Move To The Right Of The Character
                gl.glTranslated(10 * scale, 00);      
                // Done Building The Display List
                gl.glEndList();                         
            }   // Loop Until All 256 Are Built
        }
    }

    public void glPrintf(GL gl, int x, int y, int set, String format) {
        if (format == null)  // If There's No Text
            return;

        byte text[] = format.getBytes();

        if (set > 1)  // Did User Choose An Invalid Character Set?
            set = 1;

        gl.glEnable(GL.GL_TEXTURE_2D);  // Enable 2d Textures
        gl.glEnable(GL.GL_BLEND);       // Enable Blending
        gl.glBlendFunc(GL.GL_SRC_COLOR, GL.GL_ONE_MINUS_SRC_COLOR);
        gl.glBindTexture(GL.GL_TEXTURE_2D, m_FontTexture)// Select Our Font Texture
        gl.glDisable(GL.GL_DEPTH_TEST);                    // Disables Depth Testing
        gl.glMatrixMode(GL.GL_PROJECTION);                 // Select The Projection Matrix
        gl.glPushMatrix();                                 // Store The Projection Matrix
        gl.glLoadIdentity();                               // Reset The Projection Matrix
        gl.glOrtho(0, m_WindowWidth, 0, m_WindowHeight, -11)// Set Up An Ortho Screen
        gl.glMatrixMode(GL.GL_MODELVIEW);                  // Select The Modelview Matrix
        gl.glPushMatrix();                                 // Store The Modelview Matrix
        gl.glLoadIdentity();                               // Reset The Modelview Matrix
        // Position The Text (0,0 - Bottom Left)
        gl.glTranslated(x, y, 0);                          
        gl.glListBase(m_ListBase - 32 (128 * set));      // Choose The Font Set (0 or 1)

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

        stringBuffer.clear();
        stringBuffer.put(format.getBytes());
        stringBuffer.flip();

        // Write The Text To The Screen
        gl.glCallLists(text.length, GL.GL_BYTE, stringBuffer)
        gl.glMatrixMode(GL.GL_PROJECTION);  // Select The Projection Matrix
        gl.glPopMatrix();                   // Restore The Old Projection Matrix
        gl.glMatrixMode(GL.GL_MODELVIEW);   // Select The Modelview Matrix
        gl.glPopMatrix();                   // Restore The Old Projection Matrix
        gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glDisable(GL.GL_BLEND);
        gl.glDisable(GL.GL_TEXTURE_2D);
    }

    public void setWindowSize(int width, int height) {
        m_WindowWidth = width;              // Set the window size width
        m_WindowHeight = height;            // Set the window size height
    }
}


package demos.nehe.lesson44;

import javax.media.opengl.GL;

/**
 * I don't mind if you use this class in your own code. All I ask is
 * that you give me credit for it if you do.  And plug NeHe while your
 * at it! :P  Thanks go to David Steere, Cameron Tidwell, Bert Sammons,
 * and Brannon Martindale for helping me test all the code!  Enjoy.
 @author Vic Hollis
 @author Abdul Bezrati
 */
class Camera {
    Tuple3f vLightSourceToIntersect;
    Tuple3f vLightSourceToCamera;
    Tuple3f m_DirectionVector;
    Tuple3f m_LightSourcePos;
    Tuple3f ptIntersect;
    Tuple3f m_Position;
    Tuple3f pt;

    float m_MaxForwardVelocity;
    float m_ForwardVelocity;
    float m_MaxHeadingRate;
    float m_HeadingDegrees;
    float m_PitchDegrees;
    float m_MaxPitchRate;
    float m_MaxPointSize;
    float[][] m_Frustum;

    int[] m_BigGlowTexture;
    int[] m_StreakTexture;
    int[] m_HaloTexture;
    int[] m_GlowTexture;
    int m_WindowHeight;
    int m_WindowWidth;

    public Camera() {
        // Initalize all our member varibles.
        vLightSourceToIntersect = new Tuple3f();
        vLightSourceToCamera = new Tuple3f();
        m_DirectionVector = new Tuple3f();
        m_LightSourcePos = new Tuple3f();
        ptIntersect = new Tuple3f();
        m_Position = new Tuple3f();
        pt = new Tuple3f();
        m_Frustum = new float[6][4];
        m_MaxForwardVelocity = 0;
        m_LightSourcePos.x = 0;
        m_LightSourcePos.y = 0;
        m_LightSourcePos.z = 0;
        m_ForwardVelocity = 0;
        m_MaxHeadingRate = 0;
        m_HeadingDegrees = 0;
        m_BigGlowTexture = new int[1];
        m_StreakTexture = new int[1];
        m_PitchDegrees = 0;
        m_MaxPointSize = 0;
        m_MaxPitchRate = 0;
        m_GlowTexture = new int[1];
        m_HaloTexture = new int[1];
    }

    public void setPrespective(GL gl) {
        Tuple3f v = new Tuple3f();  // A vector to hold our cameras direction * 
                                    // the forward velocity
        float Matrix[] new float[16];  // A array to hold the model view matrix.
        // we don't want to destory the Direction vector by using it instead.

        // Going to use glRotate to calculate our direction vector
        gl.glRotatef(m_HeadingDegrees, 0.0f1.0f0.0f);
        gl.glRotatef(m_PitchDegrees, 1.0f0.0f0.0f);

        // Get the resulting matrix from OpenGL it will have our
        // direction vector in the 3rd row.
        gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, Matrix, 0);

        // Get the direction vector from the matrix. Element 10 must
        // be inverted!
        m_DirectionVector.x = Matrix[8];
        m_DirectionVector.y = Matrix[9];
        m_DirectionVector.z = -Matrix[10];

        // Ok erase the results of the last computation.
        gl.glLoadIdentity();

        // Rotate the scene to get the right orientation.
        gl.glRotatef(m_PitchDegrees, 1.0f0.0f0.0f);
        gl.glRotatef(m_HeadingDegrees, 0.0f1.0f0.0f);

        // Scale the direction by our speed.
        v.scale(m_ForwardVelocity, m_DirectionVector);

        // Increment our position by the vector
        m_Position.add(v);

        // Translate to our new position.
        gl.glTranslatef(-m_Position.x, -m_Position.y, -m_Position.z);
    }

    public void changePitch(float degrees) {

        if (Math.abs(degrees< Math.abs(m_MaxPitchRate)) {
            // Our pitch is less than the max pitch rate that we
            // defined so lets increment it.
            m_PitchDegrees += degrees;
        else {
            // Our pitch is greater than the max pitch rate that
            // we defined so we can only increment our pitch by the
            // maximum allowed value.
            if (degrees < 0) {
                // We are pitching down so decrement
                m_PitchDegrees -= m_MaxPitchRate;
            else {
                // We are pitching up so increment
                m_PitchDegrees += m_MaxPitchRate;
            }
        }

        // We don't want our pitch to run away from us. Although it
        // really doesn't matter I prefer to have my pitch degrees
        // within the range of -360.0f to 360.0f
        if (m_PitchDegrees > 360.0f) {
            m_PitchDegrees -= 360.0f;
        else if (m_PitchDegrees < -360.0f) {
            m_PitchDegrees += 360.0f;
        }
    }

    public void changeHeading(float degrees) {

        if (Math.abs(degrees< Math.abs(m_MaxHeadingRate)) {
            // Our Heading is less than the max heading rate that we
            // defined so lets increment it but first we must check
            // to see if we are inverted so that our heading will not
            // become inverted.
            if (m_PitchDegrees > 90 && m_PitchDegrees < 270 || 
                    (m_PitchDegrees < -90 && m_PitchDegrees > -270)) {
                m_HeadingDegrees -= degrees;
            else {
                m_HeadingDegrees += degrees;
            }
        else {
            // Our heading is greater than the max heading rate that
            // we defined so we can only increment our heading by the
            // maximum allowed value.
            if (degrees < 0) {
                // Check to see if we are upside down.
                if ((m_PitchDegrees > 90 && m_PitchDegrees < 270|| 
                        (m_PitchDegrees < -90 && m_PitchDegrees > -270)) {
                    // Ok we would normally decrement here but since we are upside
                    // down then we need to increment our heading
                    m_HeadingDegrees += m_MaxHeadingRate;
                else {
                    // We are not upside down so decrement as usual
                    m_HeadingDegrees -= m_MaxHeadingRate;
                }
            else {
                // Check to see if we are upside down.
                if (m_PitchDegrees > 90 && m_PitchDegrees < 270 || 
                        (m_PitchDegrees < -90 && m_PitchDegrees > -270)) {
                    // Ok we would normally increment here but since we are upside
                    // down then we need to decrement our heading.
                    m_HeadingDegrees -= m_MaxHeadingRate;
                else {
                    // We are not upside down so increment as usual.
                    m_HeadingDegrees += m_MaxHeadingRate;
                }
            }
        }

        // We don't want our heading to run away from us either. Although it
        // really doesn't matter I prefer to have my heading degrees
        // within the range of -360.0f to 360.0f
        if (m_HeadingDegrees > 360.0f) {
            m_HeadingDegrees -= 360.0f;
        else if (m_HeadingDegrees < -360.0f) {
            m_HeadingDegrees += 360.0f;
        }
    }

    public void changeVelocity(float vel) {

        if (Math.abs(vel< Math.abs(m_MaxForwardVelocity)) {
            // Our velocity is less than the max velocity increment that we
            // defined so lets increment it.
            m_ForwardVelocity += vel;
        else {
            // Our velocity is greater than the max velocity increment that
            // we defined so we can only increment our velocity by the
            // maximum allowed value.
            if (vel < 0) {
                // We are slowing down so decrement
                m_ForwardVelocity -= -m_MaxForwardVelocity;
            else {
                // We are speeding up so increment
                m_ForwardVelocity += m_MaxForwardVelocity;
            }
        }
    }

    // I found this code here: http://www.markmorley.com/opengl/frustumculling.html
    // and decided to make it part of
    // the camera class just in case I might want to rotate
    // and translate the projection matrix. This code will
    // make sure that the Frustum is updated correctly but
    // this member is computational expensive with:
    // 82 muliplications, 72 additions, 24 divisions, and
    // 12 subtractions for a total of 190 operations. Ouch!
    private void updateFrustum(GL gl) {

        float clip[] new float[16],
                proj[] new float[16],
                modl[] new float[16],
                t;

        /* Get the current PROJECTION matrix from OpenGL */
        gl.glGetFloatv(GL.GL_PROJECTION_MATRIX, proj, 0);

        /* Get the current MODELVIEW matrix from OpenGL */
        gl.glGetFloatv(GL.GL_MODELVIEW_MATRIX, modl, 0);

        /* Combine the two matrices (multiply projection by modelview) */
        clip[0= modl[0* proj[0+ modl[1* proj[4+ modl[2* proj[8
                modl[3* proj[12];
        clip[1= modl[0* proj[1+ modl[1* proj[5+ modl[2* proj[9
                modl[3* proj[13];
        clip[2= modl[0* proj[2+ modl[1* proj[6+ modl[2* proj[10
                modl[3* proj[14];
        clip[3= modl[0* proj[3+ modl[1* proj[7+ modl[2* proj[11
                modl[3* proj[15];

        clip[4= modl[4* proj[0+ modl[5* proj[4+ modl[6* proj[8
                modl[7* proj[12];
        clip[5= modl[4* proj[1+ modl[5* proj[5+ modl[6* proj[9+
                modl[7