@Override
  public void init(GLAutoDrawable drawable) {
    drawable.setGL(new DebugGL2(drawable.getGL().getGL2()));
    GL2 gl = drawable.getGL().getGL2();

    gl.glClearColor(0, 0, 0, 1); // Black Background
    gl.glClearDepth(1); // Depth Buffer Setup
    gl.glEnable(GL.GL_DEPTH_TEST); // Enables Depth Testing
    gl.glDepthFunc(GL.GL_LEQUAL); // The Type Of Depth Testing To Do

    gl.glEnable(GL2.GL_LIGHTING);
    gl.glEnable(GL2.GL_LIGHT0);
    gl.glEnable(GL2.GL_NORMALIZE); // normalize normals before lighting

    // Setup perFragmentLighting shader
    String shaderNamePerFragment = "perFragmentLighting";
    ShaderCode vsCodePerFragment =
        ShaderCode.create(
            gl,
            GL2.GL_VERTEX_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNamePerFragment,
            false);
    ShaderCode fsCodePerFragment =
        ShaderCode.create(
            gl,
            GL2.GL_FRAGMENT_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNamePerFragment,
            false);
    ShaderProgram programPerFragment = new ShaderProgram();
    programPerFragment.add(vsCodePerFragment);
    programPerFragment.add(fsCodePerFragment);
    if (!programPerFragment.link(gl, System.err)) {
      throw new GLException("Couldn't link program: " + programPerFragment);
    }
    statePerFragment.attachShaderProgram(gl, programPerFragment, false);

    // Setup perVertexLighting shader
    String shaderNameCheckerboard = "checkerboard";
    ShaderCode vsCodeCheckerboard =
        ShaderCode.create(
            gl,
            GL2.GL_VERTEX_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNameCheckerboard,
            false);
    ShaderCode fsCodeCheckerboard =
        ShaderCode.create(
            gl,
            GL2.GL_FRAGMENT_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNameCheckerboard,
            false);
    ShaderProgram programCheckerboard = new ShaderProgram();
    programCheckerboard.add(vsCodeCheckerboard);
    programCheckerboard.add(fsCodeCheckerboard);
    if (!programCheckerboard.link(gl, System.err)) {
      throw new GLException("Couldn't link program: " + programCheckerboard);
    }
    stateCheckerboard.attachShaderProgram(gl, programCheckerboard, false);

    // Setup woodcut shader
    String shaderNameWoodcut = "woodcut";
    ShaderCode vsCodeWoodcut =
        ShaderCode.create(
            gl,
            GL2.GL_VERTEX_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNameWoodcut,
            false);
    ShaderCode fsCodeWoodcut =
        ShaderCode.create(
            gl,
            GL2.GL_FRAGMENT_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNameWoodcut,
            false);
    ShaderProgram programWoodcut = new ShaderProgram();
    programWoodcut.add(vsCodeWoodcut);
    programWoodcut.add(fsCodeWoodcut);
    if (!programWoodcut.link(gl, System.err)) {
      throw new GLException("Couldn't link program: " + programWoodcut);
    }
    stateWoodcut.attachShaderProgram(gl, programWoodcut, false);

    // Setup toon shader
    String shaderNameToon = "toon";
    ShaderCode vsCodeToon =
        ShaderCode.create(
            gl,
            GL2.GL_VERTEX_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNameToon,
            false);
    ShaderCode fsCodeToon =
        ShaderCode.create(
            gl,
            GL2.GL_FRAGMENT_SHADER,
            this.getClass(),
            "shaders",
            "shader/bin",
            shaderNameToon,
            false);
    ShaderProgram programToon = new ShaderProgram();
    programToon.add(vsCodeToon);
    programToon.add(fsCodeToon);
    if (!programToon.link(gl, System.err)) {
      throw new GLException("Couldn't link program: " + programToon);
    }
    stateToon.attachShaderProgram(gl, programToon, false);
  }