/*
* Copyright (c) 2006 Erik Tollerud (erik.tollerud@gmail.com) All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* The names of Erik Tollerud, Sun Microsystems, Inc. or the names of
* contributors may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. ERIK TOLLERUD,
* SUN MICROSYSTEMS, INC. ("SUN"), AND SUN'S LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL ERIK
* TOLLERUD, SUN, OR SUN'S LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
* OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF ERIK
* TOLLERUD OR SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
*/
package net.java.joglutils.lighting;
import javax.media.opengl.*;
import java.awt.Color;
import java.nio.*;
/**
* This class encapsulates OpenGL material settings in an object-oriented interface.
* The class operates in two modes:
*
1. If a {@link GL} Context is attached, setter methods apply the settings to the
* OpenGL state as well as the object. the apply() and retrieve() method can be
* used for all of the settings
*
2. If no {@link GL} Context is attached, apply(GL) and retrieve(GL) set / get
* the OpenGL state from this object.
*
Note: GL_LIGHTING must be enabled in the OpenGL context by the user - this object will not do so.
* @author Erik J. Tollerud
*/
public class Material {
GL attachedGL;
private int face;
private float[] ambient;
private float[] diffuse;
private float[] specular;
private float shininess;
private float[] emissive;
/** Creates a new instance of Material from the OpenGL default material settings */
public Material() {
attachedGL = null;
face = GL.GL_FRONT_AND_BACK;
float[] localAmb = {0.2f,0.2f,0.2f,1.0f};
ambient = localAmb;
float[] localDiff = {0.8f,0.8f,0.8f,1.0f};
diffuse = localDiff;
float[] localSpec = {0.0f,0.0f,0.0f,1.0f};
specular = localSpec;
float[] localEm = {0.0f,0.0f,0.0f,1.0f};
emissive = localEm;
shininess = 0;
}
/**
* Creates a new instance of material, with the specified GL context attached.
* @param gl the OpenGL context to attach
* @param face the face to use for configuring the material
*/
public Material(GL gl, int face) {
this.attachedGL = gl;
this.face = face;
this.retrieve();
}
/**
* Creates a new instance of material, with the specified GL context attached. Settings are applied to front and back.
* @param gl the OpenGL context to attach
*/
public Material(GL gl) {
this(gl,GL.GL_FRONT_AND_BACK);
}
/**
* Attached the specified OpenGL context to this object
* @param gl the OpenGL context to attach this to
*/
public void setAttachedGL(GL gl) {
this.attachedGL = gl;
}
/**
* Returns the OpenGL context attached to this Lighting object
* @return the attached OpenGL context, or null if there is no attached context
*/
public GL getAttachedGL() {
return this.attachedGL;
}
/**
* Detaches the currently attached OpenGL context from this object
*/
public void detachGL() {
this.attachedGL = null;
}
/**
* Determines if an OpenGL context is attached.
* @return true if an OpenGL context is attached to this object.
*/
public boolean isAttached() {
if (this.attachedGL == null)
return false;
return true;
}
/**
* Sets the OpenGL State in the supplied context based on the settings in this Material.
* @param gl the OpenGL Context upon which to apply the settings from this Material.
*/
public void apply(GL gl) {
gl.glMaterialfv(face,GL.GL_SPECULAR,specular,0);
gl.glMaterialfv(face,GL.GL_EMISSION,emissive,0);
gl.glMaterialfv(face,GL.GL_AMBIENT,ambient,0);
gl.glMaterialfv(face,GL.GL_DIFFUSE,diffuse,0);
gl.glMaterialf(face,GL.GL_SHININESS,shininess);
}
/**
* Sets the settings in this Material from the specified OpenGL context's state.
* @param gl the OpenGL Context to use in setting this Material's settings.
*/
public void retrieve(GL gl) {
int retrievalFace = face;
if (face == GL.GL_FRONT_AND_BACK)
retrievalFace = GL.GL_FRONT;
FloatBuffer buff = FloatBuffer.allocate(17);
gl.glGetMaterialfv(retrievalFace,gl.GL_SPECULAR,buff);
gl.glGetMaterialfv(retrievalFace,gl.GL_EMISSION,buff);
gl.glGetMaterialfv(retrievalFace,gl.GL_AMBIENT,buff);
gl.glGetMaterialfv(retrievalFace,gl.GL_DIFFUSE,buff);
gl.glGetMaterialfv(retrievalFace,gl.GL_SHININESS,buff);
buff.get(this.specular);
buff.get(this.emissive);
buff.get(this.ambient);
buff.get(this.diffuse);
this.shininess = buff.get();
}
/**
* Sets the state on the attached OpenGL Context to match this Material.
* @throws sddm.lighting.LightingException if no OpenGL Context is attached.
*/
public void apply() throws LightingException {
if (attachedGL == null)
throw new LightingException("Tried to apply material settings with no attached GL Context");
this.apply(this.attachedGL);
}
/**
* Sets this Material object from the attached OpenGL state.
* @throws sddm.lighting.LightingException if no OpenGL Context is attached.
*/
public void retrieve() throws LightingException {
if (attachedGL == null)
throw new LightingException("Tried to retrieve material settings with no attached GL Context");
this.retrieve(attachedGL);
}
/**
* Specifies the face for subsequent apply method calls to apply and retrieve the material settings. If
* GL_FRONT_AND_BACK, will retrieve from GL_FRONT.
* @param face the face to apply material settings upon. Must be GL.GL_FRONT_AND_BACK, GL.GL_FRONT, or GL.GL_BACK
* @throws sddm.lighting.LightingException if an invalid input is provided
*/
public void setFace(int face) throws LightingException {
if(face==GL.GL_FRONT_AND_BACK)
this.face = GL.GL_FRONT_AND_BACK;
else if(face == GL.GL_FRONT)
this.face = GL.GL_FRONT;
else if(face == GL.GL_BACK)
this.face = GL.GL_BACK;
else
throw new LightingException("Attempted to set face to an invalid value");
}
/**
* Determines what face the material settings are applied to or retrieved from.
* @return the face used - can be GL.GL_FRONT_AND_BACK, GL.GL_FRONT, or GL.GL_BACK
*/
public int getFace() {
return face;
}
/**
* Sets this object's specular color from an input Color. Default is {0,0,0,1}.
* @param specular the color that the specular color is copied from - later changes to the Color object will not be reflected in this Material.
*/
public void setSpecular(Color specular) {
if (this.attachedGL != null)
attachedGL.glMaterialfv(face,GL.GL_SPECULAR,specular.getRGBComponents(null),0);
this.specular = specular.getRGBComponents(null);
}
/**
* Retrieves the specular color from this Material.
* @return a new Color with components copied from this Material.
*/
public Color getSpecular() {
return new Color(specular[0],specular[1],specular[2],specular[3]);
}
/**
* Sets the shininess for this Material. Defaults to 0.
* @param shininess the value to use for shininess
*/
public void setShininess(float shininess) {
if (this.attachedGL != null)
attachedGL.glMaterialf(face,GL.GL_SHININESS,shininess);
this.shininess = shininess;
}
/**
* Retrieves the shininess from this Material.
* @return the shininess value
*/
public float getShininess() {
return shininess;
}
/**
* Sets this object's emissive color from an input Color. Default is {0,0,0,1}.
* @param emissive the color that the specular color is copied from - later changes to the Color object will not be reflected in this Material.
*/
public void setEmissive(Color emissive) {
if (this.attachedGL != null)
attachedGL.glMaterialfv(face,GL.GL_EMISSION,emissive.getRGBComponents(null),0);
this.emissive = emissive.getRGBComponents(null);
}
/**
* This retrieves the emissive color from this Material.
* @return a new Color with components copied from this Material.
*/
public Color getEmissive() {
return new Color(emissive[0],emissive[1],emissive[2],emissive[3]);
}
/**
* Sets this object's ambient color from an input Color. Defaults to {0.2,0.2,0.2,1.0}.
* @param ambient the color that the specular color is copied from - later changes to the Color object will not be reflected in this Material.
*/
public void setAmbient(Color ambient) {
if (this.attachedGL != null)
attachedGL.glMaterialfv(face,GL.GL_AMBIENT,ambient.getRGBComponents(null),0);
this.ambient = ambient.getRGBComponents(null);
}
/**
* This retrieves the ambient color from this Material.
* @return a new Color with components copied from this Material.
*/
public Color getAmbient() {
return new Color(ambient[0],ambient[1],ambient[2],ambient[3]);
}
/**
* Sets this object's diffuse color from an input Color. Defaults to {0.8,0.8,0.8,1.0}.
* @param diffuse the color that the specular color is copied from - later changes to the Color object will not be reflected in this Material.
*/
public void setDiffuse(Color diffuse) {
if (this.attachedGL != null)
attachedGL.glMaterialfv(face,GL.GL_DIFFUSE,diffuse.getRGBComponents(null),0);
this.diffuse = diffuse.getRGBComponents(null);
}
/**
* This retrieves the diffuse color from this Material.
* @return a new Color with components copied from this Material.
*/
public Color getDiffuse() {
return new Color(diffuse[0],diffuse[1],diffuse[2],diffuse[3]);
}
/**
* Sets the light model parameter GL_LIGHT_MODEL_AMBIENT for the attached GL context. This applies for all lighted fragments on this GL context.
* @param ambient the ambient color to be applied.
* @throws sddm.lighting.LightingException if no OpenGL Context is attached.
*/
public void applyGlobalAmbient(Color ambient) throws LightingException {
if (this.attachedGL == null)
throw new LightingException("tried to set global ambient color on object with no attached GL Context");
this.applyGlobalAmbient(this.attachedGL,ambient);
}
/**
* Retrieves the GL_LIGHT_MODEL_AMBIENT color from the attached OpenGL context.
* @throws sddm.lighting.LightingException if no OpenGL Context is attached.
* @return the ambient color in the specified OpenGL Context.
*/
public Color getGlobalAmbient() throws LightingException {
if (this.attachedGL == null)
throw new LightingException("tried to get global ambient color on object with with no attached GL Context");
return this.getGlobalAmbient(this.attachedGL);
}
/**
* Sets the light model parameter GL_LIGHT_MODEL_AMBIENT for the specified GL context. This applies for all lighted fragments on this GL context.
* @param gl the OpenGL context to apply this color to.
* @param ambient the ambient color to be applied.
*/
public static void applyGlobalAmbient(GL gl, Color ambient) {
gl.glLightModelfv(gl.GL_LIGHT_MODEL_AMBIENT,ambient.getRGBComponents(null),0);
}
/**
* Retrieves the GL_LIGHT_MODEL_AMBIENT color from a specified OpenGL context.
* @param gl the OpenGL Context from which to get the color.
* @return the ambient color in the specified OpenGL Context.
*/
public static Color getGlobalAmbient(GL gl) {
FloatBuffer buff = FloatBuffer.allocate(4);
gl.glGetFloatv(gl.GL_LIGHT_MODEL_AMBIENT, buff);
return new Color(buff.get(),buff.get(),buff.get(),buff.get());
}
}