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.shader; import java.nio.ByteBuffer; import java.util.logging.Logger; import org.lwjgl.opengl.ARBShaderObjects; import org.lwjgl.opengl.ARBVertexProgram; import org.lwjgl.opengl.ARBVertexShader; import org.lwjgl.opengl.GL11; import com.ardor3d.renderer.ContextCapabilities; import com.ardor3d.renderer.ContextManager; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.lwjgl.LwjglRenderer; import com.ardor3d.renderer.state.RenderState.StateType; import com.ardor3d.renderer.state.record.ShaderObjectsStateRecord; import com.ardor3d.scene.state.lwjgl.util.LwjglRendererUtil; import com.ardor3d.util.geom.BufferUtils; import com.ardor3d.util.shader.ShaderVariable; import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat; import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat2; import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat3; import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloat4; import com.ardor3d.util.shader.uniformtypes.ShaderVariableFloatArray; import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt; import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt2; import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt3; import com.ardor3d.util.shader.uniformtypes.ShaderVariableInt4; import com.ardor3d.util.shader.uniformtypes.ShaderVariableIntArray; import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix2; import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix3; import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix4; import com.ardor3d.util.shader.uniformtypes.ShaderVariableMatrix4Array; import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerByte; import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerFloat; import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerFloatMatrix; import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerInt; import com.ardor3d.util.shader.uniformtypes.ShaderVariablePointerShort; /** Utility class for updating shadervariables(uniforms and attributes) */ public abstract class LwjglShaderUtil { private static final Logger logger = Logger.getLogger(LwjglShaderUtil.class.getName()); /** * Updates a uniform shadervariable. * * @param shaderVariable * variable to update */ public static void updateShaderUniform(final ShaderVariable shaderVariable) { if (!shaderVariable.hasData()) { throw new IllegalArgumentException("shaderVariable has no data: " + shaderVariable.name + " type: " + shaderVariable.getClass().getName()); } if (shaderVariable instanceof ShaderVariableInt) { updateShaderUniform((ShaderVariableInt) shaderVariable); } else if (shaderVariable instanceof ShaderVariableInt2) { updateShaderUniform((ShaderVariableInt2) shaderVariable); } else if (shaderVariable instanceof ShaderVariableInt3) { updateShaderUniform((ShaderVariableInt3) shaderVariable); } else if (shaderVariable instanceof ShaderVariableInt4) { updateShaderUniform((ShaderVariableInt4) shaderVariable); } else if (shaderVariable instanceof ShaderVariableIntArray) { updateShaderUniform((ShaderVariableIntArray) shaderVariable); } else if (shaderVariable instanceof ShaderVariableFloat) { updateShaderUniform((ShaderVariableFloat) shaderVariable); } else if (shaderVariable instanceof ShaderVariableFloat2) { updateShaderUniform((ShaderVariableFloat2) shaderVariable); } else if (shaderVariable instanceof ShaderVariableFloat3) { updateShaderUniform((ShaderVariableFloat3) shaderVariable); } else if (shaderVariable instanceof ShaderVariableFloat4) { updateShaderUniform((ShaderVariableFloat4) shaderVariable); } else if (shaderVariable instanceof ShaderVariableFloatArray) { updateShaderUniform((ShaderVariableFloatArray) shaderVariable); } else if (shaderVariable instanceof ShaderVariableMatrix2) { updateShaderUniform((ShaderVariableMatrix2) shaderVariable); } else if (shaderVariable instanceof ShaderVariableMatrix3) { updateShaderUniform((ShaderVariableMatrix3) shaderVariable); } else if (shaderVariable instanceof ShaderVariableMatrix4) { updateShaderUniform((ShaderVariableMatrix4) shaderVariable); } else if (shaderVariable instanceof ShaderVariableMatrix4Array) { updateShaderUniform((ShaderVariableMatrix4Array) shaderVariable); } else { logger.warning("updateShaderUniform: Unknown shaderVariable type!"); } } /** * Update variableID for uniform shadervariable if needed. * * @param variable * shadervaribale to update ID on * @param programID * shader program context ID */ public static void updateUniformLocation(final ShaderVariable variable, final int programID) { if (variable.variableID == -1) { final ByteBuffer nameBuf = BufferUtils.createByteBuffer(variable.name.getBytes().length + 1); nameBuf.clear(); nameBuf.put(variable.name.getBytes()); nameBuf.rewind(); variable.variableID = ARBShaderObjects.glGetUniformLocationARB(programID, nameBuf); if (variable.variableID == -1 && !variable.errorLogged) { logger.severe("Shader uniform [" + variable.name + "] could not be located in shader"); variable.errorLogged = true; } } } private static void updateShaderUniform(final ShaderVariableInt shaderUniform) { ARBShaderObjects.glUniform1iARB(shaderUniform.variableID, shaderUniform.value1); } private static void updateShaderUniform(final ShaderVariableInt2 shaderUniform) { ARBShaderObjects.glUniform2iARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2); } private static void updateShaderUniform(final ShaderVariableInt3 shaderUniform) { ARBShaderObjects.glUniform3iARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3); } private static void updateShaderUniform(final ShaderVariableInt4 shaderUniform) { ARBShaderObjects.glUniform4iARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3, shaderUniform.value4); } private static void updateShaderUniform(final ShaderVariableIntArray shaderUniform) { switch (shaderUniform.size) { case 1: ARBShaderObjects.glUniform1ARB(shaderUniform.variableID, shaderUniform.value); break; case 2: ARBShaderObjects.glUniform2ARB(shaderUniform.variableID, shaderUniform.value); break; case 3: ARBShaderObjects.glUniform3ARB(shaderUniform.variableID, shaderUniform.value); break; case 4: ARBShaderObjects.glUniform4ARB(shaderUniform.variableID, shaderUniform.value); break; default: throw new IllegalArgumentException("Wrong size: " + shaderUniform.size); } } private static void updateShaderUniform(final ShaderVariableFloat shaderUniform) { ARBShaderObjects.glUniform1fARB(shaderUniform.variableID, shaderUniform.value1); } private static void updateShaderUniform(final ShaderVariableFloat2 shaderUniform) { ARBShaderObjects.glUniform2fARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2); } private static void updateShaderUniform(final ShaderVariableFloat3 shaderUniform) { ARBShaderObjects.glUniform3fARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3); } private static void updateShaderUniform(final ShaderVariableFloat4 shaderUniform) { ARBShaderObjects.glUniform4fARB(shaderUniform.variableID, shaderUniform.value1, shaderUniform.value2, shaderUniform.value3, shaderUniform.value4); } private static void updateShaderUniform(final ShaderVariableFloatArray shaderUniform) { switch (shaderUniform.size) { case 1: ARBShaderObjects.glUniform1ARB(shaderUniform.variableID, shaderUniform.value); break; case 2: ARBShaderObjects.glUniform2ARB(shaderUniform.variableID, shaderUniform.value); break; case 3: ARBShaderObjects.glUniform3ARB(shaderUniform.variableID, shaderUniform.value); break; case 4: ARBShaderObjects.glUniform4ARB(shaderUniform.variableID, shaderUniform.value); break; default: throw new IllegalArgumentException("Wrong size: " + shaderUniform.size); } } private static void updateShaderUniform(final ShaderVariableMatrix2 shaderUniform) { shaderUniform.matrixBuffer.rewind(); ARBShaderObjects.glUniformMatrix2ARB(shaderUniform.variableID, shaderUniform.rowMajor, shaderUniform.matrixBuffer); } private static void updateShaderUniform(final ShaderVariableMatrix3 shaderUniform) { shaderUniform.matrixBuffer.rewind(); ARBShaderObjects.glUniformMatrix3ARB(shaderUniform.variableID, shaderUniform.rowMajor, shaderUniform.matrixBuffer); } private static void updateShaderUniform(final ShaderVariableMatrix4 shaderUniform) { shaderUniform.matrixBuffer.rewind(); ARBShaderObjects.glUniformMatrix4ARB(shaderUniform.variableID, shaderUniform.rowMajor, shaderUniform.matrixBuffer); } private static void updateShaderUniform(final ShaderVariableMatrix4Array shaderUniform) { shaderUniform.matrixBuffer.rewind(); ARBShaderObjects.glUniformMatrix4ARB(shaderUniform.variableID, shaderUniform.rowMajor, shaderUniform.matrixBuffer); } /** * Update variableID for attribute shadervariable if needed. * * @param variable * shadervaribale to update ID on * @param programID * shader program context ID */ public static void updateAttributeLocation(final ShaderVariable variable, final int programID) { if (variable.variableID == -1) { final ByteBuffer nameBuf = BufferUtils.createByteBuffer(variable.name.getBytes().length + 1); nameBuf.clear(); nameBuf.put(variable.name.getBytes()); nameBuf.rewind(); variable.variableID = ARBVertexShader.glGetAttribLocationARB(programID, nameBuf); if (variable.variableID == -1 && !variable.errorLogged) { logger.severe("Shader attribute [" + variable.name + "] could not be located in shader"); variable.errorLogged = true; } } } /** * Updates an vertex attribute pointer. * * @param renderer * the current renderer * @param shaderVariable * variable to update * @param useVBO * if true, we'll use VBO for the attributes, if false we'll use arrays. */ public static void updateShaderAttribute(final Renderer renderer, final ShaderVariable shaderVariable, final boolean useVBO) { if (shaderVariable.variableID == -1) { // attribute is not bound, or was not found in shader. return; } if (!shaderVariable.hasData()) { throw new IllegalArgumentException("shaderVariable has no data: " + shaderVariable.name + " type: " + shaderVariable.getClass().getName()); } final RenderContext context = ContextManager.getCurrentContext(); final ContextCapabilities caps = context.getCapabilities(); if (caps.isVBOSupported() && !useVBO) { renderer.unbindVBO(); } final ShaderObjectsStateRecord record = (ShaderObjectsStateRecord) context .getStateRecord(StateType.GLSLShader); if (shaderVariable instanceof ShaderVariablePointerFloat) { updateShaderAttribute((ShaderVariablePointerFloat) shaderVariable, record, useVBO); } else if (shaderVariable instanceof ShaderVariablePointerFloatMatrix) { updateShaderAttribute((ShaderVariablePointerFloatMatrix) shaderVariable, record, useVBO); } else if (shaderVariable instanceof ShaderVariablePointerByte) { updateShaderAttribute((ShaderVariablePointerByte) shaderVariable, record, useVBO); } else if (shaderVariable instanceof ShaderVariablePointerInt) { updateShaderAttribute((ShaderVariablePointerInt) shaderVariable, record, useVBO); } else if (shaderVariable instanceof ShaderVariablePointerShort) { updateShaderAttribute((ShaderVariablePointerShort) shaderVariable, record, useVBO); } else { logger.warning("updateShaderAttribute: Unknown shaderVariable type!"); return; } } public static void useShaderProgram(final int id, final ShaderObjectsStateRecord record) { if (record.shaderId != id) { ARBShaderObjects.glUseProgramObjectARB(id); record.shaderId = id; } } private static void enableVertexAttribute(final ShaderVariable var, final ShaderObjectsStateRecord record) { if (!record.enabledAttributes.contains(var)) { if (var.getSize() == 1) { ARBVertexProgram.glEnableVertexAttribArrayARB(var.variableID); } else { for (int i = 0, max = var.getSize(); i < max; i++) { ARBVertexProgram.glEnableVertexAttribArrayARB(var.variableID + i); } } record.enabledAttributes.add(var); } } private static void updateShaderAttribute(final ShaderVariablePointerFloat variable, final ShaderObjectsStateRecord record, final boolean useVBO) { enableVertexAttribute(variable, record); if (useVBO) { final RenderContext context = ContextManager.getCurrentContext(); final int vboId = LwjglRenderer.setupVBO(variable.data, context); LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, GL11.GL_FLOAT, variable.normalized, variable.stride, 0); } else { variable.data.getBuffer().rewind(); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.normalized, variable.stride, variable.data.getBuffer()); } } private static void updateShaderAttribute(final ShaderVariablePointerFloatMatrix variable, final ShaderObjectsStateRecord record, final boolean useVBO) { final int size = variable.size; final int length = variable.data.getBuffer().capacity() / size; final RenderContext context = ContextManager.getCurrentContext(); int pos = 0; enableVertexAttribute(variable, record); for (int i = 0; i < size; i++) { pos = (i * length); if (useVBO) { final int vboId = LwjglRenderer.setupVBO(variable.data, context); LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID + i, size, GL11.GL_FLOAT, variable.normalized, 0, pos); } else { variable.data.getBuffer().limit(pos + length - 1); variable.data.getBuffer().position(pos); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID + i, size, variable.normalized, 0, variable.data.getBuffer()); } } } private static void updateShaderAttribute(final ShaderVariablePointerByte variable, final ShaderObjectsStateRecord record, final boolean useVBO) { enableVertexAttribute(variable, record); if (useVBO) { final RenderContext context = ContextManager.getCurrentContext(); final int vboId = LwjglRenderer.setupVBO(variable.data, context); LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned ? GL11.GL_UNSIGNED_BYTE : GL11.GL_BYTE, variable.normalized, variable.stride, 0); } else { variable.data.getBuffer().rewind(); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned, variable.normalized, variable.stride, variable.data.getBuffer()); } } private static void updateShaderAttribute(final ShaderVariablePointerInt variable, final ShaderObjectsStateRecord record, final boolean useVBO) { enableVertexAttribute(variable, record); if (useVBO) { final RenderContext context = ContextManager.getCurrentContext(); final int vboId = LwjglRenderer.setupVBO(variable.data, context); LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned ? GL11.GL_UNSIGNED_INT : GL11.GL_INT, variable.normalized, variable.stride, 0); } else { variable.data.getBuffer().rewind(); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned, variable.normalized, variable.stride, variable.data.getBuffer()); } } private static void updateShaderAttribute(final ShaderVariablePointerShort variable, final ShaderObjectsStateRecord record, final boolean useVBO) { enableVertexAttribute(variable, record); if (useVBO) { final RenderContext context = ContextManager.getCurrentContext(); final int vboId = LwjglRenderer.setupVBO(variable.data, context); LwjglRendererUtil.setBoundVBO(context.getRendererRecord(), vboId); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned ? GL11.GL_UNSIGNED_SHORT : GL11.GL_SHORT, variable.normalized, variable.stride, 0); } else { variable.data.getBuffer().rewind(); ARBVertexProgram.glVertexAttribPointerARB(variable.variableID, variable.size, variable.unsigned, variable.normalized, variable.stride, variable.data.getBuffer()); } } }