Java tutorial
/** * 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.ARBImaging; import org.lwjgl.opengl.ARBMultisample; import org.lwjgl.opengl.EXTBlendColor; import org.lwjgl.opengl.EXTBlendEquationSeparate; import org.lwjgl.opengl.EXTBlendFuncSeparate; import org.lwjgl.opengl.EXTBlendMinmax; import org.lwjgl.opengl.EXTBlendSubtract; import org.lwjgl.opengl.GL11; import com.ardor3d.math.type.ReadOnlyColorRGBA; import com.ardor3d.renderer.ContextCapabilities; import com.ardor3d.renderer.ContextManager; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.state.BlendState; import com.ardor3d.renderer.state.BlendState.BlendEquation; import com.ardor3d.renderer.state.BlendState.DestinationFunction; import com.ardor3d.renderer.state.BlendState.SourceFunction; import com.ardor3d.renderer.state.BlendState.TestFunction; import com.ardor3d.renderer.state.RenderState.StateType; import com.ardor3d.renderer.state.record.BlendStateRecord; public abstract class LwjglBlendStateUtil { public static void apply(final BlendState state) { // ask for the current state record final RenderContext context = ContextManager.getCurrentContext(); final BlendStateRecord record = (BlendStateRecord) context.getStateRecord(StateType.Blend); final ContextCapabilities caps = context.getCapabilities(); context.setCurrentState(StateType.Blend, state); if (state.isEnabled()) { applyBlendEquations(state.isBlendEnabled(), state, record, caps); applyBlendColor(state.isBlendEnabled(), state, record, caps); applyBlendFunctions(state.isBlendEnabled(), state, record, caps); applyTest(state.isTestEnabled(), state, record); if (caps.isMultisampleSupported()) { applyAlphaCoverage(state.isSampleAlphaToCoverageEnabled(), state.isSampleAlphaToOneEnabled(), record, caps); applySampleCoverage(state.isSampleCoverageEnabled(), state, record, caps); } } else { // disable blend applyBlendEquations(false, state, record, caps); // disable alpha test applyTest(false, state, record); // disable sample coverage if (caps.isMultisampleSupported()) { applyAlphaCoverage(false, false, record, caps); applySampleCoverage(false, state, record, caps); } } if (!record.isValid()) { record.validate(); } } protected static void applyBlendEquations(final boolean enabled, final BlendState state, final BlendStateRecord record, final ContextCapabilities caps) { if (record.isValid()) { if (enabled) { if (!record.blendEnabled) { GL11.glEnable(GL11.GL_BLEND); record.blendEnabled = true; } final int blendEqRGB = getGLEquationValue(state.getBlendEquationRGB(), caps); if (caps.isSeparateBlendEquationsSupported()) { final int blendEqAlpha = getGLEquationValue(state.getBlendEquationAlpha(), caps); if (record.blendEqRGB != blendEqRGB || record.blendEqAlpha != blendEqAlpha) { EXTBlendEquationSeparate.glBlendEquationSeparateEXT(blendEqRGB, blendEqAlpha); record.blendEqRGB = blendEqRGB; record.blendEqAlpha = blendEqAlpha; } } else if (caps.isBlendEquationSupported()) { if (record.blendEqRGB != blendEqRGB) { ARBImaging.glBlendEquation(blendEqRGB); record.blendEqRGB = blendEqRGB; } } } else if (record.blendEnabled) { GL11.glDisable(GL11.GL_BLEND); record.blendEnabled = false; } } else { if (enabled) { GL11.glEnable(GL11.GL_BLEND); record.blendEnabled = true; final int blendEqRGB = getGLEquationValue(state.getBlendEquationRGB(), caps); if (caps.isSeparateBlendEquationsSupported()) { final int blendEqAlpha = getGLEquationValue(state.getBlendEquationAlpha(), caps); EXTBlendEquationSeparate.glBlendEquationSeparateEXT(blendEqRGB, blendEqAlpha); record.blendEqRGB = blendEqRGB; record.blendEqAlpha = blendEqAlpha; } else if (caps.isBlendEquationSupported()) { ARBImaging.glBlendEquation(blendEqRGB); record.blendEqRGB = blendEqRGB; } } else { GL11.glDisable(GL11.GL_BLEND); record.blendEnabled = false; } } } protected static void applyBlendColor(final boolean enabled, final BlendState state, final BlendStateRecord record, final ContextCapabilities caps) { if (enabled) { final boolean applyConstant = state.getDestinationFunctionRGB().usesConstantColor() || state.getSourceFunctionRGB().usesConstantColor() || (caps.isConstantBlendColorSupported() && (state.getDestinationFunctionAlpha().usesConstantColor() || state.getSourceFunctionAlpha().usesConstantColor())); if (applyConstant && caps.isConstantBlendColorSupported()) { final ReadOnlyColorRGBA constant = state.getConstantColor(); if (!record.isValid() || (caps.isConstantBlendColorSupported() && !record.blendColor.equals(constant))) { ARBImaging.glBlendColor(constant.getRed(), constant.getGreen(), constant.getBlue(), constant.getAlpha()); record.blendColor.set(constant); } } } } protected static void applyBlendFunctions(final boolean enabled, final BlendState state, final BlendStateRecord record, final ContextCapabilities caps) { if (record.isValid()) { if (enabled) { final int glSrcRGB = getGLSrcValue(state.getSourceFunctionRGB(), caps); final int glDstRGB = getGLDstValue(state.getDestinationFunctionRGB(), caps); if (caps.isSeparateBlendFunctionsSupported()) { final int glSrcAlpha = getGLSrcValue(state.getSourceFunctionAlpha(), caps); final int glDstAlpha = getGLDstValue(state.getDestinationFunctionAlpha(), caps); if (record.srcFactorRGB != glSrcRGB || record.dstFactorRGB != glDstRGB || record.srcFactorAlpha != glSrcAlpha || record.dstFactorAlpha != glDstAlpha) { EXTBlendFuncSeparate.glBlendFuncSeparateEXT(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha); record.srcFactorRGB = glSrcRGB; record.dstFactorRGB = glDstRGB; record.srcFactorAlpha = glSrcAlpha; record.dstFactorAlpha = glDstAlpha; } } else if (record.srcFactorRGB != glSrcRGB || record.dstFactorRGB != glDstRGB) { GL11.glBlendFunc(glSrcRGB, glDstRGB); record.srcFactorRGB = glSrcRGB; record.dstFactorRGB = glDstRGB; } } } else { if (enabled) { final int glSrcRGB = getGLSrcValue(state.getSourceFunctionRGB(), caps); final int glDstRGB = getGLDstValue(state.getDestinationFunctionRGB(), caps); if (caps.isSeparateBlendFunctionsSupported()) { final int glSrcAlpha = getGLSrcValue(state.getSourceFunctionAlpha(), caps); final int glDstAlpha = getGLDstValue(state.getDestinationFunctionAlpha(), caps); EXTBlendFuncSeparate.glBlendFuncSeparateEXT(glSrcRGB, glDstRGB, glSrcAlpha, glDstAlpha); record.srcFactorRGB = glSrcRGB; record.dstFactorRGB = glDstRGB; record.srcFactorAlpha = glSrcAlpha; record.dstFactorAlpha = glDstAlpha; } else { GL11.glBlendFunc(glSrcRGB, glDstRGB); record.srcFactorRGB = glSrcRGB; record.dstFactorRGB = glDstRGB; } } } } protected static void applyAlphaCoverage(final boolean sampleAlphaToCoverageEnabled, final boolean sampleAlphaToOneEnabled, final BlendStateRecord record, final ContextCapabilities caps) { if (record.isValid()) { if (sampleAlphaToCoverageEnabled != record.sampleAlphaToCoverageEnabled) { if (sampleAlphaToCoverageEnabled) { GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } else { GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } record.sampleAlphaToCoverageEnabled = sampleAlphaToCoverageEnabled; } if (sampleAlphaToOneEnabled != record.sampleAlphaToOneEnabled) { if (sampleAlphaToOneEnabled) { GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB); } else { GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB); } record.sampleAlphaToOneEnabled = sampleAlphaToOneEnabled; } } else { if (sampleAlphaToCoverageEnabled) { GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } else { GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); } record.sampleAlphaToCoverageEnabled = sampleAlphaToCoverageEnabled; if (sampleAlphaToOneEnabled) { GL11.glEnable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB); } else { GL11.glDisable(ARBMultisample.GL_SAMPLE_ALPHA_TO_ONE_ARB); } record.sampleAlphaToOneEnabled = sampleAlphaToOneEnabled; } } protected static void applySampleCoverage(final boolean enabled, final BlendState state, final BlendStateRecord record, final ContextCapabilities caps) { final boolean coverageInverted = state.isSampleCoverageInverted(); final float coverageValue = state.getSampleCoverage(); if (record.isValid()) { if (enabled) { if (!record.sampleCoverageEnabled) { GL11.glEnable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB); record.sampleCoverageEnabled = true; } if (record.sampleCoverageInverted != coverageInverted || record.sampleCoverage != coverageValue) { ARBMultisample.glSampleCoverageARB(coverageValue, coverageInverted); record.sampleCoverageInverted = coverageInverted; record.sampleCoverage = coverageValue; } } else { if (record.sampleCoverageEnabled) { GL11.glDisable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB); record.sampleCoverageEnabled = false; } } } else { if (enabled) { GL11.glEnable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB); record.sampleCoverageEnabled = true; ARBMultisample.glSampleCoverageARB(coverageValue, coverageInverted); record.sampleCoverageInverted = coverageInverted; record.sampleCoverage = coverageValue; } else { GL11.glDisable(ARBMultisample.GL_SAMPLE_COVERAGE_ARB); record.sampleCoverageEnabled = false; } } } protected static int getGLSrcValue(final SourceFunction function, final ContextCapabilities caps) { switch (function) { case Zero: return GL11.GL_ZERO; case DestinationColor: return GL11.GL_DST_COLOR; case OneMinusDestinationColor: return GL11.GL_ONE_MINUS_DST_COLOR; case SourceAlpha: return GL11.GL_SRC_ALPHA; case OneMinusSourceAlpha: return GL11.GL_ONE_MINUS_SRC_ALPHA; case DestinationAlpha: return GL11.GL_DST_ALPHA; case OneMinusDestinationAlpha: return GL11.GL_ONE_MINUS_DST_ALPHA; case SourceAlphaSaturate: return GL11.GL_SRC_ALPHA_SATURATE; case ConstantColor: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_CONSTANT_COLOR_EXT; } // FALLS THROUGH case OneMinusConstantColor: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_ONE_MINUS_CONSTANT_COLOR_EXT; } // FALLS THROUGH case ConstantAlpha: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_CONSTANT_ALPHA_EXT; } // FALLS THROUGH case OneMinusConstantAlpha: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_ONE_MINUS_CONSTANT_ALPHA_EXT; } // FALLS THROUGH case One: return GL11.GL_ONE; } throw new IllegalArgumentException("Invalid source function type: " + function); } protected static int getGLDstValue(final DestinationFunction function, final ContextCapabilities caps) { switch (function) { case Zero: return GL11.GL_ZERO; case SourceColor: return GL11.GL_SRC_COLOR; case OneMinusSourceColor: return GL11.GL_ONE_MINUS_SRC_COLOR; case SourceAlpha: return GL11.GL_SRC_ALPHA; case OneMinusSourceAlpha: return GL11.GL_ONE_MINUS_SRC_ALPHA; case DestinationAlpha: return GL11.GL_DST_ALPHA; case OneMinusDestinationAlpha: return GL11.GL_ONE_MINUS_DST_ALPHA; case ConstantColor: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_CONSTANT_COLOR_EXT; } // FALLS THROUGH case OneMinusConstantColor: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_ONE_MINUS_CONSTANT_COLOR_EXT; } // FALLS THROUGH case ConstantAlpha: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_CONSTANT_ALPHA_EXT; } // FALLS THROUGH case OneMinusConstantAlpha: if (caps.isConstantBlendColorSupported()) { return EXTBlendColor.GL_ONE_MINUS_CONSTANT_ALPHA_EXT; } // FALLS THROUGH case One: return GL11.GL_ONE; } throw new IllegalArgumentException("Invalid destination function type: " + function); } protected static int getGLEquationValue(final BlendEquation eq, final ContextCapabilities caps) { switch (eq) { case Min: if (caps.isMinMaxBlendEquationsSupported()) { return EXTBlendMinmax.GL_MIN_EXT; } // FALLS THROUGH case Max: if (caps.isMinMaxBlendEquationsSupported()) { return EXTBlendMinmax.GL_MAX_EXT; } else { return ARBImaging.GL_FUNC_ADD; } case Subtract: if (caps.isSubtractBlendEquationsSupported()) { return EXTBlendSubtract.GL_FUNC_SUBTRACT_EXT; } // FALLS THROUGH case ReverseSubtract: if (caps.isSubtractBlendEquationsSupported()) { return EXTBlendSubtract.GL_FUNC_REVERSE_SUBTRACT_EXT; } // FALLS THROUGH case Add: return ARBImaging.GL_FUNC_ADD; } throw new IllegalArgumentException("Invalid blend equation: " + eq); } protected static void applyTest(final boolean enabled, final BlendState state, final BlendStateRecord record) { if (record.isValid()) { if (enabled) { if (!record.testEnabled) { GL11.glEnable(GL11.GL_ALPHA_TEST); record.testEnabled = true; } final int glFunc = getGLFuncValue(state.getTestFunction()); if (record.alphaFunc != glFunc || record.alphaRef != state.getReference()) { GL11.glAlphaFunc(glFunc, state.getReference()); record.alphaFunc = glFunc; record.alphaRef = state.getReference(); } } else if (record.testEnabled) { GL11.glDisable(GL11.GL_ALPHA_TEST); record.testEnabled = false; } } else { if (enabled) { GL11.glEnable(GL11.GL_ALPHA_TEST); record.testEnabled = true; final int glFunc = getGLFuncValue(state.getTestFunction()); GL11.glAlphaFunc(glFunc, state.getReference()); record.alphaFunc = glFunc; record.alphaRef = state.getReference(); } else { GL11.glDisable(GL11.GL_ALPHA_TEST); record.testEnabled = false; } } } protected static int getGLFuncValue(final TestFunction function) { switch (function) { case Never: return GL11.GL_NEVER; case LessThan: return GL11.GL_LESS; case EqualTo: return GL11.GL_EQUAL; case LessThanOrEqualTo: return GL11.GL_LEQUAL; case GreaterThan: return GL11.GL_GREATER; case NotEqualTo: return GL11.GL_NOTEQUAL; case GreaterThanOrEqualTo: return GL11.GL_GEQUAL; case Always: return GL11.GL_ALWAYS; } throw new IllegalArgumentException("Invalid test function type: " + function); } }