diff --git a/engine/src/core/com/jme3/shader/Shader.java b/engine/src/core/com/jme3/shader/Shader.java index 1469c045f..d0efe81b7 100644 --- a/engine/src/core/com/jme3/shader/Shader.java +++ b/engine/src/core/com/jme3/shader/Shader.java @@ -1,334 +1,366 @@ -/* - * Copyright (c) 2009-2012 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.shader; - -import com.jme3.renderer.Renderer; -import com.jme3.scene.VertexBuffer; -import com.jme3.util.IntMap; -import com.jme3.util.IntMap.Entry; -import com.jme3.util.ListMap; -import com.jme3.util.NativeObject; -import java.util.ArrayList; -import java.util.Collection; - -public final class Shader extends NativeObject { - - /** - * A list of all shader sources currently attached. - */ - private ArrayList shaderSourceList; - - /** - * Maps uniform name to the uniform variable. - */ - private ListMap uniforms; - - /** - * Maps attribute name to the location of the attribute in the shader. - */ - private IntMap attribs; - - /** - * Type of shader. The shader will control the pipeline of it's type. - */ - public static enum ShaderType { - /** - * Control fragment rasterization. (e.g color of pixel). - */ - Fragment, - - /** - * Control vertex processing. (e.g transform of model to clip space) - */ - Vertex, - - /** - * Control geometry assembly. (e.g compile a triangle list from input data) - */ - Geometry; - } - - /** - * Shader source describes a shader object in OpenGL. Each shader source - * is assigned a certain pipeline which it controls (described by it's type). - */ - public static class ShaderSource extends NativeObject { - - ShaderType sourceType; - String language; - String name; - String source; - String defines; - - public ShaderSource(ShaderType type){ - super(); - this.sourceType = type; - if (type == null) { - throw new IllegalArgumentException("The shader type must be specified"); - } - } - - protected ShaderSource(ShaderSource ss){ - super(ss.id); - // No data needs to be copied. - // (This is a destructable clone) - } - - public ShaderSource(){ - super(); - } - - public void setName(String name){ - this.name = name; - } - - public String getName(){ - return name; - } - - public ShaderType getType() { - return sourceType; - } - - public String getLanguage() { - return language; - } - - public void setLanguage(String language) { - if (language == null) { - throw new IllegalArgumentException("Shader language cannot be null"); - } - this.language = language; - setUpdateNeeded(); - } - - public void setSource(String source){ - if (source == null) { - throw new IllegalArgumentException("Shader source cannot be null"); - } - this.source = source; - setUpdateNeeded(); - } - - public void setDefines(String defines){ - if (defines == null) { - throw new IllegalArgumentException("Shader defines cannot be null"); - } - this.defines = defines; - setUpdateNeeded(); - } - - public String getSource(){ - return source; - } - - public String getDefines(){ - return defines; - } - - @Override - public long getUniqueId() { - return ((long)OBJTYPE_SHADERSOURCE << 32) | ((long)id); - } - - @Override - public String toString(){ - String nameTxt = ""; - if (name != null) - nameTxt = "name="+name+", "; - if (defines != null) - nameTxt += "defines, "; - - - return getClass().getSimpleName() + "["+nameTxt+"type=" - + sourceType.name()+", language=" + language + "]"; - } - - public void resetObject(){ - id = -1; - setUpdateNeeded(); - } - - public void deleteObject(Object rendererObject){ - ((Renderer)rendererObject).deleteShaderSource(ShaderSource.this); - } - - public NativeObject createDestructableClone(){ - return new ShaderSource(ShaderSource.this); - } - } - - /** - * Initializes the shader for use, must be called after the - * constructor without arguments is used. - */ - public void initialize() { - shaderSourceList = new ArrayList(); - uniforms = new ListMap(); - attribs = new IntMap(); - } - - /** - * Creates a new shader, {@link #initialize() } must be called - * after this constructor for the shader to be usable. - */ - public Shader(){ - super(); - } - - /** - * Do not use this constructor. Used for destructable clones only. - */ - protected Shader(Shader s){ - super(s.id); - - // Shader sources cannot be shared, therefore they must - // be destroyed together with the parent shader. - shaderSourceList = new ArrayList(); - for (ShaderSource source : s.shaderSourceList){ - shaderSourceList.add( (ShaderSource)source.createDestructableClone() ); - } - } - - /** - * Adds source code to a certain pipeline. - * - * @param type The pipeline to control - * @param source The shader source code (in GLSL). - * @param defines Preprocessor defines (placed at the beginning of the shader) - * @param language The shader source language, currently accepted is GLSL### - * where ### is the version, e.g. GLSL100 = GLSL 1.0, GLSL330 = GLSL 3.3, etc. - */ - public void addSource(ShaderType type, String name, String source, String defines, String language){ - ShaderSource shaderSource = new ShaderSource(type); - shaderSource.setSource(source); - shaderSource.setName(name); - shaderSource.setLanguage(language); - if (defines != null) { - shaderSource.setDefines(defines); - } - shaderSourceList.add(shaderSource); - setUpdateNeeded(); - } - - public Uniform getUniform(String name){ - Uniform uniform = uniforms.get(name); - if (uniform == null){ - uniform = new Uniform(); - uniform.name = name; - uniforms.put(name, uniform); - } - return uniform; - } - - public void removeUniform(String name){ - uniforms.remove(name); - } - - public Attribute getAttribute(VertexBuffer.Type attribType){ - int ordinal = attribType.ordinal(); - Attribute attrib = attribs.get(ordinal); - if (attrib == null){ - attrib = new Attribute(); - attrib.name = attribType.name(); - attribs.put(ordinal, attrib); - } - return attrib; - } - - public ListMap getUniformMap(){ - return uniforms; - } - - public Collection getSources(){ - return shaderSourceList; - } - - @Override - public String toString() { - return getClass().getSimpleName() + - "[numSources=" + shaderSourceList.size() + - ", numUniforms=" + uniforms.size() + - ", shaderSources=" + getSources() + "]"; - } - - /** - * Usually called when the shader itself changes or during any - * time when the variable locations need to be refreshed. - */ - public void resetLocations() { - if (uniforms != null) { - // NOTE: Shader sources will be reset seperately from the shader itself. - for (Uniform uniform : uniforms.values()) { - uniform.reset(); // fixes issue with re-initialization - } - } - if (attribs != null) { - for (Entry entry : attribs) { - entry.getValue().location = ShaderVariable.LOC_UNKNOWN; - } - } - } - - @Override - public void setUpdateNeeded(){ - super.setUpdateNeeded(); - resetLocations(); - } - - /** - * Called by the object manager to reset all object IDs. This causes - * the shader to be reuploaded to the GPU incase the display was restarted. - */ - @Override - public void resetObject() { - this.id = -1; - for (ShaderSource source : shaderSourceList){ - source.resetObject(); - } - setUpdateNeeded(); - } - - @Override - public void deleteObject(Object rendererObject) { - ((Renderer)rendererObject).deleteShader(this); - } - - public NativeObject createDestructableClone(){ - return new Shader(this); - } - - @Override - public long getUniqueId() { - return ((long)OBJTYPE_SHADER << 32) | ((long)id); - } -} +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.shader; + +import com.jme3.renderer.Renderer; +import com.jme3.scene.VertexBuffer; +import com.jme3.util.IntMap; +import com.jme3.util.IntMap.Entry; +import com.jme3.util.ListMap; +import com.jme3.util.NativeObject; +import java.util.ArrayList; +import java.util.Collection; + +public final class Shader extends NativeObject { + + /** + * A list of all shader sources currently attached. + */ + private ArrayList shaderSourceList; + + /** + * Maps uniform name to the uniform variable. + */ + private ListMap uniforms; + + /** + * Maps attribute name to the location of the attribute in the shader. + */ + private IntMap attribs; + + /** + * Type of shader. The shader will control the pipeline of it's type. + */ + public static enum ShaderType { + /** + * Control fragment rasterization. (e.g color of pixel). + */ + Fragment, + + /** + * Control vertex processing. (e.g transform of model to clip space) + */ + Vertex, + + /** + * Control geometry assembly. (e.g compile a triangle list from input data) + */ + Geometry; + } + + /** + * Shader source describes a shader object in OpenGL. Each shader source + * is assigned a certain pipeline which it controls (described by it's type). + */ + public static class ShaderSource extends NativeObject { + + ShaderType sourceType; + String language; + String name; + String source; + String defines; + + public ShaderSource(ShaderType type){ + super(); + this.sourceType = type; + if (type == null) { + throw new IllegalArgumentException("The shader type must be specified"); + } + } + + protected ShaderSource(ShaderSource ss){ + super(ss.id); + // No data needs to be copied. + // (This is a destructable clone) + } + + public ShaderSource(){ + super(); + } + + public void setName(String name){ + this.name = name; + } + + public String getName(){ + return name; + } + + public ShaderType getType() { + return sourceType; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + if (language == null) { + throw new IllegalArgumentException("Shader language cannot be null"); + } + this.language = language; + setUpdateNeeded(); + } + + public void setSource(String source){ + if (source == null) { + throw new IllegalArgumentException("Shader source cannot be null"); + } + this.source = source; + setUpdateNeeded(); + } + + public void setDefines(String defines){ + if (defines == null) { + throw new IllegalArgumentException("Shader defines cannot be null"); + } + this.defines = defines; + setUpdateNeeded(); + } + + public String getSource(){ + return source; + } + + public String getDefines(){ + return defines; + } + + @Override + public long getUniqueId() { + return ((long)OBJTYPE_SHADERSOURCE << 32) | ((long)id); + } + + @Override + public String toString(){ + String nameTxt = ""; + if (name != null) + nameTxt = "name="+name+", "; + if (defines != null) + nameTxt += "defines, "; + + + return getClass().getSimpleName() + "["+nameTxt+"type=" + + sourceType.name()+", language=" + language + "]"; + } + + public void resetObject(){ + id = -1; + setUpdateNeeded(); + } + + public void deleteObject(Object rendererObject){ + ((Renderer)rendererObject).deleteShaderSource(ShaderSource.this); + } + + public NativeObject createDestructableClone(){ + return new ShaderSource(ShaderSource.this); + } + } + + /** + * Initializes the shader for use, must be called after the + * constructor without arguments is used. + */ + public void initialize() { + shaderSourceList = new ArrayList(); + uniforms = new ListMap(); + attribs = new IntMap(); + } + + /** + * Creates a new shader, {@link #initialize() } must be called + * after this constructor for the shader to be usable. + */ + public Shader(){ + super(); + } + + /** + * Do not use this constructor. Used for destructable clones only. + */ + protected Shader(Shader s){ + super(s.id); + + // Shader sources cannot be shared, therefore they must + // be destroyed together with the parent shader. + shaderSourceList = new ArrayList(); + for (ShaderSource source : s.shaderSourceList){ + shaderSourceList.add( (ShaderSource)source.createDestructableClone() ); + } + } + + /** + * Adds source code to a certain pipeline. + * + * @param type The pipeline to control + * @param source The shader source code (in GLSL). + * @param defines Preprocessor defines (placed at the beginning of the shader) + * @param language The shader source language, currently accepted is GLSL### + * where ### is the version, e.g. GLSL100 = GLSL 1.0, GLSL330 = GLSL 3.3, etc. + */ + public void addSource(ShaderType type, String name, String source, String defines, String language){ + ShaderSource shaderSource = new ShaderSource(type); + shaderSource.setSource(source); + shaderSource.setName(name); + shaderSource.setLanguage(language); + if (defines != null) { + shaderSource.setDefines(defines); + } + shaderSourceList.add(shaderSource); + setUpdateNeeded(); + } + + public Uniform getUniform(String name){ + Uniform uniform = uniforms.get(name); + if (uniform == null){ + uniform = new Uniform(); + uniform.name = name; + uniforms.put(name, uniform); + } + return uniform; + } + + public void removeUniform(String name){ + uniforms.remove(name); + } + + public Attribute getAttribute(VertexBuffer.Type attribType){ + int ordinal = attribType.ordinal(); + Attribute attrib = attribs.get(ordinal); + if (attrib == null){ + attrib = new Attribute(); + attrib.name = attribType.name(); + attribs.put(ordinal, attrib); + } + return attrib; + } + + public ListMap getUniformMap(){ + return uniforms; + } + + public Collection getSources(){ + return shaderSourceList; + } + + @Override + public String toString() { + return getClass().getSimpleName() + + "[numSources=" + shaderSourceList.size() + + ", numUniforms=" + uniforms.size() + + ", shaderSources=" + getSources() + "]"; + } + + /** + * Removes the "set-by-current-material" flag from all uniforms. + * When a uniform is modified after this call, the flag shall + * become "set-by-current-material". + * A call to {@link #resetUniformsNotSetByCurrent() } will reset + * all uniforms that do not have the "set-by-current-material" flag + * to their default value (usually all zeroes or false). + */ + public void clearUniformsSetByCurrentFlag() { + int size = uniforms.size(); + for (int i = 0; i < size; i++) { + Uniform u = uniforms.getValue(i); + u.clearSetByCurrentMaterial(); + } + } + + /** + * Resets all uniforms that do not have the "set-by-current-material" flag + * to their default value (usually all zeroes or false). + * When a uniform is modified, that flag is set, to remove the flag, + * use {@link #clearUniformsSetByCurrent() }. + */ + public void resetUniformsNotSetByCurrent() { + int size = uniforms.size(); + for (int i = 0; i < size; i++) { + Uniform u = uniforms.getValue(i); + if (!u.isSetByCurrentMaterial()) { + u.clearValue(); + } + } + } + + /** + * Usually called when the shader itself changes or during any + * time when the variable locations need to be refreshed. + */ + public void resetLocations() { + if (uniforms != null) { + // NOTE: Shader sources will be reset seperately from the shader itself. + for (Uniform uniform : uniforms.values()) { + uniform.reset(); // fixes issue with re-initialization + } + } + if (attribs != null) { + for (Entry entry : attribs) { + entry.getValue().location = ShaderVariable.LOC_UNKNOWN; + } + } + } + + @Override + public void setUpdateNeeded(){ + super.setUpdateNeeded(); + resetLocations(); + } + + /** + * Called by the object manager to reset all object IDs. This causes + * the shader to be reuploaded to the GPU incase the display was restarted. + */ + @Override + public void resetObject() { + this.id = -1; + for (ShaderSource source : shaderSourceList){ + source.resetObject(); + } + setUpdateNeeded(); + } + + @Override + public void deleteObject(Object rendererObject) { + ((Renderer)rendererObject).deleteShader(this); + } + + public NativeObject createDestructableClone(){ + return new Shader(this); + } + + @Override + public long getUniqueId() { + return ((long)OBJTYPE_SHADER << 32) | ((long)id); + } +}