/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
package com.ardor3d.scene.state.lwjgl;
import org.lwjgl.opengl.GL11;
import com.ardor3d.math.type.ReadOnlyColorRGBA;
import com.ardor3d.renderer.ContextManager;
import com.ardor3d.renderer.RenderContext;
import com.ardor3d.renderer.state.MaterialState;
import com.ardor3d.renderer.state.MaterialState.ColorMaterial;
import com.ardor3d.renderer.state.MaterialState.MaterialFace;
import com.ardor3d.renderer.state.RenderState.StateType;
import com.ardor3d.renderer.state.record.MaterialStateRecord;
public abstract class LwjglMaterialStateUtil {
public static void apply(final MaterialState state) {
// ask for the current state record
final RenderContext context = ContextManager.getCurrentContext();
final MaterialStateRecord record = (MaterialStateRecord) context.getStateRecord(StateType.Material);
context.setCurrentState(StateType.Material, state);
if (state.isEnabled()) {
// setup colormaterial, if changed.
applyColorMaterial(state.getColorMaterial(), state.getColorMaterialFace(), record);
// apply colors, if needed and not what is currently set.
applyColor(ColorMaterial.Ambient, state.getAmbient(), state.getBackAmbient(), record);
applyColor(ColorMaterial.Diffuse, state.getDiffuse(), state.getBackDiffuse(), record);
applyColor(ColorMaterial.Emissive, state.getEmissive(), state.getBackEmissive(), record);
applyColor(ColorMaterial.Specular, state.getSpecular(), state.getBackSpecular(), record);
// set our shine
applyShininess(state.getShininess(), state.getBackShininess(), record);
} else {
// apply defaults
applyColorMaterial(MaterialState.DEFAULT_COLOR_MATERIAL, MaterialState.DEFAULT_COLOR_MATERIAL_FACE, record);
applyColor(ColorMaterial.Ambient, MaterialState.DEFAULT_AMBIENT, MaterialState.DEFAULT_AMBIENT, record);
applyColor(ColorMaterial.Diffuse, MaterialState.DEFAULT_DIFFUSE, MaterialState.DEFAULT_DIFFUSE, record);
applyColor(ColorMaterial.Emissive, MaterialState.DEFAULT_EMISSIVE, MaterialState.DEFAULT_EMISSIVE, record);
applyColor(ColorMaterial.Specular, MaterialState.DEFAULT_SPECULAR, MaterialState.DEFAULT_SPECULAR, record);
applyShininess(MaterialState.DEFAULT_SHININESS, MaterialState.DEFAULT_SHININESS, record);
}
if (!record.isValid()) {
record.validate();
}
}
private static void applyColor(final ColorMaterial glMatColor, final ReadOnlyColorRGBA frontColor,
final ReadOnlyColorRGBA backColor, final MaterialStateRecord record) {
final int glMat = getGLColorMaterial(glMatColor);
if (frontColor.equals(backColor)) {
// consolidate to one call
if (!isVertexProvidedColor(MaterialFace.FrontAndBack, glMatColor, record)) {
if (!record.isValid() || !record.isSetColor(MaterialFace.FrontAndBack, glMatColor, frontColor, record)) {
record.tempColorBuff.clear();
record.tempColorBuff.put(frontColor.getRed()).put(frontColor.getGreen()).put(frontColor.getBlue())
.put(frontColor.getAlpha());
record.tempColorBuff.flip();
GL11.glMaterial(getGLMaterialFace(MaterialFace.FrontAndBack), glMat, record.tempColorBuff);
record.setColor(MaterialFace.FrontAndBack, glMatColor, frontColor);
}
}
} else {
if (!isVertexProvidedColor(MaterialFace.Front, glMatColor, record)) {
if (!record.isValid() || !record.isSetColor(MaterialFace.Front, glMatColor, frontColor, record)) {
record.tempColorBuff.clear();
record.tempColorBuff.put(frontColor.getRed()).put(frontColor.getGreen()).put(frontColor.getBlue())
.put(frontColor.getAlpha());
record.tempColorBuff.flip();
GL11.glMaterial(getGLMaterialFace(MaterialFace.Front), glMat, record.tempColorBuff);
record.setColor(MaterialFace.Front, glMatColor, frontColor);
}
}
if (!isVertexProvidedColor(MaterialFace.Back, glMatColor, record)) {
if (!record.isValid() || !record.isSetColor(MaterialFace.Back, glMatColor, backColor, record)) {
record.tempColorBuff.clear();
record.tempColorBuff.put(backColor.getRed()).put(backColor.getGreen()).put(backColor.getBlue())
.put(backColor.getAlpha());
record.tempColorBuff.flip();
GL11.glMaterial(getGLMaterialFace(MaterialFace.Back), glMat, record.tempColorBuff);
record.setColor(MaterialFace.Back, glMatColor, backColor);
}
}
}
}
private static boolean isVertexProvidedColor(final MaterialFace face, final ColorMaterial glMatColor,
final MaterialStateRecord record) {
if (face != record.colorMaterialFace) {
return false;
}
switch (glMatColor) {
case Ambient:
return record.colorMaterial == ColorMaterial.Ambient
|| record.colorMaterial == ColorMaterial.AmbientAndDiffuse;
case Diffuse:
return record.colorMaterial == ColorMaterial.Diffuse
|| record.colorMaterial == ColorMaterial.AmbientAndDiffuse;
case Specular:
return record.colorMaterial == ColorMaterial.Specular;
case Emissive:
return record.colorMaterial == ColorMaterial.Emissive;
}
return false;
}
private static void applyColorMaterial(final ColorMaterial colorMaterial, final MaterialFace face,
final MaterialStateRecord record) {
if (!record.isValid() || face != record.colorMaterialFace || colorMaterial != record.colorMaterial) {
if (colorMaterial == ColorMaterial.None) {
GL11.glDisable(GL11.GL_COLOR_MATERIAL);
} else {
final int glMat = getGLColorMaterial(colorMaterial);
final int glFace = getGLMaterialFace(face);
GL11.glColorMaterial(glFace, glMat);
GL11.glEnable(GL11.GL_COLOR_MATERIAL);
record.resetColorsForCM(face, colorMaterial);
}
record.colorMaterial = colorMaterial;
record.colorMaterialFace = face;
}
}
private static void applyShininess(final float frontShininess, final float backShininess,
final MaterialStateRecord record) {
if (frontShininess == backShininess) {
// consolidate to one call
if (!record.isValid() || frontShininess != record.frontShininess || record.backShininess != backShininess) {
GL11.glMaterialf(getGLMaterialFace(MaterialFace.FrontAndBack), GL11.GL_SHININESS, frontShininess);
record.backShininess = record.frontShininess = frontShininess;
}
} else {
if (!record.isValid() || frontShininess != record.frontShininess) {
GL11.glMaterialf(getGLMaterialFace(MaterialFace.Front), GL11.GL_SHININESS, frontShininess);
record.frontShininess = frontShininess;
}
if (!record.isValid() || backShininess != record.backShininess) {
GL11.glMaterialf(getGLMaterialFace(MaterialFace.Back), GL11.GL_SHININESS, backShininess);
record.backShininess = backShininess;
}
}
}
/**
* Converts the color material setting of this state to a GL constant.
*
* @return the GL constant
*/
private static int getGLColorMaterial(final ColorMaterial material) {
switch (material) {
case None:
return GL11.GL_NONE;
case Ambient:
return GL11.GL_AMBIENT;
case Diffuse:
return GL11.GL_DIFFUSE;
case AmbientAndDiffuse:
return GL11.GL_AMBIENT_AND_DIFFUSE;
case Emissive:
return GL11.GL_EMISSION;
case Specular:
return GL11.GL_SPECULAR;
}
throw new IllegalArgumentException("invalid color material setting: " + material);
}
/**
* Converts the material face setting of this state to a GL constant.
*
* @return the GL constant
*/
private static int getGLMaterialFace(final MaterialFace face) {
switch (face) {
case Front:
return GL11.GL_FRONT;
case Back:
return GL11.GL_BACK;
case FrontAndBack:
return GL11.GL_FRONT_AND_BACK;
}
throw new IllegalArgumentException("invalid material face setting: " + face);
}
}