/**
   * Set up a material for rendering. Activate its shader, and pass the material properties,
   * textures, and light sources to the shader.
   *
   * @param m the material to be set up for rendering
   */
  private void setMaterial(Material m) {

    // Set up the shader for the material, if it has one
    if (m != null && m.shader != null) {

      // Identifier for shader variables
      int id;

      // Activate the shader
      useShader(m.shader);

      // Activate the diffuse texture, if the material has one
      if (m.diffuseMap != null) {
        // OpenGL calls to activate the texture
        gl.glActiveTexture(GL3.GL_TEXTURE0); // Work with texture unit 0
        gl.glEnable(GL3.GL_TEXTURE_2D);
        gl.glBindTexture(GL3.GL_TEXTURE_2D, ((GLTexture) m.diffuseMap).getId());
        gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_LINEAR);
        gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_LINEAR);
        // We assume the texture in the shader is called "myTexture"
        id = gl.glGetUniformLocation(activeShaderID, "myTexture");
        gl.glUniform1i(
            id,
            0); // The variable in the shader needs to be set to the desired texture unit, i.e., 0
      }

      // Pass a default light source to shader
      String lightString = "lightDirection[" + 0 + "]";
      id = gl.glGetUniformLocation(activeShaderID, lightString);
      if (id != -1) gl.glUniform4f(id, 0, 0, 1, 0.f); // Set light direction
      else System.out.print("Could not get location of uniform variable " + lightString + "\n");
      int nLights = 1;

      // Iterate over all light sources in scene manager (overwriting the default light source)
      Iterator<Light> iter = sceneManager.lightIterator();

      Light l;
      if (iter != null) {
        nLights = 0;
        while (iter.hasNext() && nLights < 8) {
          l = iter.next();

          // Pass light direction to shader, we assume the shader stores it in an array
          // "lightDirection[]"
          lightString = "lightDirection[" + nLights + "]";
          id = gl.glGetUniformLocation(activeShaderID, lightString);
          if (id != -1)
            gl.glUniform4f(
                id, l.direction.x, l.direction.y, l.direction.z, 0.f); // Set light direction
          else System.out.print("Could not get location of uniform variable " + lightString + "\n");

          nLights++;
        }

        // Pass number of lights to shader, we assume this is in a variable "nLights" in the shader
        id = gl.glGetUniformLocation(activeShaderID, "nLights");
        if (id != -1) gl.glUniform1i(id, nLights); // Set number of lightrs
        // Only for debugging
        //				else
        //					System.out.print("Could not get location of uniform variable nLights\n");
      }
    }
  }
  /**
   * Binds the BufferedImage byte-stream into video memory. BufferedImage must be in 4BYTE_ABGR.
   * 4BYTE_ABGR removes endinese problems.
   */
  public Texture bind(final BufferedImage _image, final InternalFormat _format) {
    final GL3 gl = GLRenderer.getCanvas().getContext().getCurrentGL().getGL3();
    if (gl == null) {
      System.out.println("GL context doesn't exist");
      return null;
    }

    gl.glEnable(GL.GL_TEXTURE_2D);

    final int textureID = glGenTextures(gl);
    gl.glBindTexture(GL3.GL_TEXTURE_2D, textureID);

    gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_S, GL3.GL_REPEAT);
    gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_T, GL3.GL_REPEAT);
    gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_LINEAR);
    gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_LINEAR_MIPMAP_LINEAR);

    final int width = _image.getWidth();
    final int height = _image.getHeight();
    final int channels = _image.getSampleModel().getNumBands();
    int internalFormat = GL3.GL_RGB;

    if (gl.isExtensionAvailable("GL_EXT_abgr") == true) {
      switch (channels) {
        case 4:
          imageFormat = GL2.GL_ABGR_EXT;
          break;
        case 3:
          imageFormat = GL3.GL_BGR;
          break;
        case 1:
          imageFormat = GL3.GL_RED;
          break;
      }
    } else {
      switch (channels) {
        case 4:
          imageFormat = GL3.GL_RGBA;
          break;
        case 3:
          imageFormat = GL3.GL_RGB;
          break;
        case 1:
          imageFormat = GL3.GL_RED;
          break;
      }
    }

    gl.glPixelStorei(GL3.GL_UNPACK_ALIGNMENT, 1);
    gl.glTexImage2D(
        GL3.GL_TEXTURE_2D,
        0,
        getGLInternalFormat(channels, _format),
        width,
        height,
        0,
        imageFormat,
        GL3.GL_UNSIGNED_BYTE,
        getByteBuffer(_image));

    gl.glGenerateMipmap(GL3.GL_TEXTURE_2D);
    gl.glBindTexture(GL.GL_TEXTURE_2D, 0); // Reset to default texture

    return new Texture(new GLImage(textureID, width, height));
  }