My favorites | Sign in
Project Home Downloads Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
Thunderstorm  
Thunderstorm algorithm
Phase-Implementation
Updated Dec 22, 2010 by wonderso...@gmail.com
package tf4r;

import org.lwjgl.input.Keyboard;
import org.lwjgl.openal.AL;
import org.lwjgl.opengl.*;
import org.lwjgl.util.glu.GLU;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;
import tf4r.loader.ContentLoader;
import tf4r.loader.sound.SoundManager;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

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

/**
 */
public class TestLightning {
    private static final boolean ORTHO = true;
    private static final int WIDTH = 640;
    private static final int HEIGHT = 480;

    final static Random rand = new Random(System.currentTimeMillis());

    static class Rain {
        private final Vector4f[] rain = new Vector4f[400];
        private final float x = 30f;
        private final float xStep = x * 0.0005f;
        private final float y = -50f;
        private final float yStep = y * 0.0005f;

        public Rain(int screenWidth, int screenHeight) {
            for (int i = 0; i < rain.length; i++) {
                rain[i] = new Vector4f();
                rain[i].x = (rand.nextInt(screenWidth) - screenWidth / 2) / (float) screenWidth;
                rain[i].y = (rand.nextInt(screenHeight) - screenHeight / 2) / (float) screenHeight;
                rain[i].z = rain[i].x + x / (float) screenWidth;
                rain[i].w = rain[i].y + y / (float) screenHeight;
            }
        }

        public void draw() {
            GL11.glEnable(GL11.GL_BLEND);
            GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

            glDisable(GL_TEXTURE_2D);
            GL11.glLineWidth(2f);

            glLoadIdentity();
            MyLWJGLUtil.glBegin(GL11.GL_LINES);
            {
                MyLWJGLUtil.glColor4f(0.313f, 0.313f, 0.313f, 0.1f + rand.nextFloat() * 0.2f);
                glNormal3f(0, 0, 1);
                for (Vector4f r : rain) {
                    MyLWJGLUtil.glVertex3f(r.x, r.y, -1);
                    MyLWJGLUtil.glVertex3f(r.z, r.w, -1);
                    r.x += xStep;
                    r.y += yStep;
                    r.z += xStep;
                    r.w += yStep;

                    if (r.y < -0.5f/*-HEIGHT / 2*/) {
                        //r.x = rand.nextInt(WIDTH * 2) - WIDTH - x;
                        r.x = rand.nextFloat() * 1.33333f - .5f * 1.33333f;
                        //r.y = HEIGHT / 2 - y;
                        r.y = rand.nextFloat() * 0.5f - .25f;
                        r.z = r.x + x / 640f;
                        r.w = r.y + y / 480f;
                    }
                }
            }
            MyLWJGLUtil.glEnd();
        }
    }

    static class Lightning {
        final List<Vector3f[]> lightning = new ArrayList<Vector3f[]>();
        private final int screenHeight;
        private final int screenWidth;
        private boolean finishedDisplayLightning;
        private int displayFlash;
        private int flashSphereTextureID;
        private float initX;
        private float initY;
        private float finishAlive;
        private boolean hasToPlaySound;
        private int playSound;

        public Lightning(int screenWidth, int screenHeight, int flashSphereTextureID) {
            this.screenWidth = screenWidth;
            this.screenHeight = screenHeight;
            this.flashSphereTextureID = flashSphereTextureID;

            reset();

            // for bloom
            createOffScreenBuffer();
        }

        public void reset() {
            lightning.clear();
            alive = finishAlive = 0f;
            displayFlash = 0;
            finishedDisplayLightning = false;
            hasToPlaySound = true;
            playSound = 5 + rand.nextInt(30);

            Vector3f[] lightning0 = new Vector3f[43];
            lightning.add(lightning0);
            // starting point
            initX = rand.nextFloat() * .5f - .25f;
            initY = .5f - rand.nextFloat() * .25f;
            lightning0[0] = new Vector3f(initX, initY, 0);

            // build main arcs
            final float STEP = .05f;
            for (int i = 1; i < lightning0.length; i++) {
                float x = Math.abs(rand.nextFloat() * STEP * .8f - STEP * (Math.abs(initX)) / 2f);
                if (initX > 0) {
                    x *= -1f;
                }
                final float y = rand.nextFloat() * STEP;
                lightning0[i] = new Vector3f(lightning0[i - 1].x + x, lightning0[i - 1].y - y, (float) i);

                // build other arcs
                if (rand.nextFloat() > .85f && i < 25) {
                    addArc(lightning0[i], i, 1);
                }
            }
        }

        private int BLOOM_TEXTURE_ID;

        private void createOffScreenBuffer() {
            IntBuffer buf = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
            GL11.glGenTextures(buf); // Create Texture In OpenGL
            BLOOM_TEXTURE_ID = buf.get(0);
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, BLOOM_TEXTURE_ID);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
            final int bytesPerPixel = 4;
            ByteBuffer scratch = ByteBuffer.allocateDirect(WIDTH * HEIGHT * bytesPerPixel);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
            GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, WIDTH, HEIGHT, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, scratch);
        }

        private void addArc(Vector3f origin, int iter, int generation) {
            Vector3f[] arc = new Vector3f[5 + rand.nextInt(10)];
            lightning.add(arc);
            arc[0] = origin;
            final float STEP = .05f;
            boolean xDir = rand.nextBoolean();
            for (int i = 1; i < arc.length; i++) {
                float x = Math.abs(rand.nextFloat() * 3f * STEP - STEP * 1.5f) * 1f / (float) generation;
                if (xDir) {
                    if (rand.nextFloat() < .95f) {
                        x *= -1;
                    } else {
                        xDir = !xDir;
                    }
                } else {
                    if (rand.nextFloat() > .95f) {
                        x *= -1;
                        xDir = !xDir;
                    }
                }
                final float y = rand.nextFloat() * STEP / 1.5f * 1f / (float) generation;
                arc[i] = new Vector3f(arc[i - 1].x + x, arc[i - 1].y - y, i + iter);

                if (rand.nextFloat() > .92f && lightning.size() < 60) {
                    addArc(arc[i], i + iter, generation + 1);
                }
            }
        }

        private float alive;

        private void draw() {
            if (playSound > 0 || displayFlash > 0 || isFinished()) {
                return;
            }

            alive += 3f;

            GL11.glMatrixMode(GL11.GL_PROJECTION);
            MyLWJGLUtil.glLoadIdentity();
            GL11.glViewport(0, 0, screenWidth, screenHeight);
            GLU.gluPerspective(45.0f, (float) screenWidth / (float) screenHeight, 1f, 1000.0f);

            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            MyLWJGLUtil.glLoadIdentity();

            GL11.glDisable(GL11.GL_DEPTH_TEST);
            GL11.glDepthMask(false);

            glEnable(GL_LINE_SMOOTH);
            glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

            GL11.glLineWidth(3f);
            MyLWJGLUtil.glColor4f(1, 1, 1, finishAlive > 0 ? finishAlive * .01f : 1);

            glDisable(GL_TEXTURE_2D);

            finishedDisplayLightning = true;

            for (Vector3f[] arc : lightning) {
                MyLWJGLUtil.glBegin(GL11.GL_LINE_STRIP);
                glNormal3f(0, 0, 1);
                for (Vector3f r : arc) {
                    if (r.z > alive) {
                        finishedDisplayLightning = false;
                        break;
                    }
                    MyLWJGLUtil.glVertex3f(r.x, r.y, -1);
                }
                MyLWJGLUtil.glEnd();

                MyLWJGLUtil.glColor4f(.5f, .5f, .5f, finishAlive > 0 ? finishAlive * .01f : .8f);
                GL11.glLineWidth(2f);
            }

            glEnable(GL_TEXTURE_2D);

            if (finishedDisplayLightning && finishAlive == 0) {
                displayFlash = 10;
            }
        }

        public boolean isFinished() {
            return finishedDisplayLightning && displayFlash == 0 && finishAlive == 0f;
        }

        public void captureScreenForBloom() {
            if (displayFlash > 0 || isFinished()) {
                return;
            }

            glEnable(GL_TEXTURE_2D);

            GL11.glBindTexture(GL11.GL_TEXTURE_2D, BLOOM_TEXTURE_ID);
            GL11.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, 0, 0, screenWidth, screenHeight);
        }

        public void bloom() {
            if (isFinished()) {
                return;
            }

            glMatrixMode(GL_PROJECTION);
            glLoadIdentity();
            glOrtho(0, WIDTH, HEIGHT, 0, 0.1f, 2048);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            glTranslatef(0, 0, -1.0f);
            glDisable(GL_CULL_FACE);
            glDisable(GL_FOG);
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            //Render full-screen effects
            glBlendFunc(GL_ONE, GL_ONE);
            glDisable(GL_DEPTH_TEST);
            glDepthMask(false);

            if (finishedDisplayLightning && displayFlash > 0) {
                displayFlash--;

                glDisable(GL_TEXTURE_2D);

                glBegin(GL_QUADS);
                {
                    GL11.glColor4f(1, 1, 1, 1);
                    glVertex2i(0, HEIGHT);
                    glVertex2i(0, 0);
                    glVertex2i(WIDTH, 0);
                    glVertex2i(WIDTH, HEIGHT);
                }
                glEnd();

                glEnable(GL_TEXTURE_2D);

                if (displayFlash <= 0) {
                    displayFlash = 0;
                    finishAlive = alive;
                }
            } else {

                if( alive > 3 ) {
                    glEnable(GL_TEXTURE_2D);

                    float a = .3f;

                    //Simple bloom effect
                    glBegin(GL_QUADS);
                    //color = WorldBloomColor () * BLOOM_SCALING;
                    final int bloom_radius = 3;
                    final int bloom_step = 1;
                    for (int x = -bloom_radius; x <= bloom_radius; x += bloom_step) {
                        GL11.glColor4f(.07f, .051f, .09f, a);
                        //GL11.glColor4f(.02f, .028f, .03f, a);
                        for (int y = -bloom_radius; y <= bloom_radius; y += bloom_step) {
                            if (Math.abs(x) == Math.abs(y) && x != 0)
                                continue;

                            glTexCoord2f(0, 0);
                            glVertex2i(x, y + HEIGHT);
                            glTexCoord2f(0, 1);
                            glVertex2i(x, y);
                            glTexCoord2f(1, 1);
                            glVertex2i(x + WIDTH, y);
                            glTexCoord2f(1, 0);
                            glVertex2i(x + WIDTH, y + HEIGHT);
                        }

                        if (x < 0) {
                            a += .1f;
                        } else if (x > 0) {
                            a -= .1f;
                        }
                    }
                    glEnd();

                    GL11.glMatrixMode(GL11.GL_PROJECTION);
                    MyLWJGLUtil.glLoadIdentity();
                    GL11.glViewport(0, 0, screenWidth, screenHeight);
                    GLU.gluPerspective(45.0f, (float) screenWidth / (float) screenHeight, 1f, 1000.0f);

                    GL11.glMatrixMode(GL11.GL_MODELVIEW);
                    MyLWJGLUtil.glLoadIdentity();

                    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

                    GL11.glBindTexture(GL11.GL_TEXTURE_2D, flashSphereTextureID);

                    final float scale = 15f;

                    final float temp = finishAlive == 0f ? alive : finishAlive;

                    if (finishAlive > 0f) {
                        finishAlive -= 1.5f;
                    } else {
                        finishAlive = 0;
                    }

                    // draw flash sphere
                    glBegin(GL_QUADS);
                    {
                        //color = WorldBloomColor () * BLOOM_SCALING;
                        GL11.glColor4f(1, 1, 1, .005f * temp);
                        //GL11.glColor4f(1, 1, 1, 1);
                        //GL11.glColor4f(.02f, .028f, .03f, a);
                        glTexCoord2f(0, 0);
                        glVertex3f(initX - temp / screenWidth * scale, initY + temp / screenHeight * scale, -1);
                        glTexCoord2f(0, 1);
                        glVertex3f(initX - temp / screenWidth * scale, initY - temp / screenHeight * scale, -1);
                        glTexCoord2f(1, 1);
                        glVertex3f(initX + temp / screenWidth * scale, initY - temp / screenHeight * scale, -1);
                        glTexCoord2f(1, 0);
                        glVertex3f(initX + temp / screenWidth * scale, initY + temp / screenHeight * scale, -1);
                    }
                    glEnd();

                }

            }
        }

        public void sound() {
            playSound--;
            if (hasToPlaySound) {
                switch (rand.nextInt(6)) {
                    case 0:
                        SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 1.mp3").getAbsolutePath());
                        break;
                    case 1:
                        SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 2.mp3").getAbsolutePath());
                        break;
                    case 2:
                        SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 3.mp3").getAbsolutePath());
                        break;
                    case 3:
                        SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 4.mp3").getAbsolutePath());
                        break;
                    case 4:
                        SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 5.mp3").getAbsolutePath());
                        break;
                    case 5:
                        SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 6.mp3").getAbsolutePath());
                        break;
                }

                hasToPlaySound = false;
            }
        }
    }


    public static void main(String[] args) {
        try {
            Display.setFullscreen(true);
            try {
                final DisplayMode[] availableDisplayModes = org.lwjgl.util.Display.getAvailableDisplayModes(
                        WIDTH, HEIGHT, WIDTH, HEIGHT, 32, 32, 60, 60);
                org.lwjgl.util.Display.setDisplayMode(availableDisplayModes, new String[]{
                        "width=" + WIDTH,
                        "height=" + HEIGHT,
                        "freq=" + 60,
                        "bpp=" + 32
                });
            } catch (Exception e) {
                System.err.println("ERROR: could not start full screen mode, switching to windowed mode!");
                try {
                    // wait 3s so that the player sees the message!
                    Thread.sleep(3000L);
                } catch (InterruptedException ignored) {
                }
            Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
            }


            Display.create(new PixelFormat(32, 8, 24, 8, 0));


            MyLWJGLUtil.init();

            SoundManager.resetGlobalMusicVolume();
            SoundManager.setGlobalMusicVolume(.5f);
            //SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/wind.mp3").getAbsolutePath(), "Wind");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/rain.mp3").getAbsolutePath(), "Rain");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 1.mp3").getAbsolutePath(), "TS1");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 2.mp3").getAbsolutePath(), "TS2");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 3.mp3").getAbsolutePath(), "TS3");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 4.mp3").getAbsolutePath(), "TS4");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 5.mp3").getAbsolutePath(), "TS5");
            SoundManager.loadMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/thunder strike 6.mp3").getAbsolutePath(), "TS6");
            SoundManager.initializeSoundSystem(new ContentLoader("file://../"));

            //SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/wind.mp3").getAbsolutePath());

            glClearColor(0, 0, 0, 1f); // blue

            float ratio = WIDTH / HEIGHT;

            int flashSphere = loadTexture("./flash sphere.png", 256, 256);
            final Lightning l = new Lightning(WIDTH, HEIGHT, flashSphere);

            final Rain r = new Rain(WIDTH, HEIGHT);

            glDisable(GL_FOG);
            GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
            GL11.glShadeModel(GL11.GL_SMOOTH);

            GL11.glMatrixMode(GL11.GL_PROJECTION);
            MyLWJGLUtil.glLoadIdentity();
            GL11.glViewport(0, 0, WIDTH, HEIGHT);
            GLU.gluPerspective(45.0f, (float) WIDTH / (float) HEIGHT, 1f, 1000.0f);

            GL11.glMatrixMode(GL11.GL_MODELVIEW);
            MyLWJGLUtil.glLoadIdentity();

            GL11.glDisable(GL11.GL_ALPHA_TEST);
            GL11.glDisable(GL11.GL_FOG);
            GL11.glDisable(GL11.GL_LIGHTING);
            GL11.glEnable(GL11.GL_BLEND);
            GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE);

            int i = 0;
            final float step = 0.001f;
            int framesWithoutStorm = 0;

            SoundManager.playMusic("file:///" + new File("..", "modules/levelchaos/src/data/levelchaos/music/rain.mp3").getAbsolutePath());

            while (i < 5000 && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE) && !Display.isCloseRequested()) {
                Thread.yield();

                final long s = System.currentTimeMillis();
                i++;

                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                l.sound();

                l.draw();

                r.draw();
                
                l.captureScreenForBloom();

                l.bloom();


                // flip buffers
                Display.update();
                Display.sync(60);

                if (l.isFinished()) {
                    framesWithoutStorm--;
                    if (framesWithoutStorm <= 0) {
                        l.reset();
                    }
                } else {
                    framesWithoutStorm = rand.nextInt(150) + 150;
                }

                final long e = System.currentTimeMillis();
                //System.out.println((float) 1/*i*/ / (float) (e - s) * 1000 + " FPS");
            }

            Display.destroy();

            AL.destroy();
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    private static int loadTexture(String path, int width, int height) throws IOException {
        BufferedImage a = ImageIO.read(new File(path));
        byte[] data = ((DataBufferByte) a.getRaster().getDataBuffer()).getData();

        switch (a.getType()) {
            case BufferedImage.TYPE_4BYTE_ABGR:
                convertFromARGBToBGRA(data);
                break;
            case BufferedImage.TYPE_3BYTE_BGR:
                convertFromBGRToRGB(data);
                break;
        }

        final int bytesPerPixel = a.getColorModel().getPixelSize() / 8;

        final ByteBuffer scratch = ByteBuffer.allocateDirect(width * height * bytesPerPixel).order(ByteOrder.nativeOrder());
        data = ((DataBufferByte) a.getRaster().getDataBuffer()).getData();

        for (int i = 0; i < height; i++) {
            scratch.put(data, ((0 + i) * a.getWidth()) * bytesPerPixel, width * bytesPerPixel);
        }

        scratch.rewind();

        final IntBuffer buf = ByteBuffer.allocateDirect(4).order(ByteOrder.nativeOrder()).asIntBuffer();
        // Create Texture In OpenGL
        glGenTextures(buf);

        // System.out.println("Created texture: " + buf.get(0) + " (alpha: " + buffImage.getColorModel().hasAlpha() + ")");

        // Create Nearest Filtered Texture
        glBindTexture(GL_TEXTURE_2D, buf.get(0));
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);

        GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, EXTTextureEnvCombine.GL_COMBINE_EXT);
        GL11.glTexEnvi(GL11.GL_TEXTURE_ENV, EXTTextureEnvCombine.GL_COMBINE_RGB_EXT, GL11.GL_MODULATE);

        // manage openGL pixel types
        if (!a.getColorModel().hasAlpha()) {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, scratch);
        } else {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scratch);
        }

        return buf.get(0);
    }

    private static void convertFromARGBToBGRA(final byte[] data) {
        final int size = data.length;
        for (int i = 0; i < size; i += 4) {
            final int a = data[i] & 0x000000FF;
            final int r = data[i + 1] & 0x000000FF;
            final int g = data[i + 2] & 0x000000FF;
            final int b = data[i + 3] & 0x000000FF;

            data[i] = (byte) b;
            data[i + 1] = (byte) g;
            data[i + 2] = (byte) r;
            data[i + 3] = (byte) a;
        }
    }

    private static void convertFromBGRToRGB(final byte[] data) {
        final int size = data.length;
        for (int i = 0; i < size; i += 3) {
            final int b = data[i] & 0xFF;
            final int g = data[i + 1] & 0xFF;
            final int r = data[i + 2] & 0xFF;

            data[i] = (byte) r;
            data[i + 1] = (byte) g;
            data[i + 2] = (byte) b;
        }
    }

}
Powered by Google Project Hosting