Package fcagnin.jgltut.tut17

Source Code of fcagnin.jgltut.tut17.CubePointLight$LightBlock

package fcagnin.jgltut.tut17;

import fcagnin.jglsdk.BufferableData;
import fcagnin.jglsdk.glimg.DdsLoader;
import fcagnin.jglsdk.glimg.ImageSet;
import fcagnin.jglsdk.glimg.ImageSet.Dimensions;
import fcagnin.jglsdk.glimg.ImageSet.SingleImage;
import fcagnin.jglsdk.glimg.TextureGenerator;
import fcagnin.jglsdk.glm.*;
import fcagnin.jglsdk.glutil.MatrixStack;
import fcagnin.jglsdk.glutil.MousePoles.*;
import fcagnin.jgltut.LWJGLWindow;
import fcagnin.jgltut.framework.*;
import fcagnin.jgltut.framework.Scene.SceneNode;
import fcagnin.jgltut.framework.SceneBinders.UniformIntBinder;
import fcagnin.jgltut.framework.SceneBinders.UniformMat4Binder;
import fcagnin.jgltut.framework.SceneBinders.UniformVec3Binder;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;

import java.nio.FloatBuffer;
import java.util.ArrayList;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL12.*;
import static org.lwjgl.opengl.GL13.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_SRGB;
import static org.lwjgl.opengl.GL30.glBindBufferRange;
import static org.lwjgl.opengl.GL31.GL_UNIFORM_BUFFER;
import static org.lwjgl.opengl.GL32.GL_DEPTH_CLAMP;
import static org.lwjgl.opengl.GL33.*;


/**
* Visit https://github.com/integeruser/jgltut for info, updates and license terms.
* <p/>
* Part IV. Texturing
* Chapter 17. Spotlight on Textures
* http://www.arcsynthesis.org/gltut/Texturing/Tutorial%2017.html
* <p/>
* W,A,S,D  - move the camera forward/backwards and left/right, relative to the camera's current orientation. Holding
* SHIFT with these keys will move in smaller increments.
* Q,E      - raise and lower the camera, relative to its current orientation. Holding SHIFT with these keys will move
* in smaller increments.
* SPACE    - reset the projected flashlight direction.
* T        - toggle viewing of the current target point.
* G        - toggle all of the regular lighting on and off.
* P        - toggle pausing.
* 1,2      - toggle between different light textures.
* <p/>
* LEFT   CLICKING and DRAGGING         - rotate the camera around the target point, both horizontally and vertically.
* LEFT   CLICKING and DRAGGING + CTRL  - rotate the camera around the target point, either horizontally or vertically.
* LEFT   CLICKING and DRAGGING + ALT   - change the camera's up direction.
* RIGHT  CLICKING and DRAGGING         - rotate the orientation of the light horizontally and vertically, relative to
* the current camera view.
* RIGHT  CLICKING and DRAGGING + CTRL  - rotate the orientation of the light horizontally or vertically only, relative
* to the current camera view.
* RIGHT  CLICKING and DRAGGING + ALT   - spin the orientation of the light.
* WHEEL  SCROLLING                     - move the camera closer to it's target point or farther away.
*
* @author integeruser
*/
public class CubePointLight extends LWJGLWindow {
    public static void main(String[] args) {
        Framework.CURRENT_TUTORIAL_DATAPATH = "/fcagnin/jgltut/tut17/data/";

        new CubePointLight().start( displayWidth, displayHeight );
    }


    @Override
    protected void init() {
        glEnable( GL_CULL_FACE );
        glCullFace( GL_BACK );
        glFrontFace( GL_CW );

        final float depthZNear = 0.0f;
        final float depthZFar = 1.0f;

        glEnable( GL_DEPTH_TEST );
        glDepthMask( true );
        glDepthFunc( GL_LEQUAL );
        glDepthRange( depthZNear, depthZFar );
        glEnable( GL_DEPTH_CLAMP );
        glEnable( GL_FRAMEBUFFER_SRGB );

        // Setup our Uniform Buffers
        projectionUniformBuffer = glGenBuffers();
        glBindBuffer( GL_UNIFORM_BUFFER, projectionUniformBuffer );
        glBufferData( GL_UNIFORM_BUFFER, ProjectionBlock.SIZE, GL_STREAM_DRAW );

        glBindBufferRange( GL_UNIFORM_BUFFER, projectionBlockIndex, projectionUniformBuffer, 0, ProjectionBlock.SIZE );

        createSamplers();
        loadTextures();

        try {
            loadAndSetupScene();
        } catch ( Exception exception ) {
            exception.printStackTrace();
            System.exit( -1 );
        }

        lightUniformBuffer = glGenBuffers();
        glBindBuffer( GL_UNIFORM_BUFFER, lightUniformBuffer );
        glBufferData( GL_UNIFORM_BUFFER, LightBlock.SIZE, GL_STREAM_DRAW );

        glBindBufferRange( GL_UNIFORM_BUFFER, lightBlockIndex, lightUniformBuffer, 0, LightBlock.SIZE );

        glBindBuffer( GL_UNIFORM_BUFFER, 0 );
    }

    @Override
    protected void display() {
        timer.update( getElapsedTime() );

        glClearColor( 0.8f, 0.8f, 0.8f, 1.0f );
        glClearDepth( 1.0f );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        final Mat4 cameraMatrix = viewPole.calcMatrix();
        final Mat4 lightView = lightPole.calcMatrix();

        MatrixStack modelMatrix = new MatrixStack();
        modelMatrix.applyMatrix( cameraMatrix );

        buildLights( cameraMatrix );

        nodes.get( 0 ).nodeSetOrient( Glm.rotate( new Quaternion( 1.0f ), 360.0f * timer.getAlpha(),
                new Vec3( 0.0f, 1.0f, 0.0f ) ) );

        nodes.get( 3 ).nodeSetOrient( Quaternion.mul( spinBarOrient, Glm.rotate( new Quaternion( 1.0f ),
                360.0f * timer.getAlpha(), new Vec3( 0.0f, 0.0f, 1.0f ) ) ) );

        {
            MatrixStack persMatrix = new MatrixStack();
            persMatrix.perspective( 60.0f, displayWidth / (float) displayHeight, zNear, zFar );

            ProjectionBlock projData = new ProjectionBlock();
            projData.cameraToClipMatrix = persMatrix.top();

            glBindBuffer( GL_UNIFORM_BUFFER, projectionUniformBuffer );
            glBufferData( GL_UNIFORM_BUFFER, projData.fillAndFlipBuffer( mat4Buffer ), GL_STREAM_DRAW );
            glBindBuffer( GL_UNIFORM_BUFFER, 0 );
        }

        glActiveTexture( GL_TEXTURE0 + lightProjTexUnit );
        glBindTexture( GL_TEXTURE_CUBE_MAP, lightTextures[currTextureIndex] );
        glBindSampler( lightProjTexUnit, samplers[currSampler] );

        {
            MatrixStack lightProjStack = new MatrixStack();
            lightProjStack.applyMatrix( Glm.inverse( lightView ) );
            lightProjStack.applyMatrix( Glm.inverse( cameraMatrix ) );

            lightProjMatBinder.setValue( lightProjStack.top() );

            Vec4 worldLightPos = lightView.getColumn( 3 );
            Vec3 lightPos = new Vec3( Mat4.mul( cameraMatrix, worldLightPos ) );

            camLightPosBinder.setValue( lightPos );
        }

        glViewport( 0, 0, displayWidth, displayHeight );
        scene.render( modelMatrix.top() );

        {
            // Draw axes
            modelMatrix.push();

            modelMatrix.applyMatrix( lightView );
            modelMatrix.scale( 15.0f );

            glUseProgram( coloredProg );
            glUniformMatrix4( coloredModelToCameraMatrixUnif, false,
                    modelMatrix.top().fillAndFlipBuffer( mat4Buffer ) );
            axesMesh.render();

            modelMatrix.pop();
        }

        if ( drawCameraPos ) {
            modelMatrix.push();

            // Draw lookat point.
            modelMatrix.setIdentity();
            modelMatrix.translate( 0.0f, 0.0f, -viewPole.getView().radius );
            modelMatrix.scale( 0.5f );

            glDisable( GL_DEPTH_TEST );
            glDepthMask( false );
            glUseProgram( unlitProg );
            glUniformMatrix4( unlitModelToCameraMatrixUnif, false, modelMatrix.top().fillAndFlipBuffer( mat4Buffer ) );
            glUniform4f( unlitObjectColorUnif, 0.25f, 0.25f, 0.25f, 1.0f );
            sphereMesh.render( "flat" );
            glDepthMask( true );
            glEnable( GL_DEPTH_TEST );
            glUniform4f( unlitObjectColorUnif, 1.0f, 1.0f, 1.0f, 1.0f );
            sphereMesh.render( "flat" );

            modelMatrix.pop();
        }

        glActiveTexture( GL_TEXTURE0 + lightProjTexUnit );
        glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
        glBindSampler( lightProjTexUnit, 0 );
    }

    @Override
    protected void reshape(int w, int h) {
        displayWidth = w;
        displayHeight = h;
    }

    @Override
    protected void update() {
        while ( Mouse.next() ) {
            int eventButton = Mouse.getEventButton();

            if ( eventButton != -1 ) {
                boolean pressed = Mouse.getEventButtonState();
                MousePole.forwardMouseButton( viewPole, eventButton, pressed, Mouse.getX(), Mouse.getY() );
                MousePole.forwardMouseButton( lightPole, eventButton, pressed, Mouse.getX(), Mouse.getY() );
            } else {
                // Mouse moving or mouse scrolling
                int dWheel = Mouse.getDWheel();

                if ( dWheel != 0 ) {
                    MousePole.forwardMouseWheel( viewPole, dWheel, dWheel, Mouse.getX(), Mouse.getY() );
                    MousePole.forwardMouseWheel( lightPole, dWheel, dWheel, Mouse.getX(), Mouse.getY() );
                }

                if ( Mouse.isButtonDown( 0 ) || Mouse.isButtonDown( 1 ) || Mouse.isButtonDown( 2 ) ) {
                    MousePole.forwardMouseMotion( viewPole, Mouse.getX(), Mouse.getY() );
                    MousePole.forwardMouseMotion( lightPole, Mouse.getX(), Mouse.getY() );
                }
            }
        }


        float lastFrameDuration = getLastFrameDuration() * 10 / 1000.0f;

        if ( Keyboard.isKeyDown( Keyboard.KEY_W ) ) {
            viewPole.charPress( Keyboard.KEY_W, Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ||
                    Keyboard.isKeyDown( Keyboard.KEY_RSHIFT ), lastFrameDuration );
        } else if ( Keyboard.isKeyDown( Keyboard.KEY_S ) ) {
            viewPole.charPress( Keyboard.KEY_S, Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ||
                    Keyboard.isKeyDown( Keyboard.KEY_RSHIFT ), lastFrameDuration );
        }

        if ( Keyboard.isKeyDown( Keyboard.KEY_D ) ) {
            viewPole.charPress( Keyboard.KEY_D, Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ||
                    Keyboard.isKeyDown( Keyboard.KEY_RSHIFT ), lastFrameDuration );
        } else if ( Keyboard.isKeyDown( Keyboard.KEY_A ) ) {
            viewPole.charPress( Keyboard.KEY_A, Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ||
                    Keyboard.isKeyDown( Keyboard.KEY_RSHIFT ), lastFrameDuration );
        }

        if ( Keyboard.isKeyDown( Keyboard.KEY_E ) ) {
            viewPole.charPress( Keyboard.KEY_E, Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ||
                    Keyboard.isKeyDown( Keyboard.KEY_RSHIFT ), lastFrameDuration );
        } else if ( Keyboard.isKeyDown( Keyboard.KEY_Q ) ) {
            viewPole.charPress( Keyboard.KEY_Q, Keyboard.isKeyDown( Keyboard.KEY_LSHIFT ) ||
                    Keyboard.isKeyDown( Keyboard.KEY_RSHIFT ), lastFrameDuration );
        }


        while ( Keyboard.next() ) {
            if ( Keyboard.getEventKeyState() ) {
                switch ( Keyboard.getEventKey() ) {
                    case Keyboard.KEY_SPACE:
                        lightPole.reset();
                        break;

                    case Keyboard.KEY_T:
                        drawCameraPos = !drawCameraPos;
                        break;

                    case Keyboard.KEY_G:
                        showOtherLights = !showOtherLights;
                        break;

                    case Keyboard.KEY_P:
                        timer.togglePause();
                        break;

                    case Keyboard.KEY_1:
                    case Keyboard.KEY_2:
                        int number = Keyboard.getEventKey() - Keyboard.KEY_1;
                        currTextureIndex = number;
                        System.out.printf( "%s\n", texDefs[currTextureIndex].name );
                        break;

                    case Keyboard.KEY_ESCAPE:
                        leaveMainLoop();
                        break;
                }
            }
        }
    }


    ////////////////////////////////
    private final float zNear = 1.0f;
    private final float zFar = 1000.0f;

    private int coloredModelToCameraMatrixUnif;
    private int coloredProg;

    private int unlitProg;
    private int unlitModelToCameraMatrixUnif;
    private int unlitObjectColorUnif;


    private final FloatBuffer mat4Buffer = BufferUtils.createFloatBuffer( Mat4.SIZE );
    private final FloatBuffer lightBlockBuffer = BufferUtils.createFloatBuffer( LightBlock.SIZE );


    private void loadAndSetupScene() {
        scene = new Scene( "projCube_scene.xml" );

        nodes = new ArrayList<>();
        nodes.add( scene.findNode( "cube" ) );
        nodes.add( scene.findNode( "rightBar" ) );
        nodes.add( scene.findNode( "leaningBar" ) );
        nodes.add( scene.findNode( "spinBar" ) );
        nodes.add( scene.findNode( "diorama" ) );
        nodes.add( scene.findNode( "floor" ) );

        lightNumBinder = new UniformIntBinder();
        SceneBinders.associateUniformWithNodes( nodes, lightNumBinder, "numberOfLights" );
        SceneBinders.setStateBinderWithNodes( nodes, lightNumBinder );

        lightProjMatBinder = new UniformMat4Binder();
        SceneBinders.associateUniformWithNodes( nodes, lightProjMatBinder, "cameraToLightProjMatrix" );
        SceneBinders.setStateBinderWithNodes( nodes, lightProjMatBinder );

        camLightPosBinder = new UniformVec3Binder();
        SceneBinders.associateUniformWithNodes( nodes, camLightPosBinder, "cameraSpaceProjLightPos" );
        SceneBinders.setStateBinderWithNodes( nodes, camLightPosBinder );

        int unlit = scene.findProgram( "p_unlit" );
        sphereMesh = scene.findMesh( "m_sphere" );

        int colored = scene.findProgram( "p_colored" );
        axesMesh = scene.findMesh( "m_axes" );

        // No more things that can throw.
        spinBarOrient = nodes.get( 3 ).nodeGetOrient();
        unlitProg = unlit;
        unlitModelToCameraMatrixUnif = glGetUniformLocation( unlit, "modelToCameraMatrix" );
        unlitObjectColorUnif = glGetUniformLocation( unlit, "objectColor" );

        coloredProg = colored;
        coloredModelToCameraMatrixUnif = glGetUniformLocation( colored, "modelToCameraMatrix" );
    }


    ////////////////////////////////
    private static int displayWidth = 500;
    private static int displayHeight = 500;

    private Scene scene;
    private ArrayList<SceneNode> nodes;
    private Mesh sphereMesh, axesMesh;

    private UniformMat4Binder lightProjMatBinder;
    private UniformVec3Binder camLightPosBinder;

    private Timer timer = new Timer( Timer.Type.LOOP, 10.0f );

    private Quaternion spinBarOrient;

    private boolean showOtherLights = true;
    private boolean drawCameraPos;


    ////////////////////////////////
    // View setup.
    private ViewData initialView = new ViewData(
            new Vec3( 0.0f, 0.0f, 10.0f ),
            new Quaternion( 0.909845f, 0.16043f, -0.376867f, -0.0664516f ),
            25.0f,
            0.0f
    );

    private ViewScale initialViewScale = new ViewScale(
            5.0f, 70.0f,
            2.0f, 0.5f,
            2.0f, 0.5f,
            90.0f / 250.0f
    );


    private ObjectData initLightData = new ObjectData(
            new Vec3( 0.0f, 0.0f, 10.0f ),
            new Quaternion( 1.0f, 0.0f, 0.0f, 0.0f )
    );


    private ViewPole viewPole = new ViewPole( initialView, initialViewScale, MouseButtons.MB_LEFT_BTN );
    private ObjectPole lightPole = new ObjectPole( initLightData, 90.0f / 250.0f, MouseButtons.MB_RIGHT_BTN, viewPole );


    ////////////////////////////////
    private final TexDef[] texDefs = {
            new TexDef( "IrregularPoint.dds", "Irregular Point Light" ),
            new TexDef( "Planetarium.dds", "Planetarium" )
    };
    private final int NUM_LIGHT_TEXTURES = texDefs.length;
    private int[] lightTextures = new int[texDefs.length];
    private int currTextureIndex = 0;

    private class TexDef {
        String filename;
        String name;

        TexDef(String filename, String name) {
            this.filename = filename;
            this.name = name;
        }
    }


    private void loadTextures() {
        try {
            for ( int textureIndex = 0; textureIndex < NUM_LIGHT_TEXTURES; textureIndex++ ) {
                lightTextures[textureIndex] = glGenTextures();

                String filePath = Framework.findFileOrThrow( texDefs[textureIndex].filename );
                ImageSet imageSet = DdsLoader.loadFromFile( filePath );

                glBindTexture( GL_TEXTURE_CUBE_MAP, lightTextures[textureIndex] );
                glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0 );
                glTexParameteri( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0 );

                Dimensions imageDimensions = imageSet.getDimensions();
                int imageFormat = TextureGenerator.getInternalFormat( imageSet.getFormat(), 0 );

                for ( int face = 0; face < 6; ++face ) {
                    SingleImage singleImage = imageSet.getImage( 0, 0, face );

                    glCompressedTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, imageFormat,
                            imageDimensions.width, imageDimensions.height, 0, singleImage.getImageData() );
                }

                glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }


    ////////////////////////////////
    private final int NUM_SAMPLERS = 1;

    private int[] samplers = new int[NUM_SAMPLERS];
    private int currSampler = 0;


    private void createSamplers() {
        for ( int samplerIndex = 0; samplerIndex < NUM_SAMPLERS; samplerIndex++ ) {
            samplers[samplerIndex] = glGenSamplers();
            glSamplerParameteri( samplers[samplerIndex], GL_TEXTURE_MAG_FILTER, GL_LINEAR );
            glSamplerParameteri( samplers[samplerIndex], GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        }

        glSamplerParameteri( samplers[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
        glSamplerParameteri( samplers[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
        glSamplerParameteri( samplers[0], GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
    }


    ////////////////////////////////
    private final int projectionBlockIndex = 0;

    private int projectionUniformBuffer;

    private class ProjectionBlock extends BufferableData<FloatBuffer> {
        Mat4 cameraToClipMatrix;

        static final int SIZE = Mat4.SIZE;

        @Override
        public FloatBuffer fillBuffer(FloatBuffer buffer) {
            return cameraToClipMatrix.fillBuffer( buffer );
        }
    }


    ////////////////////////////////
    private static final int MAX_NUMBER_OF_LIGHTS = 4;

    private final int lightBlockIndex = 1;
    private final int lightProjTexUnit = 3;

    private int lightUniformBuffer;
    private UniformIntBinder lightNumBinder;

    private class PerLight extends BufferableData<FloatBuffer> {
        Vec4 cameraSpaceLightPos;
        Vec4 lightIntensity;

        static final int SIZE = Vec4.SIZE + Vec4.SIZE;

        @Override
        public FloatBuffer fillBuffer(FloatBuffer buffer) {
            cameraSpaceLightPos.fillBuffer( buffer );
            lightIntensity.fillBuffer( buffer );

            return buffer;
        }
    }

    private class LightBlock extends BufferableData<FloatBuffer> {
        Vec4 ambientIntensity;
        float lightAttenuation;
        float maxIntensity;
        float padding[] = new float[2];
        PerLight lights[] = new PerLight[MAX_NUMBER_OF_LIGHTS];

        static final int SIZE = Vec4.SIZE + ((1 + 1 + 2) * FLOAT_SIZE) + PerLight.SIZE * MAX_NUMBER_OF_LIGHTS;

        @Override
        public FloatBuffer fillBuffer(FloatBuffer buffer) {
            ambientIntensity.fillBuffer( buffer );
            buffer.put( lightAttenuation );
            buffer.put( maxIntensity );
            buffer.put( padding );

            for ( PerLight light : lights ) {
                if ( light == null ) { break; }

                light.fillBuffer( buffer );
            }

            return buffer;
        }
    }


    private void buildLights(Mat4 camMatrix) {
        LightBlock lightData = new LightBlock();
        lightData.ambientIntensity = new Vec4( 0.2f, 0.2f, 0.2f, 1.0f );
        lightData.lightAttenuation = 1.0f / (30.0f * 30.0f);
        lightData.maxIntensity = 2.0f;

        lightData.lights[0] = new PerLight();
        lightData.lights[0].lightIntensity = new Vec4( 0.2f, 0.2f, 0.2f, 1.0f );
        lightData.lights[0].cameraSpaceLightPos = Mat4.mul( camMatrix,
                Glm.normalize( new Vec4( -0.2f, 0.5f, 0.5f, 0.0f ) ) );

        lightData.lights[1] = new PerLight();
        lightData.lights[1].lightIntensity = new Vec4( 3.5f, 6.5f, 3.0f, 1.0f ).scale( 0.5f );
        lightData.lights[1].cameraSpaceLightPos = Mat4.mul( camMatrix, new Vec4( 5.0f, 6.0f, 0.5f, 1.0f ) );

        if ( showOtherLights ) {
            lightNumBinder.setValue( 2 );
        } else {
            lightNumBinder.setValue( 0 );
        }

        glBindBuffer( GL_UNIFORM_BUFFER, lightUniformBuffer );
        glBufferData( GL_UNIFORM_BUFFER, lightData.fillAndFlipBuffer( lightBlockBuffer ), GL_STREAM_DRAW );
    }
}
TOP

Related Classes of fcagnin.jgltut.tut17.CubePointLight$LightBlock

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.