@Override
  public void update(float interval, MouseInput mouseInput) {
    // Update camera based on mouse
    if (mouseInput.isRightButtonPressed()) {
      Vector2f rotVec = mouseInput.getDisplVec();
      camera.moveRotation(rotVec.x * MOUSE_SENSITIVITY, rotVec.y * MOUSE_SENSITIVITY, 0);
    }

    // Update camera position
    Vector3f prevPos = new Vector3f(camera.getPosition());
    camera.movePosition(
        cameraInc.x * CAMERA_POS_STEP,
        cameraInc.y * CAMERA_POS_STEP,
        cameraInc.z * CAMERA_POS_STEP);
    // Check if there has been a collision. If true, set the y position to
    // the maximum height
    float height = terrain != null ? terrain.getHeight(camera.getPosition()) : -Float.MAX_VALUE;
    if (camera.getPosition().y <= height) {
      camera.setPosition(prevPos.x, prevPos.y, prevPos.z);
    }

    lightAngle += angleInc;
    if (lightAngle < 0) {
      lightAngle = 0;
    } else if (lightAngle > 180) {
      lightAngle = 180;
    }
    float zValue = (float) Math.cos(Math.toRadians(lightAngle));
    float yValue = (float) Math.sin(Math.toRadians(lightAngle));
    Vector3f lightDirection = this.scene.getSceneLight().getDirectionalLight().getDirection();
    lightDirection.x = 0;
    lightDirection.y = yValue;
    lightDirection.z = zValue;
    lightDirection.normalize();
  }
  @Override
  public void init(Window window) throws Exception {
    renderer.init(window);

    scene = new Scene();

    float reflectance = 1f;

    Mesh quadMesh = OBJLoader.loadMesh("/models/plane.obj");
    Material quadMaterial = new Material(new Vector3f(0.0f, 0.0f, 1.0f), reflectance);
    quadMesh.setMaterial(quadMaterial);
    GameItem quadGameItem = new GameItem(quadMesh);
    quadGameItem.setPosition(0, 0, 0);
    quadGameItem.setScale(2.5f);

    // Setup  GameItems
    MD5Model md5Meshodel = MD5Model.parse("/models/monster.md5mesh");
    MD5AnimModel md5AnimModel = MD5AnimModel.parse("/models/monster.md5anim");
    // MD5Model md5Meshodel = MD5Model.parse("/models/boblamp.md5mesh");
    // MD5AnimModel md5AnimModel = MD5AnimModel.parse("/models/boblamp.md5anim");

    monster = MD5Loader.process(md5Meshodel, md5AnimModel, new Vector3f(1, 1, 1));
    monster.setScale(0.05f);
    monster.setRotation(90, 0, 0);

    scene.setGameItems(new GameItem[] {quadGameItem, monster});

    // Setup Lights
    setupLights();

    camera.getPosition().x = 0.25f;
    camera.getPosition().y = 6.5f;
    camera.getPosition().z = 6.5f;
    camera.getRotation().x = 25;
    camera.getRotation().y = -1;
    hud = new Hud("");
  }
  @Override
  public void init(Window window) throws Exception {
    renderer.init(window);
    soundMgr.init();

    scene = new Scene();

    float reflectance = 1f;

    float blockScale = 0.5f;
    float skyBoxScale = 100.0f;
    float extension = 2.0f;

    float startx = extension * (-skyBoxScale + blockScale);
    float startz = extension * (skyBoxScale - blockScale);
    float starty = -1.0f;
    float inc = blockScale * 2;

    float posx = startx;
    float posz = startz;
    float incy = 0.0f;

    BufferedImage heightMapImage =
        ImageIO.read(getClass().getResourceAsStream("/textures/heightmap.png"));
    int height = heightMapImage.getHeight();
    int width = heightMapImage.getWidth();
    int instances = height * width;
    Mesh mesh = OBJLoader.loadMesh("/models/cube.obj", instances);
    Texture texture = new Texture("/textures/terrain_textures.png", 2, 1);
    Material material = new Material(texture, reflectance);
    mesh.setMaterial(material);
    GameItem[] gameItems = new GameItem[instances];
    for (int i = 0; i < height; i++) {
      for (int j = 0; j < width; j++) {
        GameItem gameItem = new GameItem(mesh);
        gameItem.setScale(blockScale);
        int rgb = heightMapImage.getRGB(j, i);
        incy = rgb / (10 * 255 * 255);
        gameItem.setPosition(posx, starty + incy, posz);
        int textPos = Math.random() > 0.5f ? 0 : 1;
        gameItem.setTextPos(textPos);
        gameItems[i * width + j] = gameItem;

        posx += inc;
      }
      posx = startx;
      posz -= inc;
    }
    scene.setGameItems(gameItems);

    // Particles
    int maxParticles = 200;
    Vector3f particleSpeed = new Vector3f(0, 1, 0);
    particleSpeed.mul(2.5f);
    long ttl = 4000;
    long creationPeriodMillis = 300;
    float range = 0.2f;
    float scale = 0.2f;
    Mesh partMesh = OBJLoader.loadMesh("/models/particle.obj", maxParticles);
    Texture particleTexture = new Texture("/textures/particle_anim.png", 4, 4);
    Material partMaterial = new Material(particleTexture, reflectance);
    partMesh.setMaterial(partMaterial);
    Particle particle = new Particle(partMesh, particleSpeed, ttl, 100);
    particle.setScale(scale);
    particleEmitter = new FlowParticleEmitter(particle, maxParticles, creationPeriodMillis);
    particleEmitter.setActive(true);
    particleEmitter.setPositionRndRange(range);
    particleEmitter.setSpeedRndRange(range);
    particleEmitter.setAnimRange(10);
    this.scene.setParticleEmitters(new FlowParticleEmitter[] {particleEmitter});

    // Shadows
    scene.setRenderShadows(false);

    // Fog
    Vector3f fogColour = new Vector3f(0.5f, 0.5f, 0.5f);
    scene.setFog(new Fog(true, fogColour, 0.02f));

    // Setup  SkyBox
    SkyBox skyBox = new SkyBox("/models/skybox.obj", new Vector3f(0.65f, 0.65f, 0.65f));
    skyBox.setScale(skyBoxScale);
    scene.setSkyBox(skyBox);

    // Setup Lights
    setupLights();

    camera.getPosition().x = 0.25f;
    camera.getPosition().y = 6.5f;
    camera.getPosition().z = 6.5f;
    camera.getRotation().x = 25;
    camera.getRotation().y = -1;

    hud = new Hud("DEMO");

    // Sounds
    this.soundMgr.init();
    this.soundMgr.setAttenuationModel(AL11.AL_EXPONENT_DISTANCE);
    setupSounds();
  }