com.ardor3d.scene.state.lwjgl.LwjglBlendStateUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.ardor3d.scene.state.lwjgl.LwjglBlendStateUtil.java

Source

/**
 * 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);
    }
}