Package com.ardor3d.scene.state.lwjgl

Source Code of com.ardor3d.scene.state.lwjgl.LwjglShaderObjectsStateUtil

/**
* 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 java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.logging.Logger;

import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.ARBGeometryShader4;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBTessellationShader;
import org.lwjgl.opengl.ARBVertexProgram;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;

import com.ardor3d.renderer.ContextCapabilities;
import com.ardor3d.renderer.ContextManager;
import com.ardor3d.renderer.RenderContext;
import com.ardor3d.renderer.lwjgl.LwjglRenderer;
import com.ardor3d.renderer.state.GLSLShaderObjectsState;
import com.ardor3d.renderer.state.RenderState.StateType;
import com.ardor3d.renderer.state.record.ShaderObjectsStateRecord;
import com.ardor3d.scene.state.lwjgl.shader.LwjglShaderUtil;
import com.ardor3d.util.Ardor3dException;
import com.ardor3d.util.geom.BufferUtils;
import com.ardor3d.util.shader.ShaderVariable;

public abstract class LwjglShaderObjectsStateUtil {
    private static final Logger logger = Logger.getLogger(LwjglShaderObjectsStateUtil.class.getName());

    protected static void sendToGL(final GLSLShaderObjectsState state, final ContextCapabilities caps) {
        if (state.getVertexShader() == null && state.getFragmentShader() == null) {
            logger.warning("Could not find shader resources!" + "(both inputbuffers are null)");
            state._needSendShader = false;
            return;
        }

        if (state._programID == -1) {
            state._programID = ARBShaderObjects.glCreateProgramObjectARB();
        }

        if (state.getVertexShader() != null) {
            if (state._vertexShaderID != -1) {
                removeVertShader(state);
            }

            state._vertexShaderID = ARBShaderObjects.glCreateShaderObjectARB(ARBVertexShader.GL_VERTEX_SHADER_ARB);

            // Create the sources
            ARBShaderObjects.glShaderSourceARB(state._vertexShaderID, state.getVertexShader());

            // Compile the vertex shader
            final IntBuffer compiled = BufferUtils.createIntBuffer(1);
            ARBShaderObjects.glCompileShaderARB(state._vertexShaderID);
            ARBShaderObjects.glGetObjectParameterARB(state._vertexShaderID,
                    ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
            checkProgramError(compiled, state._vertexShaderID, state._vertexShaderName);

            // Attach the program
            ARBShaderObjects.glAttachObjectARB(state._programID, state._vertexShaderID);
        } else if (state._vertexShaderID != -1) {
            removeVertShader(state);
            state._vertexShaderID = -1;
        }

        if (state.getFragmentShader() != null) {
            if (state._fragmentShaderID != -1) {
                removeFragShader(state);
            }

            state._fragmentShaderID = ARBShaderObjects
                    .glCreateShaderObjectARB(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);

            // Create the sources
            ARBShaderObjects.glShaderSourceARB(state._fragmentShaderID, state.getFragmentShader());

            // Compile the fragment shader
            final IntBuffer compiled = BufferUtils.createIntBuffer(1);
            ARBShaderObjects.glCompileShaderARB(state._fragmentShaderID);
            ARBShaderObjects.glGetObjectParameterARB(state._fragmentShaderID,
                    ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
            checkProgramError(compiled, state._fragmentShaderID, state._fragmentShaderName);

            // Attach the program
            ARBShaderObjects.glAttachObjectARB(state._programID, state._fragmentShaderID);
        } else if (state._fragmentShaderID != -1) {
            removeFragShader(state);
            state._fragmentShaderID = -1;
        }

        if (caps.isGeometryShader4Supported()) {
            if (state.getGeometryShader() != null) {
                if (state._geometryShaderID != -1) {
                    removeGeomShader(state);
                }

                state._geometryShaderID = ARBShaderObjects
                        .glCreateShaderObjectARB(ARBGeometryShader4.GL_GEOMETRY_SHADER_ARB);

                // Create the sources
                ARBShaderObjects.glShaderSourceARB(state._geometryShaderID, state.getGeometryShader());

                // Compile the fragment shader
                final IntBuffer compiled = BufferUtils.createIntBuffer(1);
                ARBShaderObjects.glCompileShaderARB(state._geometryShaderID);
                ARBShaderObjects.glGetObjectParameterARB(state._geometryShaderID,
                        ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
                checkProgramError(compiled, state._geometryShaderID, state._geometryShaderName);

                // Attach the program
                ARBShaderObjects.glAttachObjectARB(state._programID, state._geometryShaderID);
            } else if (state._geometryShaderID != -1) {
                removeGeomShader(state);
                state._geometryShaderID = -1;
            }
        }

        if (caps.isTessellationShadersSupported()) {
            if (state.getTessellationControlShader() != null) {
                if (state._tessellationControlShaderID != -1) {
                    removeTessControlShader(state);
                }

                state._tessellationControlShaderID = ARBShaderObjects
                        .glCreateShaderObjectARB(ARBTessellationShader.GL_TESS_CONTROL_SHADER);

                // Create the sources
                ARBShaderObjects.glShaderSourceARB(state._tessellationControlShaderID,
                        state.getTessellationControlShader());

                // Compile the tessellation control shader
                final IntBuffer compiled = BufferUtils.createIntBuffer(1);
                ARBShaderObjects.glCompileShaderARB(state._tessellationControlShaderID);
                ARBShaderObjects.glGetObjectParameterARB(state._tessellationControlShaderID,
                        ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
                checkProgramError(compiled, state._tessellationControlShaderID, state._tessellationControlShaderName);

                // Attach the program
                ARBShaderObjects.glAttachObjectARB(state._programID, state._tessellationControlShaderID);
            } else if (state._tessellationControlShaderID != -1) {
                removeTessControlShader(state);
                state._tessellationControlShaderID = -1;
            }

            if (state.getTessellationEvaluationShader() != null) {
                if (state._tessellationEvaluationShaderID != -1) {
                    removeTessEvalShader(state);
                }

                state._tessellationEvaluationShaderID = ARBShaderObjects
                        .glCreateShaderObjectARB(ARBTessellationShader.GL_TESS_CONTROL_SHADER);

                // Create the sources
                ARBShaderObjects.glShaderSourceARB(state._tessellationEvaluationShaderID,
                        state.getTessellationEvaluationShader());

                // Compile the tessellation control shader
                final IntBuffer compiled = BufferUtils.createIntBuffer(1);
                ARBShaderObjects.glCompileShaderARB(state._tessellationEvaluationShaderID);
                ARBShaderObjects.glGetObjectParameterARB(state._tessellationEvaluationShaderID,
                        ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB, compiled);
                checkProgramError(compiled, state._tessellationEvaluationShaderID,
                        state._tessellationEvaluationShaderName);

                // Attach the program
                ARBShaderObjects.glAttachObjectARB(state._programID, state._tessellationEvaluationShaderID);
            } else if (state._tessellationEvaluationShaderID != -1) {
                removeTessEvalShader(state);
                state._tessellationEvaluationShaderID = -1;
            }
        }

        ARBShaderObjects.glLinkProgramARB(state._programID);
        checkLinkError(state._programID);
        state.setNeedsRefresh(true);
        state._needSendShader = false;
    }

    private static void checkLinkError(final int programId) {
        final IntBuffer compiled = BufferUtils.createIntBuffer(1);
        ARBShaderObjects.glGetObjectParameterARB(programId, GL20.GL_LINK_STATUS, compiled);
        if (compiled.get(0) == GL11.GL_FALSE) {
            ARBShaderObjects.glGetObjectParameterARB(programId, GL20.GL_INFO_LOG_LENGTH, compiled);
            final int length = compiled.get(0);
            String out = null;
            if (length > 0) {
                final ByteBuffer infoLog = BufferUtils.createByteBuffer(length);

                ARBShaderObjects.glGetInfoLogARB(programId, compiled, infoLog);

                final byte[] infoBytes = new byte[length];
                infoLog.get(infoBytes);
                out = new String(infoBytes);
            }

            logger.severe(out);

            throw new Ardor3dException("Error linking GLSL shader: " + out);
        }
    }

    /** Removes the geometry shader */
    private static void removeGeomShader(final GLSLShaderObjectsState state) {
        if (state._geometryShaderID != -1) {
            ARBShaderObjects.glDetachObjectARB(state._programID, state._geometryShaderID);
            ARBShaderObjects.glDeleteObjectARB(state._geometryShaderID);
        }
    }

    /** Removes the fragment shader */
    private static void removeFragShader(final GLSLShaderObjectsState state) {
        if (state._fragmentShaderID != -1) {
            ARBShaderObjects.glDetachObjectARB(state._programID, state._fragmentShaderID);
            ARBShaderObjects.glDeleteObjectARB(state._fragmentShaderID);
        }
    }

    /**
     * Removes the vertex shader
     */
    private static void removeVertShader(final GLSLShaderObjectsState state) {
        if (state._vertexShaderID != -1) {
            ARBShaderObjects.glDetachObjectARB(state._programID, state._vertexShaderID);
            ARBShaderObjects.glDeleteObjectARB(state._vertexShaderID);
        }
    }

    /** Removes the tessellation control shader */
    private static void removeTessControlShader(final GLSLShaderObjectsState state) {
        if (state._tessellationControlShaderID != -1) {
            ARBShaderObjects.glDetachObjectARB(state._programID, state._tessellationControlShaderID);
            ARBShaderObjects.glDeleteObjectARB(state._tessellationControlShaderID);
        }
    }

    /** Removes the tessellation evaluation shader */
    private static void removeTessEvalShader(final GLSLShaderObjectsState state) {
        if (state._tessellationEvaluationShaderID != -1) {
            ARBShaderObjects.glDetachObjectARB(state._programID, state._tessellationEvaluationShaderID);
            ARBShaderObjects.glDeleteObjectARB(state._tessellationEvaluationShaderID);
        }
    }

    /**
     * Check for program errors. If an error is detected, program exits.
     *
     * @param compiled
     *            the compiler state for a given shader
     * @param id
     *            shader's id
     */
    private static void checkProgramError(final IntBuffer compiled, final int id, final String shaderName) {
        if (compiled.get(0) == GL11.GL_FALSE) {
            final IntBuffer iVal = BufferUtils.createIntBuffer(1);
            ARBShaderObjects.glGetObjectParameterARB(id, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
            final int length = iVal.get(0);
            String out = null;

            if (length > 0) {
                final ByteBuffer infoLog = BufferUtils.createByteBuffer(length);

                ARBShaderObjects.glGetInfoLogARB(id, iVal, infoLog);

                final byte[] infoBytes = new byte[length];
                infoLog.get(infoBytes);
                out = new String(infoBytes);
            }

            logger.severe(out);
            final String nameString = shaderName.equals("") ? "" : " [ " + shaderName + " ]";
            throw new Ardor3dException("Error compiling GLSL shader " + nameString + ": " + out);

        }
    }

    public static void apply(final LwjglRenderer renderer, final GLSLShaderObjectsState state) {
        final RenderContext context = ContextManager.getCurrentContext();
        final ContextCapabilities caps = context.getCapabilities();

        if (caps.isGLSLSupported()) {
            // Ask for the current state record
            final ShaderObjectsStateRecord record = (ShaderObjectsStateRecord) context
                    .getStateRecord(StateType.GLSLShader);
            context.setCurrentState(StateType.GLSLShader, state);

            if (state.isEnabled()) {
                if (state._needSendShader) {
                    sendToGL(state, caps);
                }

                if (state._shaderDataLogic != null) {
                    state._shaderDataLogic.applyData(state, state._mesh, renderer);
                }
            }

            if (!record.isValid() || record.getReference() != state || state.needsRefresh()) {
                record.setReference(state);
                if (state.isEnabled() && state._programID != -1) {
                    // clear any previously existing attributes
                    clearEnabledAttributes(record);

                    // set our current shader
                    LwjglShaderUtil.useShaderProgram(state._programID, record);

                    for (int i = state.getShaderAttributes().size(); --i >= 0;) {
                        final ShaderVariable shaderVariable = state.getShaderAttributes().get(i);
                        if (shaderVariable.needsRefresh) {
                            LwjglShaderUtil.updateAttributeLocation(shaderVariable, state._programID);
                            shaderVariable.needsRefresh = false;
                        }
                        LwjglShaderUtil.updateShaderAttribute(renderer, shaderVariable, state.isUseAttributeVBO());
                    }

                    for (int i = state.getShaderUniforms().size(); --i >= 0;) {
                        final ShaderVariable shaderVariable = state.getShaderUniforms().get(i);
                        if (shaderVariable.needsRefresh) {
                            LwjglShaderUtil.updateUniformLocation(shaderVariable, state._programID);
                            LwjglShaderUtil.updateShaderUniform(shaderVariable);
                            shaderVariable.needsRefresh = false;
                        }
                    }
                } else {
                    LwjglShaderUtil.useShaderProgram(0, record);

                    clearEnabledAttributes(record);
                }
            }

            if (!record.isValid()) {
                record.validate();
            }
        }
    }

    private static void clearEnabledAttributes(final ShaderObjectsStateRecord record) {
        // go through and disable any enabled attributes
        if (!record.enabledAttributes.isEmpty()) {
            for (int i = 0, maxI = record.enabledAttributes.size(); i < maxI; i++) {
                final ShaderVariable var = record.enabledAttributes.get(i);
                if (var.getSize() == 1) {
                    ARBVertexProgram.glDisableVertexAttribArrayARB(var.variableID);
                } else {
                    for (int j = 0, maxJ = var.getSize(); j < maxJ; j++) {
                        ARBVertexProgram.glDisableVertexAttribArrayARB(var.variableID + j);
                    }
                }
            }
            record.enabledAttributes.clear();
        }
    }
}
TOP

Related Classes of com.ardor3d.scene.state.lwjgl.LwjglShaderObjectsStateUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.