/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.util.opengl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.media.opengl.GL;
/**
* Abstracts usage of OpenGL materials.
*
* Usage:
* instantiate a new material,
* set the material properties (setDiffuse(), setAmbient(), setSpecular(), setShininess()),
* call material.apply() in your render function to set the OpenGL current material properties.
*/
public class GLMaterial {
// A sampling of color and shininess values
/** The Constant colorNone. */
public static final float colorNone[] = { 0f, 0f, 0f, 1f}; // no color = black
/** The Constant colorYellow. */
public static final float colorYellow[] = { 1f, 1f, 0f, 1f};
/** The Constant colorRed. */
public static final float colorRed[] = { .4f, 0f, 0f, 1f};
/** The Constant colorGreen. */
public static final float colorGreen[] = { .1f, .8f, .2f, 1f};
/** The Constant colorBlue. */
public static final float colorBlue[] = { 0f, 0f, 1f, 1f};
/** The Constant colorGray. */
public static final float colorGray[] = { .5f, .5f, .5f, 1f};
/** The Constant colorWhite. */
public static final float colorWhite[] = { 1f, 1f, 1f, 1f};
/** The Constant colorBlack. */
public static final float colorBlack[] = { 0f, 0f, 0f, 1f};
/** The Constant colorBeige. */
public static final float colorBeige[] = { .7f, .7f, .4f, 1f};
/** The Constant colorCyan. */
public static final float colorCyan[] = { .1f, .1f, .9f, 1f};
/** The Constant colorDefaultDiffuse. */
public static final float colorDefaultDiffuse[] = { .8f, .8f, .8f, 1f}; // OpenGL default diffuse color
/** The Constant colorDefaultAmbient. */
public static final float colorDefaultAmbient[] = { .2f, .2f, .2f, 1f}; // OpenGL default ambient color
/** The Constant colorDefaultSpecular. */
public static final float colorDefaultSpecular[] = { 1.0f, 1.0f, 1.0f, 1f};
/** The Constant minShine. */
public static final float minShine = 0.0f;
/** The Constant maxShine. */
public static final float maxShine = 127.0f;
//
/** The default diffuse. */
private static FloatBuffer defaultDiffuse;
/** The default ambient. */
private static FloatBuffer defaultAmbient;
/** The default specular. */
private static FloatBuffer defaultSpecular;
/** The default emission. */
private static FloatBuffer defaultEmission;
/** The default shine. */
private static FloatBuffer defaultShine;
// The color values for this material
/** The diffuse. */
private FloatBuffer diffuse; // color of the lit surface
/** The ambient. */
private FloatBuffer ambient; // color of the shadowed surface
/** The specular. */
private FloatBuffer specular; // reflection color (typically this is a shade of gray)
/** The emission. */
private FloatBuffer emission; // glow color
/** The shininess. */
private FloatBuffer shininess; // size of the reflection highlight
/** The gl. */
private GL gl;
/**
* set up some default material color values
* this code is run only once, when the class is first used
*/
static {
defaultAmbient = allocFloats(colorDefaultAmbient);
defaultDiffuse = allocFloats(colorDefaultDiffuse);
defaultSpecular = allocFloats(colorDefaultSpecular);
float[] shine = {50, 0, 0, 0}; // LWJGL requires four values, so include three extra zeroes
defaultShine = allocFloats(shine);
defaultEmission = allocFloats(colorNone);
}
/**
* Instantiates a new gL material.
*
* @param gl the gl
*/
public GLMaterial(GL gl) {
this.gl = gl;
this.setDefaults();
}
/**
* Instantiates a new gL material.
*
* @param gl the gl
* @param color the color
*/
public GLMaterial(GL gl, float[] color) {
this.gl = gl;
this.setDefaults();
this.setDiffuseAndAmbientColor(color);
}
/**
* Set the material to OpenGL's default values (gray, with no reflection and no glow).
*/
public void setDefaults() {
this.setDiffuse(colorDefaultDiffuse);
this.setAmbient(colorDefaultAmbient);
this.setSpecular(colorNone);
this.setEmission(colorNone);
this.setShininess(minShine);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Functions to set the material properties
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Set the diffuse material color. ([R][G][B][A]) This is the color of the material
* where it is directly lit.
*
* @param color the color
*/
public void setDiffuse(float[] color) {
this.diffuse = allocFloats(color);
}
/**
* Set the ambient material color. ([R][G][B][A]) This is the color of the material
* where it is lit by indirect light (light scattered off the environment).
* Ie. the shadowed side of an object.
*
* @param color the color
*/
public void setAmbient(float[] color) {
this.ambient = allocFloats(color);
}
/**
* Set the specular material color. ([R][G][B][A]) This controls how much light
* is reflected off a glossy surface. This color value describes
* the brightness of the reflection and is typically a shade of gray.
* Pure black means that no light is reflected (ie. a very rough matte
* surface). Pure white means that the surface is highly reflective,
*
* see also: setShininess()
*
* @param color the color
*/
public void setSpecular(float[] color) {
this.specular = allocFloats(color);
}
/**
* Set the emission material color. ([R][G][B][A]) This controls the "glow" of the material,
* and can be used to make a material that seems to be lit from inside.
*
* @param color the color
*/
public void setEmission(float[] color) {
this.emission = allocFloats(color);
}
/**
* Set size of the reflection highlight. Must also set the specular color for
* shininess to have any effect:
* setSpecular(GLMaterial.colorWhite);
*
* @param howShiny How sharp reflection is: 0 - 127 (127=very sharp pinpoint)
*/
public void setShininess(float howShiny) {
if (howShiny >= minShine && howShiny <= maxShine) {
float[] tmp = {howShiny,0,0,0};
this.shininess = allocFloats(tmp);
}
}
/**
* Call glMaterial() to activate these material properties in the OpenGL environment.
* These properties will stay in effect until you change them or disable lighting.
*/
public void apply() {
/*
// GL_FRONT: affect only front facing triangles
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, this.ambient);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, this.diffuse);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, this.specular);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, this.emission);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, this.shininess);
*/
// /*
//FIXME welche einstellung nehmen?
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, this.ambient);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, this.diffuse);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, this.specular);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, this.emission);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, this.shininess);
// */
}
/**
* Reset all material settings to the default values.
*
* @param gl the gl
*/
public static void clear(GL gl) {
gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, defaultDiffuse);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, defaultAmbient);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, defaultSpecular);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_EMISSION, defaultEmission);
gl.glMaterialfv(GL.GL_FRONT, GL.GL_SHININESS, defaultShine);
/*
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, defaultDiffuse);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, defaultAmbient);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, defaultSpecular);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, defaultEmission);
gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, defaultShine);
*/
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* The following functions provide a simpler way to use materials
* that hides some of the complexity of the OpenGL functions.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Sets the material color to approximate a "real" surface color.
*
* Use the same color for diffuse and ambient. To create a
* shadowed effect you should lower the ambient value for the
* light sources and lower the overall ambient light.
*
* @param color the color
*/
public void setDiffuseAndAmbientColor(float[] color) {
this.setDiffuse(color); // surface directly lit
this.setAmbient(color); // surface in shadow
}
/**
* Set the reflection properties. Typically the reflection (specular color)
* describes the brightness of the reflection, and is a shade of gray.
* This function takes two params that describe the intensity
* of the reflection, and the size of the highlight.
*
* intensity - a float from 0-1 (0=no reflectivity, 1=maximum reflectivity)
* highlight - a float from 0-1 (0=soft highlight, 1=sharpest highlight)
*
* example: setReflection(1,1) creates a bright, sharp reflection
* setReflection(.5f,.5f) creates a softer, wider reflection
*
* @param intensity the intensity
* @param highlight the highlight
*/
public void setSpecular(float intensity, float highlight) {
float[] color = {intensity,intensity,intensity,1}; // create a shade of gray
this.setSpecular(color);
this.setShininess((int)(highlight*127f)); // convert 0-1 to 0-127
}
/**
* Make material appear to emit light.
*
* @param color the color
*/
public void setEmissionColor(float[] color) {
this.emission = allocFloats(color);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Native IO buffer functions
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** The Constant SIZE_FLOAT. */
public static final int SIZE_FLOAT = 4; // four bytes in a float
/**
* Alloc floats.
*
* @param howmany the howmany
*
* @return the float buffer
*/
public static FloatBuffer allocFloats(int howmany) {
return ByteBuffer.allocateDirect(howmany * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
}
/**
* Alloc floats.
*
* @param floatarray the floatarray
*
* @return the float buffer
*/
public static FloatBuffer allocFloats(float[] floatarray) {
FloatBuffer fb = ByteBuffer.allocateDirect(floatarray.length * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
fb.put(floatarray).flip();
return fb;
}
}