org.joml.Vector3f - java examples

Here are the examples of the java api org.joml.Vector3f taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

79 Examples 7

19 View Complete Implementation : BlockOutlineRenderer.java
Copyright GNU General Public License v3.0
Author : Lux-Vacuos
public void vertex3f(Vector3f pos) {
    this.pos.add(pos);
}

19 View Complete Implementation : DirectionalLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public void setDirection(Vector3f direction) {
    this.direction = direction;
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXRotateY() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().rotateY((float) Math.toRadians(90));
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, 1), dir, 1E-7f);
}

19 View Complete Implementation : Vector3Mover.java
Copyright MIT License
Author : JOML-CI
/**
 * This is an integrator providing smooth convergence of a <code>current</code>
 * position to a <code>target</code> position in 3D space, based on velocity and
 * acceleration computations.
 * <p>
 * Initially, the current and the target position is zero and no velocity or
 * acceleration is applied. Once, the user sets the {@link #target} to some
 * value, the {@link #current} value will begin to converge against that target
 * using time and maximum acceleration constraints.
 * <p>
 * To advance the integration, the client invokes {@link #update(float)} with
 * the elased time in seconds since the last call to update.
 * <p>
 * This clreplaced does not provide tweening, which is a parameterization of a
 * function between two given points. It instead uses a simulation based on
 * velocity and acceleration and allowing to alter the {@link #target} to any
 * value at any time.
 *
 * @author Kai Burjack
 */
public clreplaced Vector3Mover {

    public static final float SMALL_VALUE_THRESHOLD = 1E-5f;

    /**
     * The maximum acceleration directly towards the target.
     */
    public float maxDirectAcceleration = 20.0f;

    /**
     * The maximum deceleration directly towards the target.
     */
    public float maxDirectDeceleration = 100.0f;

    /**
     * The maximum deceleration (in positive values) towards the velocity
     * component perpendicular to the target direction.
     */
    public float maxPerpendicularDeceleration = 30.0f;

    /**
     * The current position. This will change after an invocation to
     * {@link #update(float)}.
     */
    public final Vector3f current = new Vector3f();

    /**
     * The desired target position. Set this to any value at any time.
     */
    public final Vector3f target = new Vector3f();

    /**
     * The current acceleration. MUST NOT be modified from outside.
     */
    public final Vector3f acceleration = new Vector3f();

    /**
     * The current velocity. MUST NOT be modified from outside.
     */
    public final Vector3f velocity = new Vector3f();

    /* Some helper objects. JOML did not use any, but joml-camera now has to. */
    private final Vector3f currentToTarget = new Vector3f();

    private final Vector3f currentToTargetNormalized = new Vector3f();

    private final Vector3f perpendicularVelocityComponent = new Vector3f();

    private final Vector3f directVelocityComponent = new Vector3f();

    private final Vector3f directAcceleration = new Vector3f();

    private final Vector3f perpendicularAcceleration = new Vector3f();

    private final Vector3f newAcceleration = new Vector3f();

    private final Vector3f newVelocity = new Vector3f();

    private final Vector3f way = new Vector3f();

    /**
     * Update the simulation based on the elapsed time since the last update.
     *
     * @param elapsedTimeInSeconds
     *            the elapsed time in seconds since the last update
     */
    public void update(float elapsedTimeInSeconds) {
        /* Compute the way we need to got */
        currentToTarget.set(target).sub(current);
        if (currentToTarget.length() < 1E-5) {
            return;
        }
        currentToTargetNormalized.set(currentToTarget).normalize();
        /*
         * Dot product in order to project the velocity onto the target
         * direction.
         */
        float dot = currentToTargetNormalized.dot(velocity);
        /*
         * Compute the perpendicular velocity component (how much of the current
         * velocity is directed exactly perpendicular to the target).
         */
        perpendicularVelocityComponent.set(currentToTargetNormalized);
        perpendicularVelocityComponent.mul(dot);
        perpendicularVelocityComponent.sub(velocity);
        /*
         * Now this contains the vector to eliminate the perpendicular
         * component, i.e. it is directed towards the line of sight between the
         * target and current.
         */
        /*
         * Compute the direct velocity component (how much of the current
         * velocity is directed towards the target).
         */
        directVelocityComponent.set(currentToTargetNormalized);
        directVelocityComponent.mul(Math.abs(dot));
        /*
         * In which time can we reach complete zero perpendicular movement?
         */
        float timeToStopPerpendicular = perpendicularVelocityComponent.length() / maxPerpendicularDeceleration;
        /*
         * This is how long our whole movement to the target needs to take at
         * least in order for the perpendicular movement to stop (which we
         * want!). The problem now is that the length of the direct way depends
         * on the perpendicular movement. The more we move in the perpendicular
         * direction, the longer the direct path becomes.
         */
        /*
         * Compute how far we would move along the direct component if we
         * completely eliminate this velocity component.
         */
        float directStopDistance = directVelocityComponent.lengthSquared() / (2.0f * maxDirectDeceleration);
        /*
         * Now see how much time it will take us to fully stop the direct
         * movement.
         */
        float timeToStopDirect = directVelocityComponent.length() / maxDirectDeceleration;
        /*
         * Check if we need to decelerate the direct component, because we would
         * move too far if we didn't.
         */
        if (dot >= SMALL_VALUE_THRESHOLD && (directStopDistance >= currentToTarget.length() || timeToStopPerpendicular > timeToStopDirect)) {
            /* We need to decelerate the direct component */
            directAcceleration.set(currentToTargetNormalized).mul(maxDirectDeceleration).negate();
        } else {
            /*
             * We can still accelerate directly towards the target. Compute the
             * necessary acceleration to reach the target in the elapsed time.
             */
            float neededDirectAcc = currentToTarget.length() / elapsedTimeInSeconds;
            float directAcc = neededDirectAcc;
            /* Check if that would be too much acceleration */
            if (neededDirectAcc > maxDirectAcceleration) {
                /* Limit to maximum allowed acceleration */
                directAcc = maxDirectAcceleration;
            }
            directAcceleration.set(currentToTargetNormalized).mul(directAcc);
        }
        /*
         * Compute the perpendicular deceleration. If maximum deceleration would
         * be too much for the time, we compute the optimal deceleration based
         * on the elapsed time.
         */
        float neededPerpendicularAcc = perpendicularVelocityComponent.length() / elapsedTimeInSeconds;
        float perpendicularDeceleration = neededPerpendicularAcc;
        /* Check if that would be too much acceleration */
        if (neededPerpendicularAcc > maxPerpendicularDeceleration) {
            /* Limit to maximum allowed acceleration */
            perpendicularDeceleration = maxPerpendicularDeceleration;
        }
        /* If the perpendicular velocity would be too small */
        if (perpendicularVelocityComponent.length() > SMALL_VALUE_THRESHOLD) {
            perpendicularAcceleration.set(perpendicularVelocityComponent).normalize().mul(perpendicularDeceleration);
        } else {
            perpendicularAcceleration.set(0.0f, 0.0f, 0.0f);
        }
        /* Compute new acceleration */
        newAcceleration.set(directAcceleration).add(perpendicularAcceleration);
        /* Compute new velocity */
        newVelocity.set(newAcceleration).mul(elapsedTimeInSeconds).add(velocity);
        velocity.set(newVelocity);
        way.set(velocity).mul(elapsedTimeInSeconds);
        if (way.length() > currentToTarget.length()) {
            velocity.zero();
            way.set(currentToTarget);
        }
        /* Compute new current position based on updated velocity */
        current.add(way);
    }
}

19 View Complete Implementation : Matrix4x3fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXRotateXY() {
    Vector3f dir = new Vector3f();
    Matrix4x3f m = new Matrix4x3f().rotateY((float) Math.toRadians(90)).rotateX((float) Math.toRadians(45));
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 1, 1).normalize(), dir, 1E-7f);
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXPerspectiveRotateY() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().perspective((float) Math.toRadians(90), 1.0f, 0.1f, 100.0f).rotateY((float) Math.toRadians(90));
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, -1), dir, 1E-7f);
}

19 View Complete Implementation : Mesh.java
Copyright Apache License 2.0
Author : lwjglgamedev
public void setColour(Vector3f colour) {
    this.colour = colour;
}

19 View Complete Implementation : IntersectionfTest.java
Copyright MIT License
Author : JOML-CI
public static void testIntersectRaySphere() {
    Vector3f origin = new Vector3f();
    Vector3f dir = new Vector3f(1, 0, 0);
    Vector3f center = new Vector3f(5, 0, 0);
    float radiusSquared = 1.0f;
    Vector2f result = new Vector2f();
    boolean intersect = Intersectionf.intersectRaySphere(origin, dir, center, radiusSquared, result);
    replacedertTrue(intersect);
    replacedertEquals(4.0f, result.x, 1E-6f);
    replacedertEquals(6.0f, result.y, 1E-6f);
}

19 View Complete Implementation : SpotLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public void setConeDirection(Vector3f coneDirection) {
    this.coneDirection = coneDirection;
}

19 View Complete Implementation : IntersectionfTest.java
Copyright MIT License
Author : JOML-CI
public static void testIntersectRayTriangleFrontPX() {
    Vector3f origin = new Vector3f();
    Vector3f dir = new Vector3f(1, 0, 0);
    Vector3f v0 = new Vector3f(1, -1, -1);
    Vector3f v1 = new Vector3f(1, -1, 1);
    Vector3f v2 = new Vector3f(1, 1, 0);
    float t = Intersectionf.intersectRayTriangleFront(origin, dir, v0, v1, v2, 0.0f);
    replacedertEquals(1.0f, t, 0.0f);
}

19 View Complete Implementation : FreeCamera.java
Copyright MIT License
Author : JOML-CI
/**
 * Compute the world-space 'forward' vector and store it into <code>dest</code>.
 *
 * @param dest
 *          will hold the result
 * @return dest
 */
public Vector3f forward(Vector3f dest) {
    return rotation.positiveZ(dest).negate();
}

19 View Complete Implementation : Matrix4x3fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveYRotateX() {
    Vector3f dir = new Vector3f();
    Matrix4x3f m = new Matrix4x3f().rotateX((float) Math.toRadians(90));
    m.positiveY(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, -1), dir, 1E-7f);
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPerspectiveOrigin() {
    Matrix4f m = new Matrix4f().perspective((float) Math.toRadians(90), 1.0f, 0.1f, 100.0f).lookAt(6, 0, 1, 0, 0, 0, 0, 1, 0);
    Vector3f origin = new Vector3f();
    m.perspectiveOrigin(origin);
    TestUtil.replacedertVector3fEquals(new Vector3f(6, 0, 1), origin, 1E-5f);
    // test symmetric frustum with some modelview translation and rotation
    m = new Matrix4f().perspective((float) Math.toRadians(90), 1.0f, 0.1f, 100.0f).lookAt(-5, 2, 1, 0, 1, 0, 0, 1, 0);
    m.perspectiveOrigin(origin);
    TestUtil.replacedertVector3fEquals(new Vector3f(-5, 2, 1), origin, 1E-5f);
    // test asymmetric frustum
    m = new Matrix4f().frustum(-0.1f, 0.5f, -0.1f, 0.1f, 0.1f, 100.0f).lookAt(-5, 2, 1, 0, 1, 0, 0, 1, 0);
    m.perspectiveOrigin(origin);
    TestUtil.replacedertVector3fEquals(new Vector3f(-5, 2, 1), origin, 1E-5f);
}

19 View Complete Implementation : CameraDemo.java
Copyright MIT License
Author : JOML-CI
public clreplaced CameraDemo {

    GLFWErrorCallback errorCallback;

    GLFWKeyCallback keyCallback;

    GLFWFramebufferSizeCallback fbCallback;

    long window;

    int width = 300;

    int height = 300;

    // Declare matrices for two cameras
    Matrix4f[] projMatrix = { new Matrix4f(), new Matrix4f() };

    Matrix4f[] viewMatrix = { new Matrix4f(), new Matrix4f() };

    int active = 0;

    int inactive = 1;

    // And a model matrix for a rotating cube
    Matrix4f modelMatrix = new Matrix4f();

    // Temporary vector
    Vector3f tmp = new Vector3f();

    // Rotation of the inactive camera
    float rotate = 0.0f;

    float[] rotation = { 0.0f, 0.0f };

    void run() {
        try {
            init();
            loop();
            glfwDestroyWindow(window);
            keyCallback.free();
        } finally {
            glfwTerminate();
            errorCallback.free();
        }
    }

    void init() {
        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
        if (!glfwInit())
            throw new IllegalStateException("Unable to initialize GLFW");
        // Configure our window
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
        window = glfwCreateWindow(width, height, "Hello Cameras!", NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");
        System.out.println("Press 'C' to switch between the two cameras");
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {

            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                    glfwSetWindowShouldClose(window, true);
                if (key == GLFW_KEY_C && action == GLFW_RELEASE)
                    switchCamera();
                if (key == GLFW_KEY_LEFT && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
                    rotate = 1.0f;
                } else if (key == GLFW_KEY_LEFT && (action == GLFW_RELEASE)) {
                    rotate = 0.0f;
                } else if (key == GLFW_KEY_RIGHT && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
                    rotate = -1.0f;
                } else if (key == GLFW_KEY_RIGHT && (action == GLFW_RELEASE)) {
                    rotate = 0.0f;
                }
            }
        });
        glfwSetFramebufferSizeCallback(window, fbCallback = new GLFWFramebufferSizeCallback() {

            public void invoke(long window, int w, int h) {
                if (w > 0 && h > 0) {
                    width = w;
                    height = h;
                }
            }
        });
        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
        glfwMakeContextCurrent(window);
        glfwSwapInterval(0);
        glfwShowWindow(window);
        IntBuffer framebufferSize = BufferUtils.createIntBuffer(2);
        nglfwGetFramebufferSize(window, memAddress(framebufferSize), memAddress(framebufferSize) + 4);
        width = framebufferSize.get(0);
        height = framebufferSize.get(1);
    }

    void renderCube() {
        glBegin(GL_QUADS);
        glColor3f(0.0f, 0.0f, 0.2f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glColor3f(0.0f, 0.0f, 1.0f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glColor3f(1.0f, 0.0f, 0.0f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glColor3f(0.2f, 0.0f, 0.0f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glColor3f(0.0f, 1.0f, 0.0f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glColor3f(0.0f, 0.2f, 0.0f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glEnd();
    }

    void renderGrid() {
        glBegin(GL_LINES);
        glColor3f(0.2f, 0.2f, 0.2f);
        for (int i = -20; i <= 20; i++) {
            glVertex3f(-20.0f, 0.0f, i);
            glVertex3f(20.0f, 0.0f, i);
            glVertex3f(i, 0.0f, -20.0f);
            glVertex3f(i, 0.0f, 20.0f);
        }
        glEnd();
    }

    void renderFrustum(Matrix4f m) {
        // Perspective origin to near plane
        Vector3f v = tmp;
        glBegin(GL_LINES);
        glColor3f(0.2f, 0.2f, 0.2f);
        for (int i = 0; i < 4; i++) {
            m.perspectiveOrigin(v);
            glVertex3f(v.x, v.y, v.z);
            m.frustumCorner(i, v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
        // Near plane
        glBegin(GL_LINE_STRIP);
        glColor3f(0.8f, 0.2f, 0.2f);
        for (int i = 0; i < 4 + 1; i++) {
            m.frustumCorner(i & 3, v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
        // Edges
        glBegin(GL_LINES);
        for (int i = 0; i < 4; i++) {
            m.frustumCorner(3 - i, v);
            glVertex3f(v.x, v.y, v.z);
            m.frustumCorner(4 + ((i + 2) & 3), v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
        // Far plane
        glBegin(GL_LINE_STRIP);
        for (int i = 0; i < 4 + 1; i++) {
            m.frustumCorner(4 + (i & 3), v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
    }

    void switchCamera() {
        active = 1 - active;
        inactive = 1 - inactive;
    }

    void loop() {
        GL.createCapabilities();
        // Set the clear color
        glClearColor(0.6f, 0.7f, 0.8f, 1.0f);
        // Enable depth testing
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        // Remember the current time.
        long firstTime = System.nanoTime();
        long lastTime = firstTime;
        // FloatBuffer for transferring matrices to OpenGL
        FloatBuffer fb = BufferUtils.createFloatBuffer(16);
        // Matrix to build combined model-view
        Matrix4f modelView = new Matrix4f();
        // Matrix to build combined view-projection
        Matrix4f viewProj = new Matrix4f();
        while (!glfwWindowShouldClose(window)) {
            long thisTime = System.nanoTime();
            float diff = (thisTime - firstTime) / 1E9f;
            float angle = diff;
            float delta = (thisTime - lastTime) / 1E9f;
            lastTime = thisTime;
            // Process rotation
            rotation[inactive] += rotate * delta;
            // Setup both camera's projection matrices
            projMatrix[0].setPerspective((float) Math.toRadians(40), (float) width / height, 1.0f, 20.0f);
            projMatrix[1].setPerspective((float) Math.toRadians(30), (float) width / height, 2.0f, 5.0f);
            // Load the active camera's projection
            glMatrixMode(GL_PROJECTION);
            glLoadMatrixf(projMatrix[active].get(fb));
            // Setup both camera's view matrices
            viewMatrix[0].setLookAt(0, 2, 10, 0, 0, 0, 0, 1, 0).rotateY(rotation[0]);
            viewMatrix[1].setLookAt(3, 1, 1, 0, 0, 0, 0, 1, 0).rotateY(rotation[1]);
            // Apply model transformation to active camera's view
            modelMatrix.rotationY(angle * (float) Math.toRadians(10));
            viewMatrix[active].mul(modelMatrix, modelView);
            // And load it
            glMatrixMode(GL_MODELVIEW);
            glLoadMatrixf(modelView.get(fb));
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glViewport(0, 0, width, height);
            // Render a cube
            renderCube();
            // Load the active camera's view again to render the inactive camera's frustum
            glLoadMatrixf(viewMatrix[active].get(fb));
            // Compute and render the inactive camera's frustum
            viewProj.set(projMatrix[inactive]).mul(viewMatrix[inactive]);
            renderFrustum(viewProj);
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    }

    public static void main(String[] args) {
        new CameraDemo().run();
    }
}

19 View Complete Implementation : WorldScene.java
Copyright MIT License
Author : integeruser
/**
 * Visit https://github.com/integeruser/jgltut for info and updates.
 * Original: https://bitbucket.org/alfonse/gltut/src/default/Tut%2007%20World%20in%20Motion/World%20Scene.cpp
 * <p>
 * Part II. Positioning
 * Chapter 7. World in Motion
 * <p>
 * Function                                     Increase/Left   Decrease/Right
 * Move camera target up/down                          E               Q
 * Move camera target horizontally                     A               D
 * Move camera target vertically                       W               S
 * Rotate camera horizontally around target            L               J
 * Rotate camera vertically around target              I               K
 * Move camera towards/away from target                U               O
 * In addition, if you hold down the SHIFT key while pressing any of the last six keys, then the affected control will
 * be much slower.
 * <p>
 * SPACE    - toggle the appearance of an object indicating the position of the camera point.
 */
public clreplaced WorldScene extends Tutorial {

    public static void main(String[] args) {
        Framework.CURRENT_TUTORIAL_DATAPATH = "/integeruser/jgltut/tut07/data/";
        new WorldScene().start(700, 700);
    }

    @Override
    protected void init() {
        initializeProgram();
        coneMesh = new Mesh("UnitConeTint.xml");
        cylinderMesh = new Mesh("UnitCylinderTint.xml");
        cubeTintMesh = new Mesh("UnitCubeTint.xml");
        cubeColorMesh = new Mesh("UnitCubeColor.xml");
        planeMesh = new Mesh("UnitPlane.xml");
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(true);
        glDepthFunc(GL_LEQUAL);
        glDepthRange(0.0f, 1.0f);
        glEnable(GL_DEPTH_CLAMP);
        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if (action == GLFW_PRESS) {
                switch(key) {
                    case GLFW_KEY_SPACE:
                        drawLookatPoint = !drawLookatPoint;
                        System.out.printf("Target: %f, %f, %f\n", camTarget.x, camTarget.y, camTarget.z);
                        System.out.printf("Position: %f, %f, %f\n", sphereCamRelPos.x, sphereCamRelPos.y, sphereCamRelPos.z);
                        break;
                    case GLFW_KEY_ESCAPE:
                        glfwSetWindowShouldClose(window, true);
                        break;
                }
            }
        });
    }

    @Override
    protected void display() {
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClearDepth(1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        {
            final Vector3f camPos = resolveCamPosition();
            MatrixStackf camMatrix = new MatrixStackf();
            camMatrix.mul(calcLookAtMatrix(camPos, camTarget, new Vector3f(0.0f, 1.0f, 0.0f)));
            glUseProgram(uniformColor.theProgram);
            glUniformMatrix4fv(uniformColor.worldToCameraMatrixUnif, false, camMatrix.get(mat4Buffer));
            glUseProgram(objectColor.theProgram);
            glUniformMatrix4fv(objectColor.worldToCameraMatrixUnif, false, camMatrix.get(mat4Buffer));
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.worldToCameraMatrixUnif, false, camMatrix.get(mat4Buffer));
            glUseProgram(0);
            MatrixStackf modelMatrix = new MatrixStackf(4);
            // Render the ground plane.
            {
                modelMatrix.pushMatrix();
                modelMatrix.scale(100.0f, 1.0f, 100.0f);
                glUseProgram(uniformColor.theProgram);
                glUniformMatrix4fv(uniformColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
                glUniform4f(uniformColor.baseColorUnif, 0.302f, 0.416f, 0.0589f, 1.0f);
                planeMesh.render();
                glUseProgram(0);
                modelMatrix.popMatrix();
            }
            // Draw the trees.
            drawForest(modelMatrix);
            // Draw the building.
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate(20.0f, 0.0f, -10.0f);
                drawParthenon(modelMatrix);
                modelMatrix.popMatrix();
            }
            if (drawLookatPoint) {
                glDisable(GL_DEPTH_TEST);
                modelMatrix.pushMatrix();
                Vector3f cameraAimVec = new Vector3f(camTarget).sub(camPos);
                modelMatrix.translate(0.0f, 0.0f, -cameraAimVec.length());
                modelMatrix.scale(1.0f, 1.0f, 1.0f);
                Matrix4f idenreplacedy = new Matrix4f();
                glUseProgram(objectColor.theProgram);
                glUniformMatrix4fv(objectColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
                glUniformMatrix4fv(objectColor.worldToCameraMatrixUnif, false, idenreplacedy.get(mat4Buffer));
                cubeColorMesh.render();
                glUseProgram(0);
                modelMatrix.popMatrix();
                glEnable(GL_DEPTH_TEST);
            }
        }
    }

    @Override
    protected void reshape(int w, int h) {
        float zNear = 1.0f;
        float zFar = 1000.0f;
        Matrix4f persMatrix = new Matrix4f();
        persMatrix.perspective((float) Math.toRadians(45.0f), (w / (float) h), zNear, zFar);
        glUseProgram(uniformColor.theProgram);
        glUniformMatrix4fv(uniformColor.cameraToClipMatrixUnif, false, persMatrix.get(mat4Buffer));
        glUseProgram(objectColor.theProgram);
        glUniformMatrix4fv(objectColor.cameraToClipMatrixUnif, false, persMatrix.get(mat4Buffer));
        glUseProgram(uniformColorTint.theProgram);
        glUniformMatrix4fv(uniformColorTint.cameraToClipMatrixUnif, false, persMatrix.get(mat4Buffer));
        glUseProgram(0);
        glViewport(0, 0, w, h);
    }

    @Override
    protected void update() {
        final float scale = 5;
        if (isKeyPressed(GLFW_KEY_W)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.z = camTarget.z - 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.z = camTarget.z - 4.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_S)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.z = camTarget.z + 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.z = camTarget.z + 4.0f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_D)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.x = camTarget.x + 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.x = camTarget.x + 4.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_A)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.x = camTarget.x - 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.x = camTarget.x - 4.0f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_E)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.y = camTarget.y - 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.y = camTarget.y - 4.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_Q)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.y = camTarget.y + 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.y = camTarget.y + 4.0f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_I)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.y = sphereCamRelPos.y - 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.y = sphereCamRelPos.y - 11.25f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_K)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.y = sphereCamRelPos.y + 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.y = sphereCamRelPos.y + 11.25f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_J)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.x = sphereCamRelPos.x - 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.x = sphereCamRelPos.x - 11.25f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_L)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.x = sphereCamRelPos.x + 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.x = sphereCamRelPos.x + 11.25f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_O)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.z = sphereCamRelPos.z - 0.5f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.z = sphereCamRelPos.z - 5.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_U)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.z = sphereCamRelPos.z + 0.5f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.z = sphereCamRelPos.z + 5.0f * lastFrameDuration * scale;
            }
        }
        sphereCamRelPos.y = Math.min(Math.max(sphereCamRelPos.y, -78.75f), -1.0f);
        camTarget.y = camTarget.y > 0.0f ? camTarget.y : 0.0f;
        sphereCamRelPos.z = sphereCamRelPos.z > 5.0f ? sphereCamRelPos.z : 5.0f;
    }

    // //////////////////////////////
    private ProgramData uniformColor;

    private ProgramData objectColor;

    private ProgramData uniformColorTint;

    private clreplaced ProgramData {

        int theProgram;

        int modelToWorldMatrixUnif;

        int worldToCameraMatrixUnif;

        int cameraToClipMatrixUnif;

        int baseColorUnif;
    }

    private void initializeProgram() {
        uniformColor = loadProgram("PosOnlyWorldTransform.vert", "ColorUniform.frag");
        objectColor = loadProgram("PosColorWorldTransform.vert", "ColorPreplacedthrough.frag");
        uniformColorTint = loadProgram("PosColorWorldTransform.vert", "ColorMultUniform.frag");
    }

    private ProgramData loadProgram(String vertexShaderFileName, String fragmentShaderFileName) {
        ArrayList<Integer> shaderList = new ArrayList<>();
        shaderList.add(Framework.loadShader(GL_VERTEX_SHADER, vertexShaderFileName));
        shaderList.add(Framework.loadShader(GL_FRAGMENT_SHADER, fragmentShaderFileName));
        ProgramData data = new ProgramData();
        data.theProgram = Framework.createProgram(shaderList);
        data.modelToWorldMatrixUnif = glGetUniformLocation(data.theProgram, "modelToWorldMatrix");
        data.worldToCameraMatrixUnif = glGetUniformLocation(data.theProgram, "worldToCameraMatrix");
        data.cameraToClipMatrixUnif = glGetUniformLocation(data.theProgram, "cameraToClipMatrix");
        data.baseColorUnif = glGetUniformLocation(data.theProgram, "baseColor");
        return data;
    }

    // //////////////////////////////
    private Mesh coneMesh;

    private Mesh cylinderMesh;

    private Mesh cubeTintMesh;

    private Mesh cubeColorMesh;

    private Mesh planeMesh;

    private boolean drawLookatPoint = false;

    private Vector3f camTarget = new Vector3f(0.0f, 0.4f, 0.0f);

    // In spherical coordinates.
    private Vector3f sphereCamRelPos = new Vector3f(67.5f, -46.0f, 150.0f);

    private Vector3f resolveCamPosition() {
        float phi = (float) Math.toRadians(sphereCamRelPos.x);
        float theta = (float) Math.toRadians(sphereCamRelPos.y + 90.0f);
        float sinTheta = (float) Math.sin(theta);
        float cosTheta = (float) Math.cos(theta);
        float cosPhi = (float) Math.cos(phi);
        float sinPhi = (float) Math.sin(phi);
        Vector3f dirToCamera = new Vector3f(sinTheta * cosPhi, cosTheta, sinTheta * sinPhi);
        return (dirToCamera.mul(sphereCamRelPos.z)).add(camTarget);
    }

    private Matrix4f calcLookAtMatrix(Vector3f cameraPt, Vector3f lookPt, Vector3f upPt) {
        Vector3f lookDir = new Vector3f(lookPt).sub(cameraPt).normalize();
        Vector3f upDir = new Vector3f(upPt).normalize();
        Vector3f rightDir = new Vector3f(lookDir).cross(upDir).normalize();
        Vector3f perpUpDir = new Vector3f(rightDir).cross(lookDir);
        Matrix4f rotMat = new Matrix4f();
        rotMat.m00(rightDir.x);
        rotMat.m01(rightDir.y);
        rotMat.m02(rightDir.z);
        rotMat.m10(perpUpDir.x);
        rotMat.m11(perpUpDir.y);
        rotMat.m12(perpUpDir.z);
        rotMat.m20(-lookDir.x);
        rotMat.m21(-lookDir.y);
        rotMat.m22(-lookDir.z);
        rotMat.transpose();
        Matrix4f transMat = new Matrix4f().setTranslation(-cameraPt.x, -cameraPt.y, -cameraPt.z);
        return rotMat.mul(transMat);
    }

    // //////////////////////////////
    private final TreeData[] forest = { new TreeData(-45.0f, -40.0f, 2.0f, 3.0f), new TreeData(-42.0f, -35.0f, 2.0f, 3.0f), new TreeData(-39.0f, -29.0f, 2.0f, 4.0f), new TreeData(-44.0f, -26.0f, 3.0f, 3.0f), new TreeData(-40.0f, -22.0f, 2.0f, 4.0f), new TreeData(-36.0f, -15.0f, 3.0f, 3.0f), new TreeData(-41.0f, -11.0f, 2.0f, 3.0f), new TreeData(-37.0f, -6.0f, 3.0f, 3.0f), new TreeData(-45.0f, 0.0f, 2.0f, 3.0f), new TreeData(-39.0f, 4.0f, 3.0f, 4.0f), new TreeData(-36.0f, 8.0f, 2.0f, 3.0f), new TreeData(-44.0f, 13.0f, 3.0f, 3.0f), new TreeData(-42.0f, 17.0f, 2.0f, 3.0f), new TreeData(-38.0f, 23.0f, 3.0f, 4.0f), new TreeData(-41.0f, 27.0f, 2.0f, 3.0f), new TreeData(-39.0f, 32.0f, 3.0f, 3.0f), new TreeData(-44.0f, 37.0f, 3.0f, 4.0f), new TreeData(-36.0f, 42.0f, 2.0f, 3.0f), new TreeData(-32.0f, -45.0f, 2.0f, 3.0f), new TreeData(-30.0f, -42.0f, 2.0f, 4.0f), new TreeData(-34.0f, -38.0f, 3.0f, 5.0f), new TreeData(-33.0f, -35.0f, 3.0f, 4.0f), new TreeData(-29.0f, -28.0f, 2.0f, 3.0f), new TreeData(-26.0f, -25.0f, 3.0f, 5.0f), new TreeData(-35.0f, -21.0f, 3.0f, 4.0f), new TreeData(-31.0f, -17.0f, 3.0f, 3.0f), new TreeData(-28.0f, -12.0f, 2.0f, 4.0f), new TreeData(-29.0f, -7.0f, 3.0f, 3.0f), new TreeData(-26.0f, -1.0f, 2.0f, 4.0f), new TreeData(-32.0f, 6.0f, 2.0f, 3.0f), new TreeData(-30.0f, 10.0f, 3.0f, 5.0f), new TreeData(-33.0f, 14.0f, 2.0f, 4.0f), new TreeData(-35.0f, 19.0f, 3.0f, 4.0f), new TreeData(-28.0f, 22.0f, 2.0f, 3.0f), new TreeData(-33.0f, 26.0f, 3.0f, 3.0f), new TreeData(-29.0f, 31.0f, 3.0f, 4.0f), new TreeData(-32.0f, 38.0f, 2.0f, 3.0f), new TreeData(-27.0f, 41.0f, 3.0f, 4.0f), new TreeData(-31.0f, 45.0f, 2.0f, 4.0f), new TreeData(-28.0f, 48.0f, 3.0f, 5.0f), new TreeData(-25.0f, -48.0f, 2.0f, 3.0f), new TreeData(-20.0f, -42.0f, 3.0f, 4.0f), new TreeData(-22.0f, -39.0f, 2.0f, 3.0f), new TreeData(-19.0f, -34.0f, 2.0f, 3.0f), new TreeData(-23.0f, -30.0f, 3.0f, 4.0f), new TreeData(-24.0f, -24.0f, 2.0f, 3.0f), new TreeData(-16.0f, -21.0f, 2.0f, 3.0f), new TreeData(-17.0f, -17.0f, 3.0f, 3.0f), new TreeData(-25.0f, -13.0f, 2.0f, 4.0f), new TreeData(-23.0f, -8.0f, 2.0f, 3.0f), new TreeData(-17.0f, -2.0f, 3.0f, 3.0f), new TreeData(-16.0f, 1.0f, 2.0f, 3.0f), new TreeData(-19.0f, 4.0f, 3.0f, 3.0f), new TreeData(-22.0f, 8.0f, 2.0f, 4.0f), new TreeData(-21.0f, 14.0f, 2.0f, 3.0f), new TreeData(-16.0f, 19.0f, 2.0f, 3.0f), new TreeData(-23.0f, 24.0f, 3.0f, 3.0f), new TreeData(-18.0f, 28.0f, 2.0f, 4.0f), new TreeData(-24.0f, 31.0f, 2.0f, 3.0f), new TreeData(-20.0f, 36.0f, 2.0f, 3.0f), new TreeData(-22.0f, 41.0f, 3.0f, 3.0f), new TreeData(-21.0f, 45.0f, 2.0f, 3.0f), new TreeData(-12.0f, -40.0f, 2.0f, 4.0f), new TreeData(-11.0f, -35.0f, 3.0f, 3.0f), new TreeData(-10.0f, -29.0f, 1.0f, 3.0f), new TreeData(-9.0f, -26.0f, 2.0f, 2.0f), new TreeData(-6.0f, -22.0f, 2.0f, 3.0f), new TreeData(-15.0f, -15.0f, 1.0f, 3.0f), new TreeData(-8.0f, -11.0f, 2.0f, 3.0f), new TreeData(-14.0f, -6.0f, 2.0f, 4.0f), new TreeData(-12.0f, 0.0f, 2.0f, 3.0f), new TreeData(-7.0f, 4.0f, 2.0f, 2.0f), new TreeData(-13.0f, 8.0f, 2.0f, 2.0f), new TreeData(-9.0f, 13.0f, 1.0f, 3.0f), new TreeData(-13.0f, 17.0f, 3.0f, 4.0f), new TreeData(-6.0f, 23.0f, 2.0f, 3.0f), new TreeData(-12.0f, 27.0f, 1.0f, 2.0f), new TreeData(-8.0f, 32.0f, 2.0f, 3.0f), new TreeData(-10.0f, 37.0f, 3.0f, 3.0f), new TreeData(-11.0f, 42.0f, 2.0f, 2.0f), new TreeData(15.0f, 5.0f, 2.0f, 3.0f), new TreeData(15.0f, 10.0f, 2.0f, 3.0f), new TreeData(15.0f, 15.0f, 2.0f, 3.0f), new TreeData(15.0f, 20.0f, 2.0f, 3.0f), new TreeData(15.0f, 25.0f, 2.0f, 3.0f), new TreeData(15.0f, 30.0f, 2.0f, 3.0f), new TreeData(15.0f, 35.0f, 2.0f, 3.0f), new TreeData(15.0f, 40.0f, 2.0f, 3.0f), new TreeData(15.0f, 45.0f, 2.0f, 3.0f), new TreeData(25.0f, 5.0f, 2.0f, 3.0f), new TreeData(25.0f, 10.0f, 2.0f, 3.0f), new TreeData(25.0f, 15.0f, 2.0f, 3.0f), new TreeData(25.0f, 20.0f, 2.0f, 3.0f), new TreeData(25.0f, 25.0f, 2.0f, 3.0f), new TreeData(25.0f, 30.0f, 2.0f, 3.0f), new TreeData(25.0f, 35.0f, 2.0f, 3.0f), new TreeData(25.0f, 40.0f, 2.0f, 3.0f), new TreeData(25.0f, 45.0f, 2.0f, 3.0f) };

    private clreplaced TreeData {

        float xPos;

        float zPos;

        float trunkHeight;

        float coneHeight;

        TreeData(float xPos, float zPos, float trunkHeight, float coneHeight) {
            this.xPos = xPos;
            this.zPos = zPos;
            this.trunkHeight = trunkHeight;
            this.coneHeight = coneHeight;
        }
    }

    private void drawForest(MatrixStackf modelMatrix) {
        for (TreeData currTree : forest) {
            modelMatrix.pushMatrix();
            modelMatrix.translate(currTree.xPos, 0.0f, currTree.zPos);
            drawTree(modelMatrix, currTree.trunkHeight, currTree.coneHeight);
            modelMatrix.popMatrix();
        }
    }

    // Trees are 3x3 in X/Z, and trunkHeight + coneHeight in the Y.
    private void drawTree(MatrixStackf modelMatrix, float trunkHeight, float coneHeight) {
        // Draw trunk.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(1.0f, trunkHeight, 1.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.694f, 0.4f, 0.106f, 1.0f);
            cylinderMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the treetop.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, trunkHeight, 0.0f);
            modelMatrix.scale(3.0f, coneHeight, 3.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.0f, 1.0f, 0.0f, 1.0f);
            coneMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
    }

    // //////////////////////////////
    // Columns are 1x1 in the X/Z, and height units in the Y.
    private void drawColumn(MatrixStackf modelMatrix, float height) {
        final float columnBaseHeight = 0.25f;
        // Draw the bottom of the column.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(1.0f, columnBaseHeight, 1.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the top of the column.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, height - columnBaseHeight, 0.0f);
            modelMatrix.scale(1.0f, columnBaseHeight, 1.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the main column.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, columnBaseHeight, 0.0f);
            modelMatrix.scale(0.8f, height - (columnBaseHeight * 2.0f), 0.8f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cylinderMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
    }

    // //////////////////////////////
    private void drawParthenon(MatrixStackf modelMatrix) {
        final float parthenonWidth = 14.0f;
        final float parthenonLength = 20.0f;
        final float parthenonColumnHeight = 5.0f;
        final float parthenonBaseHeight = 1.0f;
        final float parthenonTopHeight = 2.0f;
        // Draw base.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(parthenonWidth, parthenonBaseHeight, parthenonLength);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw top.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, parthenonColumnHeight + parthenonBaseHeight, 0.0f);
            modelMatrix.scale(parthenonWidth, parthenonTopHeight, parthenonLength);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw columns.
        final float frontZVal = (parthenonLength / 2.0f) - 1.0f;
        final float rightXVal = (parthenonWidth / 2.0f) - 1.0f;
        for (int columnNum = 0; columnNum < (int) (parthenonWidth / 2.0f); columnNum++) {
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate((2.0f * columnNum) - (parthenonWidth / 2.0f) + 1.0f, parthenonBaseHeight, frontZVal);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate((2.0f * columnNum) - (parthenonWidth / 2.0f) + 1.0f, parthenonBaseHeight, -frontZVal);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
        }
        // Don't draw the first or last columns, since they've been drawn already.
        for (int columnNum = 1; columnNum < (int) ((parthenonLength - 2.0f) / 2.0f); columnNum++) {
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate(rightXVal, parthenonBaseHeight, (2.0f * columnNum) - (parthenonLength / 2.0f) + 1.0f);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate(-rightXVal, parthenonBaseHeight, (2.0f * columnNum) - (parthenonLength / 2.0f) + 1.0f);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
        }
        // Draw interior.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, 1.0f, 0.0f);
            modelMatrix.scale(parthenonWidth - 6.0f, parthenonColumnHeight, parthenonLength - 6.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(objectColor.theProgram);
            glUniformMatrix4fv(objectColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            cubeColorMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw headpiece.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, parthenonColumnHeight + parthenonBaseHeight + (parthenonTopHeight / 2.0f), parthenonLength / 2.0f);
            modelMatrix.rotateX(-135.0f);
            modelMatrix.rotateY(45.0f);
            glUseProgram(objectColor.theProgram);
            glUniformMatrix4fv(objectColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            cubeColorMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
    }
}

19 View Complete Implementation : Transformation.java
Copyright Apache License 2.0
Author : lwjglgamedev
public Matrix4f getWorldMatrix(Vector3f offset, Vector3f rotation, float scale) {
    return worldMatrix.translation(offset).rotateX((float) Math.toRadians(rotation.x)).rotateY((float) Math.toRadians(rotation.y)).rotateZ((float) Math.toRadians(rotation.z)).scale(scale);
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveZRotateX() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().rotateX((float) Math.toRadians(90));
    m.positiveZ(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 1, 0), dir, 1E-7f);
}

19 View Complete Implementation : PointLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public void setColor(Vector3f color) {
    this.color = color;
}

19 View Complete Implementation : LinAlgNamespace.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@OpMethod(op = net.imagej.ops.linalg.rotate.Rotate3f.clreplaced)
public Vector3f rotate(final Vector3f v, final AxisAngle4f axisAngle) {
    final Quaternionfc q = new Quaternionf(axisAngle);
    return (Vector3f) ops().run(Rotate3f.clreplaced, v, q);
}

19 View Complete Implementation : PointLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public clreplaced PointLight {

    private Vector3f color;

    private Vector3f position;

    private float intensity;

    private Attenuation attenuation;

    public PointLight(Vector3f color, Vector3f position, float intensity) {
        attenuation = new Attenuation(1, 0, 0);
        this.color = color;
        this.position = position;
        this.intensity = intensity;
    }

    public PointLight(Vector3f color, Vector3f position, float intensity, Attenuation attenuation) {
        this(color, position, intensity);
        this.attenuation = attenuation;
    }

    public PointLight(PointLight pointLight) {
        this(new Vector3f(pointLight.getColor()), new Vector3f(pointLight.getPosition()), pointLight.getIntensity(), pointLight.getAttenuation());
    }

    public Vector3f getColor() {
        return color;
    }

    public void setColor(Vector3f color) {
        this.color = color;
    }

    public Vector3f getPosition() {
        return position;
    }

    public void setPosition(Vector3f position) {
        this.position = position;
    }

    public float getIntensity() {
        return intensity;
    }

    public void setIntensity(float intensity) {
        this.intensity = intensity;
    }

    public Attenuation getAttenuation() {
        return attenuation;
    }

    public void setAttenuation(Attenuation attenuation) {
        this.attenuation = attenuation;
    }

    public static clreplaced Attenuation {

        private float constant;

        private float linear;

        private float exponent;

        public Attenuation(float constant, float linear, float exponent) {
            this.constant = constant;
            this.linear = linear;
            this.exponent = exponent;
        }

        public float getConstant() {
            return constant;
        }

        public void setConstant(float constant) {
            this.constant = constant;
        }

        public float getLinear() {
            return linear;
        }

        public void setLinear(float linear) {
            this.linear = linear;
        }

        public float getExponent() {
            return exponent;
        }

        public void setExponent(float exponent) {
            this.exponent = exponent;
        }
    }
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveYRotateX() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().rotateX((float) Math.toRadians(90));
    m.positiveY(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, -1), dir, 1E-7f);
}

19 View Complete Implementation : Matrix4x3fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXRotateY() {
    Vector3f dir = new Vector3f();
    Matrix4x3f m = new Matrix4x3f().rotateY((float) Math.toRadians(90));
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, 1), dir, 1E-7f);
}

19 View Complete Implementation : LinAlgNamespace.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@OpMethod(op = net.imagej.ops.linalg.rotate.Rotate3f.clreplaced)
public Vector3f rotate1(final Vector3f v, final Quaternionfc q) {
    return (Vector3f) ops().run(Rotate3f.clreplaced, v, v, q);
}

19 View Complete Implementation : Matrix4x3fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXYZLookAt() {
    Vector3f dir = new Vector3f();
    Matrix4x3f m = new Matrix4x3f().lookAt(0, 0, 0, -1, 0, 0, 0, 1, 0);
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, -1).normalize(), dir, 1E-7f);
    m.positiveY(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 1, 0).normalize(), dir, 1E-7f);
    m.positiveZ(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(1, 0, 0).normalize(), dir, 1E-7f);
}

19 View Complete Implementation : IntersectionfTest.java
Copyright MIT License
Author : JOML-CI
public static void testNotIntersectRayPlane() {
    Vector3f origin = new Vector3f();
    Vector3f dir = new Vector3f(-1, -1, -1);
    Vector3f point = new Vector3f(2, 2, 2);
    Vector3f normal = new Vector3f(-1, -1, -1);
    float t = Intersectionf.intersectRayPlane(origin, dir, point, normal, 0.0f);
    replacedertTrue(t == -1.0f);
}

19 View Complete Implementation : FreeCamera.java
Copyright MIT License
Author : JOML-CI
/**
 * Compute the world-space 'up' vector and store it into <code>dest</code>.
 *
 * @param dest
 *          will hold the result
 * @return dest
 */
public Vector3f up(Vector3f dest) {
    return rotation.positiveY(dest);
}

19 View Complete Implementation : Matrix4x3fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveZRotateX() {
    Vector3f dir = new Vector3f();
    Matrix4x3f m = new Matrix4x3f().rotateX((float) Math.toRadians(90));
    m.positiveZ(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 1, 0), dir, 1E-7f);
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXPerspectiveRotateXY() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().perspective((float) Math.toRadians(90), 1.0f, 0.1f, 100.0f).rotateY((float) Math.toRadians(90)).rotateX((float) Math.toRadians(45));
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, -1, -1).normalize(), dir, 1E-7f);
}

19 View Complete Implementation : OrthoCameraControl.java
Copyright MIT License
Author : JOML-CI
/**
 * Allows to control an orthographic camera with the mouse via panning and zooming.
 * <p>
 * Call the following methods:
 * <ul>
 * <li>{@link #setSize(int, int)} when the window/control size changes
 * <li>{@link #onMouseDown(int)} when further calls to {@link #onMouseMove(int, int)} should pan/rotate the view
 * <li>{@link #onMouseMove(int, int)} everytime the mouse moves
 * <li>{@link #onMouseUp(int)} when panning/rotating should stop
 * <li>{@link #zoom(float)} to zoom in/out
 * <li>{@link #viewproj()} to obtain the current view-projection matrix
 * <li>{@link #center(float, float)} to center the view onto the given coordinate
 * </ul>
 *
 * @author Kai Burjack
 */
public clreplaced OrthoCameraControl {

    public static int MOUSE_LEFT = 0;

    public static int MOUSE_RIGHT = 1;

    public static int MOUSE_CENTER = 2;

    private Matrix3x2f view = new Matrix3x2f();

    private Matrix4f viewproj = new Matrix4f();

    private Matrix4f invviewproj = new Matrix4f();

    private int[] vp = new int[4];

    private float mouseX, mouseY;

    private float mouseDownX, mouseDownY;

    private boolean[] mouseDown = new boolean[3];

    private Vector2f v = new Vector2f();

    private Vector3f v3 = new Vector3f();

    private float minRotateWinDistance2 = 100.0f * 100.0f;

    /**
     * @param extents
     *            the initial extents in world coordinates
     */
    public OrthoCameraControl(float extents) {
        view.view(-extents, extents, -extents, extents);
        update();
    }

    /**
     * @param minRotateWinDistance
     *            the minimum distance in window coordinates/pixels between
     *            the mouse down position and the current mouse position so
     *            that rotation is allowed
     */
    public void setMinRotateWinDistance(float minRotateWinDistance) {
        this.minRotateWinDistance2 = minRotateWinDistance * minRotateWinDistance;
    }

    /**
     * @param width
     *            the width of the control/window in window coordinates/pixels
     * @param height
     *            the height of the control/window in window coordinates/pixels
     */
    public void setSize(int width, int height) {
        vp[0] = 0;
        vp[1] = 0;
        vp[2] = width;
        vp[3] = height;
        update();
    }

    public Matrix4f viewproj() {
        return viewproj;
    }

    public Matrix4f invviewproj() {
        return invviewproj;
    }

    private void update() {
        float aspect = (float) vp[2] / vp[3];
        viewproj.setOrtho2D(-aspect, +aspect, -1, +1).mul(view).invertAffine(invviewproj);
    }

    /**
     * @param x
     *            the x coordiante of the point to center on in world coordinates
     * @param y
     *            the y coordiante of the point to center on in world coordinates
     */
    public void center(float x, float y) {
        view.setTranslation(0, 0).translate(-x, -y);
        update();
    }

    public void onMouseDown(int button) {
        mouseDownX = mouseX;
        mouseDownY = mouseY;
        mouseDown[button] = true;
        if (button == MOUSE_CENTER) {
            /* Reset rotation with mouse position as center */
            view.positiveX(v);
            float ang = (float) Math.atan2(v.y, v.x);
            Vector2f ndc = ndc(mouseDownX, mouseDownY);
            view.translateLocal(-ndc.x, -ndc.y).rotateLocal(ang).translateLocal(ndc.x, ndc.y);
            update();
        }
    }

    public void onMouseUp(int button) {
        mouseDown[button] = false;
    }

    /**
     * @param winX
     *            the x coordinate in window coordinates/pixels
     * @param winY
     *            the y coordinate in window coordinates/pixels
     */
    public void onMouseMove(int winX, int winY) {
        Vector2f ndc;
        if (mouseDown[MOUSE_LEFT]) {
            /* Move */
            ndc = ndc(winX, winY);
            float x0 = ndc.x, y0 = ndc.y;
            ndc = ndc(mouseX, mouseY);
            float x1 = ndc.x, y1 = ndc.y;
            view.translateLocal(x0 - x1, y0 - y1);
            update();
        } else if (mouseDown[MOUSE_RIGHT]) {
            /* Check if rotation is possible */
            float dx = winX - mouseDownX;
            float dy = winY - mouseDownY;
            if (dx * dx + dy * dy > minRotateWinDistance2) {
                /* Rotate */
                float dx0 = winX - mouseDownX, dy0 = winY - mouseDownY;
                float dx1 = mouseX - mouseDownX, dy1 = mouseY - mouseDownY;
                float ang = (float) Math.atan2(dx1 * dy0 - dy1 * dx0, dx1 * dx0 + dy1 * dy0);
                ndc = ndc(mouseDownX, mouseDownY);
                view.translateLocal(-ndc.x, -ndc.y).rotateLocal(ang).translateLocal(ndc.x, ndc.y);
                update();
            }
        }
        mouseX = winX;
        mouseY = winY;
    }

    private Vector2f ndc(float winX, float winY) {
        float aspect = (float) vp[2] / vp[3];
        float x = (winX / vp[2] * 2.0f - 1.0f) * aspect;
        float y = winY / vp[3] * 2.0f - 1.0f;
        return v.set(x, y);
    }

    /**
     * @param scale
     *            the scale factor. < 1.0 to zoom out; > 1.0 to zoom in
     */
    public void zoom(float scale) {
        Vector2f ndc = ndc(mouseX, mouseY);
        view.translateLocal(-ndc.x, -ndc.y).scaleLocal(scale, scale).translateLocal(ndc.x, ndc.y);
        update();
    }

    /**
     * @param dest
     *            contains the view rectangle as {x: minX, y: minY, z: maxX, w: maxY}
     * @return dest
     */
    public Vector4f viewRect(Vector4f dest) {
        float minX = Float.POSITIVE_INFINITY, minY = Float.POSITIVE_INFINITY;
        float maxX = Float.NEGATIVE_INFINITY, maxY = Float.NEGATIVE_INFINITY;
        for (int i = 0; i < 4; i++) {
            float x = ((i & 1) << 1) - 1.0f;
            float y = (((i >>> 1) & 1) << 1) - 1.0f;
            invviewproj.transformPosition(v3.set(x, y, 0));
            minX = minX < v3.x ? minX : v3.x;
            minY = minY < v3.y ? minY : v3.y;
            maxX = maxX > v3.x ? maxX : v3.x;
            maxY = maxY > v3.y ? maxY : v3.y;
        }
        return dest.set(minX, minY, maxX, maxY);
    }

    /**
     * @param cornerDest
     *            the corner at NDC (-1, -1) of the view
     * @param xDest
     *            the direction and length (in world coordinates) of the view along the NDC x axis
     * @param yDest
     *            the direction and length (in world coordinates) of the view along the NDC y axis
     */
    public void viewSpan(Vector2f cornerDest, Vector2f xDest, Vector2f yDest) {
        invviewproj.transformPosition(v3.set(-1, -1, 0));
        cornerDest.set(v3.x, v3.y);
        xDest.set(2 * invviewproj.m00(), 2 * invviewproj.m10());
        yDest.set(2 * invviewproj.m01(), 2 * invviewproj.m11());
    }
}

19 View Complete Implementation : WorldScene.java
Copyright MIT License
Author : integeruser
private Vector3f resolveCamPosition() {
    float phi = (float) Math.toRadians(sphereCamRelPos.x);
    float theta = (float) Math.toRadians(sphereCamRelPos.y + 90.0f);
    float sinTheta = (float) Math.sin(theta);
    float cosTheta = (float) Math.cos(theta);
    float cosPhi = (float) Math.cos(phi);
    float sinPhi = (float) Math.sin(phi);
    Vector3f dirToCamera = new Vector3f(sinTheta * cosPhi, cosTheta, sinTheta * sinPhi);
    return (dirToCamera.mul(sphereCamRelPos.z)).add(camTarget);
}

19 View Complete Implementation : BoxPickingDemo.java
Copyright MIT License
Author : JOML-CI
public clreplaced BoxPickingDemo {

    GLFWErrorCallback errorCallback;

    GLFWKeyCallback keyCallback;

    GLFWFramebufferSizeCallback fbCallback;

    GLFWCursorPosCallback cpCallback;

    GLFWMouseButtonCallback mbCallback;

    long window;

    int width = 1200;

    int height = 800;

    boolean windowed = true;

    float mouseX, mouseY;

    boolean[] keyDown = new boolean[GLFW.GLFW_KEY_LAST + 1];

    float movementSpeed = 3.666f;

    int LEVEL_LENGTH = 64;

    int LEVEL_HEIGHT = 64;

    static float GHOST_CUBE_ALPHA = 0.4f;

    boolean displayListNeedsRecompile;

    int displayList = -1;

    int selectedCube = -1;

    int ghostCube = -1;

    Vector3f pos = new Vector3f(0, 2, 0);

    Vector3f selectedPos = new Vector3f();

    Vector3f tmp = new Vector3f();

    Matrix4f viewMatrix = new Matrix4f();

    boolean[] boxes = new boolean[LEVEL_LENGTH * LEVEL_LENGTH * LEVEL_HEIGHT];

    {
        /* Make a base */
        Arrays.fill(boxes, 0, LEVEL_LENGTH * LEVEL_LENGTH, true);
        displayListNeedsRecompile = true;
    }

    void run() {
        try {
            init();
            loop();
            glfwDestroyWindow(window);
            keyCallback.free();
            fbCallback.free();
            cpCallback.free();
        } finally {
            glfwTerminate();
            errorCallback.free();
        }
    }

    void init() {
        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
        if (!glfwInit())
            throw new IllegalStateException("Unable to initialize GLFW");
        // Configure our window
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
        glfwWindowHint(GLFW_SAMPLES, 4);
        long monitor = glfwGetPrimaryMonitor();
        GLFWVidMode vidmode = glfwGetVideoMode(monitor);
        if (!windowed) {
            width = vidmode.width();
            height = vidmode.height();
        }
        window = glfwCreateWindow(width, height, "Hello picking!", !windowed ? monitor : NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");
        System.out.println("Press ESC to close the application.");
        System.out.println("Press W/S to move forward/backward.");
        System.out.println("Press A/D to strave left/right.");
        System.out.println("Press left shift to move faster.");
        System.out.println("Press left control/spacebar to move up/down.");
        System.out.println("Move the mouse to rotate.");
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {

            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_UNKNOWN)
                    return;
                if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                    glfwSetWindowShouldClose(window, true);
                if (action == GLFW_PRESS || action == GLFW_REPEAT)
                    keyDown[key] = true;
                else
                    keyDown[key] = false;
            }
        });
        glfwSetFramebufferSizeCallback(window, fbCallback = new GLFWFramebufferSizeCallback() {

            public void invoke(long window, int w, int h) {
                if (w > 0 && h > 0) {
                    width = w;
                    height = h;
                }
            }
        });
        glfwSetCursorPosCallback(window, cpCallback = new GLFWCursorPosCallback() {

            public void invoke(long window, double xpos, double ypos) {
                mouseX = (float) xpos / width;
                mouseY = (float) ypos / height;
            }
        });
        glfwSetMouseButtonCallback(window, mbCallback = new GLFWMouseButtonCallback() {

            public void invoke(long window, int button, int action, int mods) {
                if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
                    clickSelected(true);
                else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
                    clickSelected(false);
            }
        });
        if (windowed) {
            glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
        }
        IntBuffer framebufferSize = BufferUtils.createIntBuffer(2);
        nglfwGetFramebufferSize(window, memAddress(framebufferSize), memAddress(framebufferSize) + 4);
        width = framebufferSize.get(0);
        height = framebufferSize.get(1);
        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
        glfwMakeContextCurrent(window);
        glfwSwapInterval(0);
        glfwShowWindow(window);
    }

    static void renderCube(int x, int y, int z, boolean selected, boolean ghost) {
        glBegin(GL_QUADS);
        glColor4f(selected ? 1.0f : 0.0f, 0.0f, 0.2f, ghost ? GHOST_CUBE_ALPHA : 1.0f);
        glVertex3f(0.49f + x, -0.49f + y, -0.49f + z);
        glVertex3f(-0.49f + x, -0.49f + y, -0.49f + z);
        glVertex3f(-0.49f + x, 0.49f + y, -0.49f + z);
        glVertex3f(0.49f + x, 0.49f + y, -0.49f + z);
        glColor4f(selected ? 1.0f : 0.0f, 0.0f, 1.0f, ghost ? GHOST_CUBE_ALPHA : 1.0f);
        glVertex3f(0.49f + x, -0.49f + y, 0.49f + z);
        glVertex3f(0.49f + x, 0.49f + y, 0.49f + z);
        glVertex3f(-0.49f + x, 0.49f + y, 0.49f + z);
        glVertex3f(-0.49f + x, -0.49f + y, 0.49f + z);
        glColor4f(1.0f, 0.0f, 0.0f, ghost ? 0.2f : 1.0f);
        glVertex3f(0.49f + x, -0.49f + y, -0.49f + z);
        glVertex3f(0.49f + x, 0.49f + y, -0.49f + z);
        glVertex3f(0.49f + x, 0.49f + y, 0.49f + z);
        glVertex3f(0.49f + x, -0.49f + y, 0.49f + z);
        glColor4f(selected ? 1.0f : 0.0f, 0.0f, 0.0f, ghost ? GHOST_CUBE_ALPHA : 1.0f);
        glVertex3f(-0.49f + x, -0.49f + y, 0.49f + z);
        glVertex3f(-0.49f + x, 0.49f + y, 0.49f + z);
        glVertex3f(-0.49f + x, 0.49f + y, -0.49f + z);
        glVertex3f(-0.49f + x, -0.49f + y, -0.49f + z);
        glColor4f(selected ? 1.0f : 0.0f, 1.0f, 0.0f, ghost ? GHOST_CUBE_ALPHA : 1.0f);
        glVertex3f(0.49f + x, 0.49f + y, 0.49f + z);
        glVertex3f(0.49f + x, 0.49f + y, -0.49f + z);
        glVertex3f(-0.49f + x, 0.49f + y, -0.49f + z);
        glVertex3f(-0.49f + x, 0.49f + y, 0.49f + z);
        glColor4f(selected ? 1.0f : 0.0f, 0.2f, 0.0f, ghost ? GHOST_CUBE_ALPHA : 1.0f);
        glVertex3f(0.49f + x, -0.49f + y, -0.49f + z);
        glVertex3f(0.49f + x, -0.49f + y, 0.49f + z);
        glVertex3f(-0.49f + x, -0.49f + y, 0.49f + z);
        glVertex3f(-0.49f + x, -0.49f + y, -0.49f + z);
        glEnd();
    }

    void computeBoxUnderCenter() {
        float closestDistance = Float.POSITIVE_INFINITY;
        selectedCube = -1;
        Vector3f dir = viewMatrix.positiveZ(tmp).negate();
        Vector2f nearFar = new Vector2f();
        for (int y = 0; y < LEVEL_HEIGHT; y++) {
            for (int z = 0; z < LEVEL_LENGTH; z++) {
                for (int x = 0; x < LEVEL_LENGTH; x++) {
                    int idx = y * LEVEL_LENGTH * LEVEL_LENGTH + z * LEVEL_LENGTH + x;
                    if (boxes[idx]) {
                        int px = (x - LEVEL_LENGTH / 2);
                        int py = y;
                        int pz = (z - LEVEL_LENGTH / 2);
                        if (Intersectionf.intersectRayAab(pos.x, pos.y, pos.z, dir.x, dir.y, dir.z, px - 0.5f, py - 0.5f, pz - 0.5f, px + 0.5f, py + 0.5f, pz + 0.5f, nearFar)) {
                            if (nearFar.x < closestDistance) {
                                closestDistance = nearFar.x;
                                selectedCube = idx;
                                selectedPos.set(dir).mul(closestDistance).add(pos);
                            }
                        }
                    }
                }
            }
        }
    }

    void compileDisplayList() {
        if (!displayListNeedsRecompile)
            return;
        if (displayList != -1) {
            glDeleteLists(displayList, 1);
        }
        displayList = glGenLists(1);
        glNewList(displayList, GL_COMPILE);
        for (int y = 0; y < LEVEL_HEIGHT; y++) {
            for (int z = 0; z < LEVEL_LENGTH; z++) {
                for (int x = 0; x < LEVEL_LENGTH; x++) {
                    if (boxes[y * LEVEL_LENGTH * LEVEL_LENGTH + z * LEVEL_LENGTH + x]) {
                        int px = (x - LEVEL_LENGTH / 2);
                        int py = y;
                        int pz = (z - LEVEL_LENGTH / 2);
                        renderCube(px, py, pz, false, false);
                    }
                }
            }
        }
        glEndList();
        displayListNeedsRecompile = false;
    }

    void renderSelectedCube() {
        glPushMatrix();
        int idx = selectedCube;
        int x = idx % LEVEL_LENGTH;
        idx /= LEVEL_LENGTH;
        int z = idx % LEVEL_LENGTH;
        idx /= LEVEL_LENGTH;
        int y = idx;
        renderCube(x - LEVEL_LENGTH / 2, y, z - LEVEL_LENGTH / 2, true, false);
        glPopMatrix();
    }

    boolean inRange(int x, int y, int z) {
        return x >= 0 && x < LEVEL_LENGTH && y >= 0 && y < LEVEL_HEIGHT && z >= 0 && z < LEVEL_LENGTH;
    }

    void renderGhostCube() {
        if (ghostCube == -1)
            return;
        glEnable(GL_BLEND);
        glPushMatrix();
        int idx = ghostCube;
        int x = idx % LEVEL_LENGTH;
        idx /= LEVEL_LENGTH;
        int z = idx % LEVEL_LENGTH;
        idx /= LEVEL_LENGTH;
        int y = idx;
        renderCube(x - LEVEL_LENGTH / 2, y, z - LEVEL_LENGTH / 2, true, true);
        glPopMatrix();
        glDisable(GL_BLEND);
    }

    void clickSelected(boolean add) {
        if (add && ghostCube != -1) {
            boxes[ghostCube] = true;
            displayListNeedsRecompile = true;
        } else if (selectedCube != -1) {
            boxes[selectedCube] = false;
            displayListNeedsRecompile = true;
        }
    }

    void computeGhostCube() {
        if (selectedCube == -1)
            return;
        int idx = selectedCube;
        int x = idx % LEVEL_LENGTH;
        idx /= LEVEL_LENGTH;
        int z = idx % LEVEL_LENGTH;
        idx /= LEVEL_LENGTH;
        int y = idx;
        float px = x - LEVEL_LENGTH / 2;
        float py = y;
        float pz = z - LEVEL_LENGTH / 2;
        Vector3f d = tmp.set(selectedPos).sub(px, py, pz);
        int maxComponent = d.maxComponent();
        int nx, ny, nz;
        int signX = d.x > 0.0f ? 1 : -1;
        int signY = d.y > 0.0f ? 1 : -1;
        int signZ = d.z > 0.0f ? 1 : -1;
        if (maxComponent == 0) {
            nx = x + signX;
            ny = y;
            nz = z;
        } else if (maxComponent == 1) {
            nx = x;
            ny = y + signY;
            nz = z;
        } else {
            nx = x;
            ny = y;
            nz = z + signZ;
        }
        if (inRange(nx, ny, nz)) {
            ghostCube = ny * LEVEL_LENGTH * LEVEL_LENGTH + nz * LEVEL_LENGTH + nx;
        }
    }

    void drawCrosshair() {
        glEnable(GL_BLEND);
        glDisable(GL_DEPTH_TEST);
        glPushMatrix();
        glLoadIdenreplacedy();
        glBegin(GL_LINES);
        glColor4f(0.2f, 0.2f, 0.2f, 0.6f);
        glVertex3f(-0.01f, 0.0f, -1.0f);
        glVertex3f(+0.01f, 0.0f, -1.0f);
        glVertex3f(0.0f, -0.01f, -1.0f);
        glVertex3f(0.0f, +0.01f, -1.0f);
        glEnd();
        glPopMatrix();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_BLEND);
    }

    void loop() {
        GL.createCapabilities();
        glClearColor(0.97f, 0.97f, 0.97f, 1.0f);
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        glDepthFunc(GL_LEQUAL);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        long lastTime = System.nanoTime();
        Vector3f dir = new Vector3f();
        Vector3f right = new Vector3f();
        Vector3f up = new Vector3f();
        Matrix4f mat = new Matrix4f();
        FloatBuffer fb = BufferUtils.createFloatBuffer(16);
        float rotX = 0.0f;
        float rotY = 0.0f;
        while (!glfwWindowShouldClose(window)) {
            long thisTime = System.nanoTime();
            float diff = (float) ((thisTime - lastTime) / 1E9);
            lastTime = thisTime;
            float move = diff * movementSpeed;
            if (keyDown[GLFW_KEY_LEFT_SHIFT])
                move *= 2.0f;
            viewMatrix.positiveZ(dir).negate().mul(move);
            viewMatrix.positiveX(right).mul(move);
            viewMatrix.positiveY(up).mul(move);
            if (keyDown[GLFW_KEY_W])
                pos.add(dir);
            if (keyDown[GLFW_KEY_S])
                pos.sub(dir);
            if (keyDown[GLFW_KEY_A])
                pos.sub(right);
            if (keyDown[GLFW_KEY_D])
                pos.add(right);
            if (keyDown[GLFW_KEY_SPACE])
                pos.add(up);
            if (keyDown[GLFW_KEY_LEFT_CONTROL])
                pos.sub(up);
            rotX = mouseY;
            rotY = mouseX;
            glMatrixMode(GL_PROJECTION);
            glLoadMatrixf(mat.setPerspective((float) Math.toRadians(45), (float) width / height, 0.01f, 100.0f).get(fb));
            glMatrixMode(GL_MODELVIEW);
            glLoadMatrixf(viewMatrix.idenreplacedy().rotateX(rotX).rotateY(rotY).translate(-pos.x, -pos.y, -pos.z).get(fb));
            glViewport(0, 0, width, height);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            compileDisplayList();
            if (displayList != -1)
                glCallList(displayList);
            computeBoxUnderCenter();
            if (selectedCube != -1) {
                renderSelectedCube();
            }
            computeGhostCube();
            renderGhostCube();
            drawCrosshair();
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    }

    public static void main(String[] args) {
        new BoxPickingDemo().run();
    }
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXRotateXY() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().rotateY((float) Math.toRadians(90)).rotateX((float) Math.toRadians(45));
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 1, 1).normalize(), dir, 1E-7f);
}

19 View Complete Implementation : LerpCameraDemo.java
Copyright MIT License
Author : JOML-CI
public clreplaced LerpCameraDemo {

    GLFWErrorCallback errorCallback;

    GLFWKeyCallback keyCallback;

    GLFWFramebufferSizeCallback fbCallback;

    long window;

    int width = 200;

    int height = 200;

    // Declare matrices for two cameras
    Matrix4f[] projMatrix = { new Matrix4f(), new Matrix4f() };

    Matrix4f[] viewMatrix = { new Matrix4f(), new Matrix4f() };

    int active = 0;

    int inactive = 1;

    // And a model matrix for a rotating cube
    Matrix4f modelMatrix = new Matrix4f();

    // Temporary vector
    Vector3f tmp = new Vector3f();

    // Rotation of the inactive camera
    float rotate = 0.0f;

    float[] rotation = { 0.0f, 0.0f };

    void run() {
        try {
            init();
            loop();
            glfwDestroyWindow(window);
            keyCallback.free();
        } finally {
            glfwTerminate();
            errorCallback.free();
        }
    }

    void init() {
        glfwSetErrorCallback(errorCallback = GLFWErrorCallback.createPrint(System.err));
        if (!glfwInit())
            throw new IllegalStateException("Unable to initialize GLFW");
        // Configure our window
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
        window = glfwCreateWindow(width, height, "Hello interpolated Cameras!", NULL, NULL);
        if (window == NULL)
            throw new RuntimeException("Failed to create the GLFW window");
        System.out.println("Press 'C' to switch between the two cameras");
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {

            public void invoke(long window, int key, int scancode, int action, int mods) {
                if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE)
                    glfwSetWindowShouldClose(window, true);
                if (key == GLFW_KEY_C && action == GLFW_RELEASE)
                    switchCamera();
                if (key == GLFW_KEY_LEFT && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
                    rotate = 1.0f;
                } else if (key == GLFW_KEY_LEFT && (action == GLFW_RELEASE)) {
                    rotate = 0.0f;
                } else if (key == GLFW_KEY_RIGHT && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
                    rotate = -1.0f;
                } else if (key == GLFW_KEY_RIGHT && (action == GLFW_RELEASE)) {
                    rotate = 0.0f;
                }
            }
        });
        glfwSetFramebufferSizeCallback(window, fbCallback = new GLFWFramebufferSizeCallback() {

            public void invoke(long window, int w, int h) {
                if (w > 0 && h > 0) {
                    width = w;
                    height = h;
                }
            }
        });
        GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        glfwSetWindowPos(window, (vidmode.width() - width) / 2, (vidmode.height() - height) / 2);
        glfwMakeContextCurrent(window);
        glfwSwapInterval(0);
        glfwShowWindow(window);
        IntBuffer framebufferSize = BufferUtils.createIntBuffer(2);
        nglfwGetFramebufferSize(window, memAddress(framebufferSize), memAddress(framebufferSize) + 4);
        width = framebufferSize.get(0);
        height = framebufferSize.get(1);
    }

    void renderCube() {
        glBegin(GL_QUADS);
        glColor3f(0.0f, 0.0f, 0.2f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glColor3f(0.0f, 0.0f, 1.0f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glColor3f(1.0f, 0.0f, 0.0f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glColor3f(0.2f, 0.0f, 0.0f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glColor3f(0.0f, 1.0f, 0.0f);
        glVertex3f(0.5f, 0.5f, 0.5f);
        glVertex3f(0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, -0.5f);
        glVertex3f(-0.5f, 0.5f, 0.5f);
        glColor3f(0.0f, 0.2f, 0.0f);
        glVertex3f(0.5f, -0.5f, -0.5f);
        glVertex3f(0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, 0.5f);
        glVertex3f(-0.5f, -0.5f, -0.5f);
        glEnd();
    }

    void renderGrid() {
        glBegin(GL_LINES);
        glColor3f(0.2f, 0.2f, 0.2f);
        for (int i = -20; i <= 20; i++) {
            glVertex3f(-20.0f, 0.0f, i);
            glVertex3f(20.0f, 0.0f, i);
            glVertex3f(i, 0.0f, -20.0f);
            glVertex3f(i, 0.0f, 20.0f);
        }
        glEnd();
    }

    void renderFrustum(Matrix4f m) {
        Vector3f v = tmp;
        // Near plane
        glBegin(GL_LINE_STRIP);
        glColor3f(0.8f, 0.2f, 0.2f);
        for (int i = 0; i < 4 + 1; i++) {
            m.frustumCorner(i & 3, v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
        // Edges
        glBegin(GL_LINES);
        for (int i = 0; i < 4; i++) {
            m.frustumCorner(3 - i, v);
            glVertex3f(v.x, v.y, v.z);
            m.frustumCorner(4 + ((i + 2) & 3), v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
        // Far plane
        glBegin(GL_LINE_STRIP);
        for (int i = 0; i < 4 + 1; i++) {
            m.frustumCorner(4 + (i & 3), v);
            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
    }

    void switchCamera() {
        active = 1 - active;
        inactive = 1 - inactive;
    }

    void loop() {
        GL.createCapabilities();
        // Set the clear color
        glClearColor(0.6f, 0.7f, 0.8f, 1.0f);
        // Enable depth testing
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        // Remember the current time.
        long firstTime = System.nanoTime();
        long lastTime = firstTime;
        // FloatBuffer for transferring matrices to OpenGL
        FloatBuffer fb = BufferUtils.createFloatBuffer(16);
        // Matrix to build combined model-view
        Matrix4f modelView = new Matrix4f();
        // Matrix to build combined view-projection
        Matrix4f viewProj = new Matrix4f();
        // Ortho matrix
        Matrix4f ortho = new Matrix4f();
        while (!glfwWindowShouldClose(window)) {
            long thisTime = System.nanoTime();
            float diff = (thisTime - firstTime) / 1E9f;
            float angle = diff;
            float delta = (thisTime - lastTime) / 1E9f;
            lastTime = thisTime;
            // Process rotation
            rotation[inactive] += rotate * delta;
            // Setup both camera's projection matrices
            float ar = (float) width / height;
            projMatrix[0].setPerspective((float) Math.toRadians(40), ar, 1.0f, 20.0f);
            // The second matrix is an interpolation of a perspective and an orthographic projection:
            projMatrix[1].setPerspective((float) Math.toRadians(30), ar, 2.0f, 5.0f).lerp(ortho.setOrtho(-ar, ar, -1, 1, 2, 5), (float) Math.sin(diff * 0.5f) * (float) Math.sin(diff * 0.5f));
            // Load the active camera's projection
            glMatrixMode(GL_PROJECTION);
            glLoadMatrixf(projMatrix[active].get(fb));
            // Setup both camera's view matrices
            viewMatrix[0].setLookAt(0, 2, 10, 0, 0, 0, 0, 1, 0).rotateY(rotation[0]);
            viewMatrix[1].setLookAt(3, 1, 1, 0, 0, 0, 0, 1, 0).rotateY(rotation[1]);
            // Apply model transformation to active camera's view
            modelMatrix.rotationY(angle * (float) Math.toRadians(10));
            viewMatrix[active].mul(modelMatrix, modelView);
            // And load it
            glMatrixMode(GL_MODELVIEW);
            glLoadMatrixf(modelView.get(fb));
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glViewport(0, 0, width, height);
            // Render a cube
            renderCube();
            // Load the active camera's view again to render the inactive camera's frustum
            glLoadMatrixf(viewMatrix[active].get(fb));
            // Compute and render the inactive camera's frustum
            viewProj.set(projMatrix[inactive]).mul(viewMatrix[inactive]);
            renderFrustum(viewProj);
            glfwSwapBuffers(window);
            glfwPollEvents();
        }
    }

    public static void main(String[] args) {
        new LerpCameraDemo().run();
    }
}

19 View Complete Implementation : LinAlgNamespace.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@OpMethod(op = net.imagej.ops.linalg.rotate.Rotate3f.clreplaced)
public Vector3f rotate(final Vector3f out, final Vector3f v, final Quaternionfc q) {
    return (Vector3f) ops().run(Rotate3f.clreplaced, out, v, q);
}

19 View Complete Implementation : BlockOutlineShader.java
Copyright GNU General Public License v3.0
Author : Lux-Vacuos
public void loadColor(Vector3f color) {
    this.color.loadVec3(color);
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testRotateTowardsXY() {
    Vector3f v = new Vector3f(1, 1, 0).normalize();
    Matrix4f m1 = new Matrix4f().rotateZ(v.angle(new Vector3f(1, 0, 0)), new Matrix4f());
    Matrix4f m2 = new Matrix4f().rotateTowardsXY(v.x, v.y, new Matrix4f());
    TestUtil.replacedertMatrix4fEquals(m1, m2, 0);
    Vector3f t = m1.transformDirection(new Vector3f(0, 1, 0));
    TestUtil.replacedertVector3fEquals(new Vector3f(-1, 1, 0).normalize(), t, 1E-6f);
}

19 View Complete Implementation : Camera.java
Copyright Apache License 2.0
Author : lwjglgamedev
public clreplaced Camera {

    private final Vector3f position;

    private final Vector3f rotation;

    public Camera() {
        position = new Vector3f();
        rotation = new Vector3f();
    }

    public Camera(Vector3f position, Vector3f rotation) {
        this.position = position;
        this.rotation = rotation;
    }

    public Vector3f getPosition() {
        return position;
    }

    public void setPosition(float x, float y, float z) {
        position.x = x;
        position.y = y;
        position.z = z;
    }

    public void movePosition(float offsetX, float offsetY, float offsetZ) {
        if (offsetZ != 0) {
            position.x += (float) Math.sin(Math.toRadians(rotation.y)) * -1.0f * offsetZ;
            position.z += (float) Math.cos(Math.toRadians(rotation.y)) * offsetZ;
        }
        if (offsetX != 0) {
            position.x += (float) Math.sin(Math.toRadians(rotation.y - 90)) * -1.0f * offsetX;
            position.z += (float) Math.cos(Math.toRadians(rotation.y - 90)) * offsetX;
        }
        position.y += offsetY;
    }

    public Vector3f getRotation() {
        return rotation;
    }

    public void setRotation(float x, float y, float z) {
        rotation.x = x;
        rotation.y = y;
        rotation.z = z;
    }

    public void moveRotation(float offsetX, float offsetY, float offsetZ) {
        rotation.x += offsetX;
        rotation.y += offsetY;
        rotation.z += offsetZ;
    }
}

19 View Complete Implementation : WorldWithUBO.java
Copyright MIT License
Author : integeruser
/**
 * Visit https://github.com/integeruser/jgltut for info and updates.
 * Original: https://bitbucket.org/alfonse/gltut/src/default/Tut%2007%20World%20in%20Motion/World%20With%20UBO.cpp
 * <p>
 * Part II. Positioning
 * Chapter 7. World in Motion
 * <p>
 * Function                                     Increase/Left   Decrease/Right
 * Move camera target up/down                          E               Q
 * Move camera target horizontally                     A               D
 * Move camera target vertically                       W               S
 * Rotate camera horizontally around target            L               J
 * Rotate camera vertically around target              I               K
 * Move camera towards/away from target                U               O
 * In addition, if you hold down the SHIFT key while pressing any of the last six keys, then the affected control will
 * be much slower.
 * <p>
 * SPACE    - toggle the appearance of an object indicating the position of the camera point.
 */
public clreplaced WorldWithUBO extends Tutorial {

    public static void main(String[] args) {
        Framework.CURRENT_TUTORIAL_DATAPATH = "/integeruser/jgltut/tut07/data/";
        new WorldWithUBO().start(700, 700);
    }

    @Override
    protected void init() {
        initializeProgram();
        coneMesh = new Mesh("UnitConeTint.xml");
        cylinderMesh = new Mesh("UnitCylinderTint.xml");
        cubeTintMesh = new Mesh("UnitCubeTint.xml");
        cubeColorMesh = new Mesh("UnitCubeColor.xml");
        planeMesh = new Mesh("UnitPlane.xml");
        glEnable(GL_CULL_FACE);
        glCullFace(GL_BACK);
        glFrontFace(GL_CW);
        glEnable(GL_DEPTH_TEST);
        glDepthMask(true);
        glDepthFunc(GL_LEQUAL);
        glDepthRange(0.0f, 1.0f);
        glEnable(GL_DEPTH_CLAMP);
        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if (action == GLFW_PRESS) {
                switch(key) {
                    case GLFW_KEY_SPACE:
                        drawLookatPoint = !drawLookatPoint;
                        System.out.printf("Target: %f, %f, %f\n", camTarget.x, camTarget.y, camTarget.z);
                        System.out.printf("Position: %f, %f, %f\n", sphereCamRelPos.x, sphereCamRelPos.y, sphereCamRelPos.z);
                        break;
                    case GLFW_KEY_ESCAPE:
                        glfwSetWindowShouldClose(window, true);
                        break;
                }
            }
        });
    }

    @Override
    protected void display() {
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClearDepth(1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        final Vector3f camPos = resolveCamPosition();
        MatrixStackf camMatrix = new MatrixStackf();
        camMatrix.mul(calcLookAtMatrix(camPos, camTarget, new Vector3f(0.0f, 1.0f, 0.0f)));
        glBindBuffer(GL_UNIFORM_BUFFER, globalMatricesUBO);
        glBufferSubData(GL_UNIFORM_BUFFER, 16 * 4, camMatrix.get(mat4Buffer));
        glBindBuffer(GL_UNIFORM_BUFFER, 0);
        MatrixStackf modelMatrix = new MatrixStackf(4);
        // Render the ground plane.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(100.0f, 1.0f, 100.0f);
            glUseProgram(uniformColor.theProgram);
            glUniformMatrix4fv(uniformColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColor.baseColorUnif, 0.302f, 0.416f, 0.0589f, 1.0f);
            planeMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the trees.
        drawForest(modelMatrix);
        // Draw the building.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(20.0f, 0.0f, -10.0f);
            drawParthenon(modelMatrix);
            modelMatrix.popMatrix();
        }
        if (drawLookatPoint) {
            glDisable(GL_DEPTH_TEST);
            modelMatrix.pushMatrix();
            modelMatrix.translate(camTarget);
            modelMatrix.scale(1.0f, 1.0f, 1.0f);
            glUseProgram(objectColor.theProgram);
            glUniformMatrix4fv(objectColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            cubeColorMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
            glEnable(GL_DEPTH_TEST);
        }
    }

    @Override
    protected void reshape(int w, int h) {
        float zNear = 1.0f;
        float zFar = 1000.0f;
        Matrix4f persMatrix = new Matrix4f();
        persMatrix.perspective((float) Math.toRadians(45.0f), (w / (float) h), zNear, zFar);
        glBindBuffer(GL_UNIFORM_BUFFER, globalMatricesUBO);
        glBufferSubData(GL_UNIFORM_BUFFER, 0, persMatrix.get(mat4Buffer));
        glBindBuffer(GL_UNIFORM_BUFFER, 0);
        glViewport(0, 0, w, h);
    }

    @Override
    protected void update() {
        final float scale = 5;
        if (isKeyPressed(GLFW_KEY_W)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.z = camTarget.z - 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.z = camTarget.z - 4.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_S)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.z = camTarget.z + 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.z = camTarget.z + 4.0f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_D)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.x = camTarget.x + 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.x = camTarget.x + 4.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_A)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.x = camTarget.x - 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.x = camTarget.x - 4.0f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_E)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.y = camTarget.y - 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.y = camTarget.y - 4.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_Q)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                camTarget.y = camTarget.y + 0.4f * lastFrameDuration * scale;
            } else {
                camTarget.y = camTarget.y + 4.0f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_I)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.y = sphereCamRelPos.y - 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.y = sphereCamRelPos.y - 11.25f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_K)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.y = sphereCamRelPos.y + 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.y = sphereCamRelPos.y + 11.25f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_J)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.x = sphereCamRelPos.x - 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.x = sphereCamRelPos.x - 11.25f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_L)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.x = sphereCamRelPos.x + 1.125f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.x = sphereCamRelPos.x + 11.25f * lastFrameDuration * scale;
            }
        }
        if (isKeyPressed(GLFW_KEY_O)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.z = sphereCamRelPos.z - 0.5f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.z = sphereCamRelPos.z - 5.0f * lastFrameDuration * scale;
            }
        } else if (isKeyPressed(GLFW_KEY_U)) {
            if (isKeyPressed(GLFW_KEY_LEFT_SHIFT) || isKeyPressed(GLFW_KEY_RIGHT_SHIFT)) {
                sphereCamRelPos.z = sphereCamRelPos.z + 0.5f * lastFrameDuration * scale;
            } else {
                sphereCamRelPos.z = sphereCamRelPos.z + 5.0f * lastFrameDuration * scale;
            }
        }
        sphereCamRelPos.y = Math.min(Math.max(sphereCamRelPos.y, -78.75f), -1.0f);
        camTarget.y = camTarget.y > 0.0f ? camTarget.y : 0.0f;
        sphereCamRelPos.z = sphereCamRelPos.z > 5.0f ? sphereCamRelPos.z : 5.0f;
    }

    // //////////////////////////////
    private ProgramData uniformColor;

    private ProgramData objectColor;

    private ProgramData uniformColorTint;

    private clreplaced ProgramData {

        int theProgram;

        int globalUniformBlockIndex;

        int modelToWorldMatrixUnif;

        int baseColorUnif;
    }

    private int globalMatricesUBO;

    private final int globalMatricesBindingIndex = 0;

    private void initializeProgram() {
        uniformColor = loadProgram("PosOnlyWorldTransformUBO.vert", "ColorUniform.frag");
        objectColor = loadProgram("PosColorWorldTransformUBO.vert", "ColorPreplacedthrough.frag");
        uniformColorTint = loadProgram("PosColorWorldTransformUBO.vert", "ColorMultUniform.frag");
        globalMatricesUBO = glGenBuffers();
        glBindBuffer(GL_UNIFORM_BUFFER, globalMatricesUBO);
        glBufferData(GL_UNIFORM_BUFFER, 16 * 4 * 2, GL_STREAM_DRAW);
        glBindBuffer(GL_UNIFORM_BUFFER, 0);
        glBindBufferRange(GL_UNIFORM_BUFFER, globalMatricesBindingIndex, globalMatricesUBO, 0, 16 * 4 * 2);
    }

    private ProgramData loadProgram(String vertexShaderFileName, String fragmentShaderFileName) {
        ArrayList<Integer> shaderList = new ArrayList<>();
        shaderList.add(Framework.loadShader(GL_VERTEX_SHADER, vertexShaderFileName));
        shaderList.add(Framework.loadShader(GL_FRAGMENT_SHADER, fragmentShaderFileName));
        ProgramData data = new ProgramData();
        data.theProgram = Framework.createProgram(shaderList);
        data.modelToWorldMatrixUnif = glGetUniformLocation(data.theProgram, "modelToWorldMatrix");
        data.globalUniformBlockIndex = glGetUniformBlockIndex(data.theProgram, "GlobalMatrices");
        data.baseColorUnif = glGetUniformLocation(data.theProgram, "baseColor");
        glUniformBlockBinding(data.theProgram, data.globalUniformBlockIndex, globalMatricesBindingIndex);
        return data;
    }

    // //////////////////////////////
    private Mesh coneMesh;

    private Mesh cylinderMesh;

    private Mesh cubeTintMesh;

    private Mesh cubeColorMesh;

    private Mesh planeMesh;

    private boolean drawLookatPoint = false;

    private Vector3f camTarget = new Vector3f(0.0f, 0.4f, 0.0f);

    // In spherical coordinates.
    private Vector3f sphereCamRelPos = new Vector3f(67.5f, -46.0f, 150.0f);

    private Vector3f resolveCamPosition() {
        float phi = (float) Math.toRadians(sphereCamRelPos.x);
        float theta = (float) Math.toRadians(sphereCamRelPos.y + 90.0f);
        float sinTheta = (float) Math.sin(theta);
        float cosTheta = (float) Math.cos(theta);
        float cosPhi = (float) Math.cos(phi);
        float sinPhi = (float) Math.sin(phi);
        Vector3f dirToCamera = new Vector3f(sinTheta * cosPhi, cosTheta, sinTheta * sinPhi);
        return (dirToCamera.mul(sphereCamRelPos.z)).add(camTarget);
    }

    private Matrix4f calcLookAtMatrix(Vector3f cameraPt, Vector3f lookPt, Vector3f upPt) {
        Vector3f lookDir = new Vector3f(lookPt).sub(cameraPt).normalize();
        Vector3f upDir = new Vector3f(upPt).normalize();
        Vector3f rightDir = new Vector3f(lookDir).cross(upDir).normalize();
        Vector3f perpUpDir = new Vector3f(rightDir).cross(lookDir);
        Matrix4f rotMat = new Matrix4f();
        rotMat.m00(rightDir.x);
        rotMat.m01(rightDir.y);
        rotMat.m02(rightDir.z);
        rotMat.m10(perpUpDir.x);
        rotMat.m11(perpUpDir.y);
        rotMat.m12(perpUpDir.z);
        rotMat.m20(-lookDir.x);
        rotMat.m21(-lookDir.y);
        rotMat.m22(-lookDir.z);
        rotMat.transpose();
        Matrix4f transMat = new Matrix4f().setTranslation(-cameraPt.x, -cameraPt.y, -cameraPt.z);
        return rotMat.mul(transMat);
    }

    // //////////////////////////////
    private final TreeData[] forest = { new TreeData(-45.0f, -40.0f, 2.0f, 3.0f), new TreeData(-42.0f, -35.0f, 2.0f, 3.0f), new TreeData(-39.0f, -29.0f, 2.0f, 4.0f), new TreeData(-44.0f, -26.0f, 3.0f, 3.0f), new TreeData(-40.0f, -22.0f, 2.0f, 4.0f), new TreeData(-36.0f, -15.0f, 3.0f, 3.0f), new TreeData(-41.0f, -11.0f, 2.0f, 3.0f), new TreeData(-37.0f, -6.0f, 3.0f, 3.0f), new TreeData(-45.0f, 0.0f, 2.0f, 3.0f), new TreeData(-39.0f, 4.0f, 3.0f, 4.0f), new TreeData(-36.0f, 8.0f, 2.0f, 3.0f), new TreeData(-44.0f, 13.0f, 3.0f, 3.0f), new TreeData(-42.0f, 17.0f, 2.0f, 3.0f), new TreeData(-38.0f, 23.0f, 3.0f, 4.0f), new TreeData(-41.0f, 27.0f, 2.0f, 3.0f), new TreeData(-39.0f, 32.0f, 3.0f, 3.0f), new TreeData(-44.0f, 37.0f, 3.0f, 4.0f), new TreeData(-36.0f, 42.0f, 2.0f, 3.0f), new TreeData(-32.0f, -45.0f, 2.0f, 3.0f), new TreeData(-30.0f, -42.0f, 2.0f, 4.0f), new TreeData(-34.0f, -38.0f, 3.0f, 5.0f), new TreeData(-33.0f, -35.0f, 3.0f, 4.0f), new TreeData(-29.0f, -28.0f, 2.0f, 3.0f), new TreeData(-26.0f, -25.0f, 3.0f, 5.0f), new TreeData(-35.0f, -21.0f, 3.0f, 4.0f), new TreeData(-31.0f, -17.0f, 3.0f, 3.0f), new TreeData(-28.0f, -12.0f, 2.0f, 4.0f), new TreeData(-29.0f, -7.0f, 3.0f, 3.0f), new TreeData(-26.0f, -1.0f, 2.0f, 4.0f), new TreeData(-32.0f, 6.0f, 2.0f, 3.0f), new TreeData(-30.0f, 10.0f, 3.0f, 5.0f), new TreeData(-33.0f, 14.0f, 2.0f, 4.0f), new TreeData(-35.0f, 19.0f, 3.0f, 4.0f), new TreeData(-28.0f, 22.0f, 2.0f, 3.0f), new TreeData(-33.0f, 26.0f, 3.0f, 3.0f), new TreeData(-29.0f, 31.0f, 3.0f, 4.0f), new TreeData(-32.0f, 38.0f, 2.0f, 3.0f), new TreeData(-27.0f, 41.0f, 3.0f, 4.0f), new TreeData(-31.0f, 45.0f, 2.0f, 4.0f), new TreeData(-28.0f, 48.0f, 3.0f, 5.0f), new TreeData(-25.0f, -48.0f, 2.0f, 3.0f), new TreeData(-20.0f, -42.0f, 3.0f, 4.0f), new TreeData(-22.0f, -39.0f, 2.0f, 3.0f), new TreeData(-19.0f, -34.0f, 2.0f, 3.0f), new TreeData(-23.0f, -30.0f, 3.0f, 4.0f), new TreeData(-24.0f, -24.0f, 2.0f, 3.0f), new TreeData(-16.0f, -21.0f, 2.0f, 3.0f), new TreeData(-17.0f, -17.0f, 3.0f, 3.0f), new TreeData(-25.0f, -13.0f, 2.0f, 4.0f), new TreeData(-23.0f, -8.0f, 2.0f, 3.0f), new TreeData(-17.0f, -2.0f, 3.0f, 3.0f), new TreeData(-16.0f, 1.0f, 2.0f, 3.0f), new TreeData(-19.0f, 4.0f, 3.0f, 3.0f), new TreeData(-22.0f, 8.0f, 2.0f, 4.0f), new TreeData(-21.0f, 14.0f, 2.0f, 3.0f), new TreeData(-16.0f, 19.0f, 2.0f, 3.0f), new TreeData(-23.0f, 24.0f, 3.0f, 3.0f), new TreeData(-18.0f, 28.0f, 2.0f, 4.0f), new TreeData(-24.0f, 31.0f, 2.0f, 3.0f), new TreeData(-20.0f, 36.0f, 2.0f, 3.0f), new TreeData(-22.0f, 41.0f, 3.0f, 3.0f), new TreeData(-21.0f, 45.0f, 2.0f, 3.0f), new TreeData(-12.0f, -40.0f, 2.0f, 4.0f), new TreeData(-11.0f, -35.0f, 3.0f, 3.0f), new TreeData(-10.0f, -29.0f, 1.0f, 3.0f), new TreeData(-9.0f, -26.0f, 2.0f, 2.0f), new TreeData(-6.0f, -22.0f, 2.0f, 3.0f), new TreeData(-15.0f, -15.0f, 1.0f, 3.0f), new TreeData(-8.0f, -11.0f, 2.0f, 3.0f), new TreeData(-14.0f, -6.0f, 2.0f, 4.0f), new TreeData(-12.0f, 0.0f, 2.0f, 3.0f), new TreeData(-7.0f, 4.0f, 2.0f, 2.0f), new TreeData(-13.0f, 8.0f, 2.0f, 2.0f), new TreeData(-9.0f, 13.0f, 1.0f, 3.0f), new TreeData(-13.0f, 17.0f, 3.0f, 4.0f), new TreeData(-6.0f, 23.0f, 2.0f, 3.0f), new TreeData(-12.0f, 27.0f, 1.0f, 2.0f), new TreeData(-8.0f, 32.0f, 2.0f, 3.0f), new TreeData(-10.0f, 37.0f, 3.0f, 3.0f), new TreeData(-11.0f, 42.0f, 2.0f, 2.0f), new TreeData(15.0f, 5.0f, 2.0f, 3.0f), new TreeData(15.0f, 10.0f, 2.0f, 3.0f), new TreeData(15.0f, 15.0f, 2.0f, 3.0f), new TreeData(15.0f, 20.0f, 2.0f, 3.0f), new TreeData(15.0f, 25.0f, 2.0f, 3.0f), new TreeData(15.0f, 30.0f, 2.0f, 3.0f), new TreeData(15.0f, 35.0f, 2.0f, 3.0f), new TreeData(15.0f, 40.0f, 2.0f, 3.0f), new TreeData(15.0f, 45.0f, 2.0f, 3.0f), new TreeData(25.0f, 5.0f, 2.0f, 3.0f), new TreeData(25.0f, 10.0f, 2.0f, 3.0f), new TreeData(25.0f, 15.0f, 2.0f, 3.0f), new TreeData(25.0f, 20.0f, 2.0f, 3.0f), new TreeData(25.0f, 25.0f, 2.0f, 3.0f), new TreeData(25.0f, 30.0f, 2.0f, 3.0f), new TreeData(25.0f, 35.0f, 2.0f, 3.0f), new TreeData(25.0f, 40.0f, 2.0f, 3.0f), new TreeData(25.0f, 45.0f, 2.0f, 3.0f) };

    private clreplaced TreeData {

        float xPos;

        float zPos;

        float trunkHeight;

        float coneHeight;

        TreeData(float xPos, float zPos, float trunkHeight, float coneHeight) {
            this.xPos = xPos;
            this.zPos = zPos;
            this.trunkHeight = trunkHeight;
            this.coneHeight = coneHeight;
        }
    }

    private void drawForest(MatrixStackf modelMatrix) {
        for (TreeData currTree : forest) {
            modelMatrix.pushMatrix();
            modelMatrix.translate(currTree.xPos, 0.0f, currTree.zPos);
            drawTree(modelMatrix, currTree.trunkHeight, currTree.coneHeight);
            modelMatrix.popMatrix();
        }
    }

    // Trees are 3x3 in X/Z, and trunkHeight + coneHeight in the Y.
    private void drawTree(MatrixStackf modelMatrix, float trunkHeight, float coneHeight) {
        // Draw trunk.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(1.0f, trunkHeight, 1.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.694f, 0.4f, 0.106f, 1.0f);
            cylinderMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the treetop.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, trunkHeight, 0.0f);
            modelMatrix.scale(3.0f, coneHeight, 3.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.0f, 1.0f, 0.0f, 1.0f);
            coneMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
    }

    // //////////////////////////////
    // Columns are 1x1 in the X/Z, and height units in the Y.
    private void drawColumn(MatrixStackf modelMatrix, float height) {
        final float columnBaseHeight = 0.25f;
        // Draw the bottom of the column.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(1.0f, columnBaseHeight, 1.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 1.0f, 1.0f, 1.0f, 1.0f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the top of the column.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, height - columnBaseHeight, 0.0f);
            modelMatrix.scale(1.0f, columnBaseHeight, 1.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw the main column.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, columnBaseHeight, 0.0f);
            modelMatrix.scale(0.8f, height - (columnBaseHeight * 2.0f), 0.8f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cylinderMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
    }

    // //////////////////////////////
    private void drawParthenon(MatrixStackf modelMatrix) {
        final float parthenonWidth = 14.0f;
        final float parthenonLength = 20.0f;
        final float parthenonColumnHeight = 5.0f;
        final float parthenonBaseHeight = 1.0f;
        final float parthenonTopHeight = 2.0f;
        // Draw base.
        {
            modelMatrix.pushMatrix();
            modelMatrix.scale(parthenonWidth, parthenonBaseHeight, parthenonLength);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw top.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, parthenonColumnHeight + parthenonBaseHeight, 0.0f);
            modelMatrix.scale(parthenonWidth, parthenonTopHeight, parthenonLength);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(uniformColorTint.theProgram);
            glUniformMatrix4fv(uniformColorTint.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            glUniform4f(uniformColorTint.baseColorUnif, 0.9f, 0.9f, 0.9f, 0.9f);
            cubeTintMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw columns.
        final float frontZVal = (parthenonLength / 2.0f) - 1.0f;
        final float rightXVal = (parthenonWidth / 2.0f) - 1.0f;
        for (int columnNum = 0; columnNum < (int) (parthenonWidth / 2.0f); columnNum++) {
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate((2.0f * columnNum) - (parthenonWidth / 2.0f) + 1.0f, parthenonBaseHeight, frontZVal);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate((2.0f * columnNum) - (parthenonWidth / 2.0f) + 1.0f, parthenonBaseHeight, -frontZVal);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
        }
        // Don't draw the first or last columns, since they've been drawn already.
        for (int columnNum = 1; columnNum < (int) ((parthenonLength - 2.0f) / 2.0f); columnNum++) {
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate(rightXVal, parthenonBaseHeight, (2.0f * columnNum) - (parthenonLength / 2.0f) + 1.0f);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
            {
                modelMatrix.pushMatrix();
                modelMatrix.translate(-rightXVal, parthenonBaseHeight, (2.0f * columnNum) - (parthenonLength / 2.0f) + 1.0f);
                drawColumn(modelMatrix, parthenonColumnHeight);
                modelMatrix.popMatrix();
            }
        }
        // Draw interior.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, 1.0f, 0.0f);
            modelMatrix.scale(parthenonWidth - 6.0f, parthenonColumnHeight, parthenonLength - 6.0f);
            modelMatrix.translate(0.0f, 0.5f, 0.0f);
            glUseProgram(objectColor.theProgram);
            glUniformMatrix4fv(objectColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            cubeColorMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
        // Draw headpiece.
        {
            modelMatrix.pushMatrix();
            modelMatrix.translate(0.0f, parthenonColumnHeight + parthenonBaseHeight + (parthenonTopHeight / 2.0f), parthenonLength / 2.0f);
            modelMatrix.rotateX(-135.0f);
            modelMatrix.rotateY(45.0f);
            glUseProgram(objectColor.theProgram);
            glUniformMatrix4fv(objectColor.modelToWorldMatrixUnif, false, modelMatrix.get(mat4Buffer));
            cubeColorMesh.render();
            glUseProgram(0);
            modelMatrix.popMatrix();
        }
    }
}

19 View Complete Implementation : PointLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public void setPosition(Vector3f position) {
    this.position = position;
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testPositiveXYZLookAt() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().lookAt(0, 0, 0, -1, 0, 0, 0, 1, 0);
    m.positiveX(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 0, -1).normalize(), dir, 1E-7f);
    m.positiveY(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(0, 1, 0).normalize(), dir, 1E-7f);
    m.positiveZ(dir);
    TestUtil.replacedertVector3fEquals(new Vector3f(1, 0, 0).normalize(), dir, 1E-7f);
}

19 View Complete Implementation : PointLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public clreplaced PointLight {

    private Vector3f color;

    private Vector3f position;

    protected float intensity;

    private Attenuation attenuation;

    public PointLight(Vector3f color, Vector3f position, float intensity) {
        attenuation = new Attenuation(1, 0, 0);
        this.color = color;
        this.position = position;
        this.intensity = intensity;
    }

    public PointLight(Vector3f color, Vector3f position, float intensity, Attenuation attenuation) {
        this(color, position, intensity);
        this.attenuation = attenuation;
    }

    public PointLight(PointLight pointLight) {
        this(new Vector3f(pointLight.getColor()), new Vector3f(pointLight.getPosition()), pointLight.getIntensity(), pointLight.getAttenuation());
    }

    public Vector3f getColor() {
        return color;
    }

    public void setColor(Vector3f color) {
        this.color = color;
    }

    public Vector3f getPosition() {
        return position;
    }

    public void setPosition(Vector3f position) {
        this.position = position;
    }

    public float getIntensity() {
        return intensity;
    }

    public void setIntensity(float intensity) {
        this.intensity = intensity;
    }

    public Attenuation getAttenuation() {
        return attenuation;
    }

    public void setAttenuation(Attenuation attenuation) {
        this.attenuation = attenuation;
    }

    public static clreplaced Attenuation {

        private float constant;

        private float linear;

        private float exponent;

        public Attenuation(float constant, float linear, float exponent) {
            this.constant = constant;
            this.linear = linear;
            this.exponent = exponent;
        }

        public float getConstant() {
            return constant;
        }

        public void setConstant(float constant) {
            this.constant = constant;
        }

        public float getLinear() {
            return linear;
        }

        public void setLinear(float linear) {
            this.linear = linear;
        }

        public float getExponent() {
            return exponent;
        }

        public void setExponent(float exponent) {
            this.exponent = exponent;
        }
    }
}

19 View Complete Implementation : LinAlgNamespace.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@OpMethod(op = net.imagej.ops.linalg.rotate.Rotate3f.clreplaced)
public Vector3f rotate(final Vector3f out, final Vector3f v, final AxisAngle4f axisAngle) {
    final Quaternionfc q = new Quaternionf(axisAngle);
    return (Vector3f) ops().run(Rotate3f.clreplaced, out, v, q);
}

19 View Complete Implementation : DirectionalLight.java
Copyright Apache License 2.0
Author : lwjglgamedev
public clreplaced DirectionalLight {

    private Vector3f color;

    private Vector3f direction;

    private float intensity;

    public DirectionalLight(Vector3f color, Vector3f direction, float intensity) {
        this.color = color;
        this.direction = direction;
        this.intensity = intensity;
    }

    public DirectionalLight(DirectionalLight light) {
        this(new Vector3f(light.getColor()), new Vector3f(light.getDirection()), light.getIntensity());
    }

    public Vector3f getColor() {
        return color;
    }

    public void setColor(Vector3f color) {
        this.color = color;
    }

    public Vector3f getDirection() {
        return direction;
    }

    public void setDirection(Vector3f direction) {
        this.direction = direction;
    }

    public float getIntensity() {
        return intensity;
    }

    public void setIntensity(float intensity) {
        this.intensity = intensity;
    }
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testFrustumRay() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().perspective((float) Math.toRadians(90), 1.0f, 0.1f, 100.0f).rotateY((float) Math.toRadians(90));
    Vector3f expectedDir;
    m.frustumRayDir(0, 0, dir);
    expectedDir = new Vector3f(1, -1, -1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
    m.frustumRayDir(1, 0, dir);
    expectedDir = new Vector3f(1, -1, 1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
    m.frustumRayDir(0, 1, dir);
    expectedDir = new Vector3f(1, 1, -1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
    m.frustumRayDir(1, 1, dir);
    expectedDir = new Vector3f(1, 1, 1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
}

19 View Complete Implementation : IntersectionfTest.java
Copyright MIT License
Author : JOML-CI
public static void testIntersectRayPlane() {
    Vector3f origin = new Vector3f();
    Vector3f dir = new Vector3f(1, 1, 1);
    Vector3f point = new Vector3f(2, 2, 2);
    Vector3f normal = new Vector3f(-1, -1, -1);
    float t = Intersectionf.intersectRayPlane(origin, dir, point, normal, 0.0f);
    replacedertTrue(t >= 0.0f);
    Vector3f intersection = new Vector3f(dir).mul(t).add(origin);
    TestUtil.replacedertVector3fEquals(new Vector3f(2, 2, 2), intersection, 1E-6f);
    normal = new Vector3f(1, 1, 1);
    t = Intersectionf.intersectRayPlane(origin, dir, point, normal, 0.0f);
    replacedertEquals(-1.0f, t, 1E-6f);
}

19 View Complete Implementation : LinAlgNamespace.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@OpMethod(op = net.imagej.ops.linalg.rotate.Rotate3f.clreplaced)
public Vector3f rotate(final Vector3f v, final Quaternionfc q) {
    return (Vector3f) ops().run(Rotate3f.clreplaced, v, q);
}

19 View Complete Implementation : LinAlgNamespace.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@OpMethod(op = net.imagej.ops.linalg.rotate.Rotate3f.clreplaced)
public Vector3f rotate1(final Vector3f v, final AxisAngle4f axisAngle) {
    final Quaternionfc q = new Quaternionf(axisAngle);
    return (Vector3f) ops().run(Rotate3f.clreplaced, v, v, q);
}

19 View Complete Implementation : Rotate3f.java
Copyright BSD 2-Clause "Simplified" License
Author : imagej
@Override
public Vector3f createOutput(final Vector3f v, final Quaternionfc q) {
    return new Vector3f();
}

19 View Complete Implementation : Matrix4fTest.java
Copyright MIT License
Author : JOML-CI
public static void testFrustumRay2() {
    Vector3f dir = new Vector3f();
    Matrix4f m = new Matrix4f().perspective((float) Math.toRadians(90), 1.0f, 0.1f, 100.0f).rotateZ((float) Math.toRadians(45));
    Vector3f expectedDir;
    m.frustumRayDir(0, 0, dir);
    expectedDir = new Vector3f(-(float) Math.sqrt(2), 0, -1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
    m.frustumRayDir(1, 0, dir);
    expectedDir = new Vector3f(0, -(float) Math.sqrt(2), -1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
    m.frustumRayDir(0, 1, dir);
    expectedDir = new Vector3f(0, (float) Math.sqrt(2), -1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
    m.frustumRayDir(1, 1, dir);
    expectedDir = new Vector3f((float) Math.sqrt(2), 0, -1).normalize();
    TestUtil.replacedertVector3fEquals(expectedDir, dir, 1E-5f);
}

19 View Complete Implementation : FreeCamera.java
Copyright MIT License
Author : JOML-CI
/**
 * Compute the world-space 'right' vector and store it into <code>dest</code>.
 *
 * @param dest
 *          will hold the result
 * @return dest
 */
public Vector3f right(Vector3f dest) {
    return rotation.positiveX(dest);
}