import java.nio.*; import org.lwjgl.opengl.*; /** * Wraps properties for a material. * * To use: * create 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 public static final float colorNone[] = { 0f, 0f, 0f, 1f}; // no color = black public static final float colorYellow[] = { 1f, 1f, 0f, 1f}; public static final float colorRed[] = { .4f, 0f, 0f, 1f}; public static final float colorGreen[] = { .1f, .8f, .2f, 1f}; public static final float colorBlue[] = { 0f, 0f, 1f, 1f}; public static final float colorGray[] = { .5f, .5f, .5f, 1f}; public static final float colorWhite[] = { 1f, 1f, 1f, 1f}; public static final float colorBlack[] = { 0f, 0f, 0f, 1f}; public static final float colorBeige[] = { .7f, .7f, .4f, 1f}; public static final float colorCyan[] = { .1f, .1f, .9f, 1f}; public static final float colorDefaultDiffuse[] = { .8f, .8f, .8f, 1f}; // OpenGL default diffuse color public static final float colorDefaultAmbient[] = { .2f, .2f, .2f, 1f}; // OpenGL default ambient color public static final float minShine = 0.0f; public static final float maxShine = 127.0f; // private static FloatBuffer defaultDiffuse; private static FloatBuffer defaultAmbient; private static FloatBuffer defaultSpecular; private static FloatBuffer defaultEmission; private static FloatBuffer defaultShine; // The color values for this material private FloatBuffer diffuse; // color of the lit surface private FloatBuffer ambient; // color of the shadowed surface private FloatBuffer specular; // reflection color (typically this is a shade of gray) private FloatBuffer emission; // glow color private FloatBuffer shininess; // size of the reflection highlight /** * set up some default material color values * this code is run only once, when the class is first used */ static { float[] shine = {minShine,0,0,0}; // LWJGL requires four values, so include three extra zeroes defaultShine = allocFloats(shine); defaultDiffuse = allocFloats(colorDefaultDiffuse); defaultAmbient = allocFloats(colorDefaultAmbient); defaultSpecular = allocFloats(colorNone); defaultEmission = allocFloats(colorNone); } public GLMaterial() { setDefaults(); } public GLMaterial(float[] color) { setDefaults(); setColor(color); } /** * Set the material to OpenGL's default values (gray, with no reflection and no glow) */ public void setDefaults() { setDiffuse(colorDefaultDiffuse); setAmbient(colorDefaultAmbient); setSpecular(colorNone); setEmission(colorNone); setShininess(minShine); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Functions to set the material properties * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * Set the diffuse material color. This is the color of the material * where it is directly lit. */ public void setDiffuse(float[] color) { diffuse = allocFloats(color); } /** * Set the ambient material color. 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. */ public void setAmbient(float[] color) { ambient = allocFloats(color); } /** * Set the specular material color. 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() */ public void setSpecular(float[] color) { specular = allocFloats(color); } /** * Set the emission material color. This controls the "glow" of the material, * and can be used to make a material that seems to be lit from inside. */ public void setEmission(float[] color) { 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}; 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 GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE, diffuse); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, ambient); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, specular); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_EMISSION, emission); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SHININESS, shininess); } /** * Reset all material settings to the default values. */ public static void clear() { GL11.glMaterial(GL11.GL_FRONT, GL11.GL_DIFFUSE, defaultDiffuse); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_AMBIENT, defaultAmbient); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_SPECULAR, defaultSpecular); GL11.glMaterial(GL11.GL_FRONT, GL11.GL_EMISSION, defaultEmission); GL11.glMaterial(GL11.GL_FRONT, GL11.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. */ public void setColor(float[] color) { setDiffuse(color); // surface directly lit 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 */ public void setReflection(float intensity, float highlight) { float[] color = {intensity,intensity,intensity,1}; // create a shade of gray setSpecular(color); setShininess((int)(highlight*127f)); // convert 0-1 to 0-127 } /** * Make material appear to emit light */ public void setGlowColor(float[] color) { emission = allocFloats(color); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Native IO buffer functions * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ public static final int SIZE_FLOAT = 4; // four bytes in a float public static FloatBuffer allocFloats(int howmany) { return ByteBuffer.allocateDirect(howmany * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); } public static FloatBuffer allocFloats(float[] floatarray) { FloatBuffer fb = ByteBuffer.allocateDirect(floatarray.length * SIZE_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer(); fb.put(floatarray).flip(); return fb; } }