diff --git a/engine/src/core/com/jme3/material/Technique.java b/engine/src/core/com/jme3/material/Technique.java index 74907c970..b4ce59aaf 100644 --- a/engine/src/core/com/jme3/material/Technique.java +++ b/engine/src/core/com/jme3/material/Technique.java @@ -1,262 +1,263 @@ -/* - * Copyright (c) 2009-2010 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.material; - -import com.jme3.asset.AssetManager; -import com.jme3.export.*; -import com.jme3.shader.*; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.logging.Logger; - -/** - * Represents a technique instance. - */ -public class Technique implements Savable { - - private static final Logger logger = Logger.getLogger(Technique.class.getName()); - private TechniqueDef def; - private Material owner; - private ArrayList worldBindUniforms; - private DefineList defines; - private Shader shader; - private boolean needReload = true; - - /** - * Creates a new technique instance that implements the given - * technique definition. - * - * @param owner The material that will own this technique - * @param def The technique definition being implemented. - */ - public Technique(Material owner, TechniqueDef def) { - this.owner = owner; - this.def = def; - if (def.isUsingShaders()) { - this.worldBindUniforms = new ArrayList(); - this.defines = new DefineList(); - } - } - - /** - * Serialization only. Do not use. - */ - public Technique() { - } - - /** - * Returns the technique definition that is implemented by this technique - * instance. - * - * @return the technique definition that is implemented by this technique - * instance. - */ - public TechniqueDef getDef() { - return def; - } - - /** - * Returns the shader currently used by this technique instance. - *

- * Shaders are typically loaded dynamically when the technique is first - * used, therefore, this variable will most likely be null most of the time. - * - * @return the shader currently used by this technique instance. - */ - public Shader getShader() { - return shader; - } - - /** - * Returns a list of uniforms that implements the world parameters - * that were requested by the material definition. - * - * @return a list of uniforms implementing the world parameters. - */ - public List getWorldBindUniforms() { - return worldBindUniforms; - } - - /** - * Called by the material to tell the technique a parameter was modified - */ - void notifySetParam(String paramName, VarType type, Object value) { - String defineName = def.getShaderParamDefine(paramName); - if (defineName != null) { - defines.set(defineName, type, value); - needReload = true; - } - if (shader != null) { - updateUniformParam(paramName, type, value); - } - } - - /** - * Called by the material to tell the technique a parameter was cleared - */ - void notifyClearParam(String paramName) { - String defineName = def.getShaderParamDefine(paramName); - if (defineName != null) { - defines.remove(defineName); - needReload = true; - } - if (shader != null) { - if (!paramName.startsWith("m_")) { - paramName = "m_" + paramName; - } - shader.removeUniform(paramName); - } - } - - void updateUniformParam(String paramName, VarType type, Object value, boolean ifNotOwner) { - Uniform u = shader.getUniform(paramName); - -// if (ifNotOwner && u.getLastChanger() == owner) -// return; - - switch (type) { - case Texture2D: // fall intentional - case Texture3D: - case TextureArray: - case TextureCubeMap: - case Int: - u.setValue(VarType.Int, value); - break; - default: - u.setValue(type, value); - break; - } -// u.setLastChanger(owner); - } - - void updateUniformParam(String paramName, VarType type, Object value) { - updateUniformParam(paramName, type, value, false); - } - - /** - * Returns true if the technique must be reloaded. - *

- * If a technique needs to reload, then the {@link Material} should - * call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this - * technique. - * - * @return true if the technique must be reloaded. - */ - public boolean isNeedReload() { - return needReload; - } - - /** - * Prepares the technique for use by loading the shader and setting - * the proper defines based on material parameters. - * - * @param assetManager The asset manager to use for loading shaders. - */ - public void makeCurrent(AssetManager assetManager) { - // check if reload is needed.. - if (def.isUsingShaders()) { - DefineList newDefines = new DefineList(); - Collection params = owner.getParams(); - for (MatParam param : params) { - String defineName = def.getShaderParamDefine(param.getName()); - if (defineName != null) { - newDefines.set(defineName, param.getVarType(), param.getValue()); - } - } - - if (!needReload && defines.getCompiled().equals(newDefines.getCompiled())) { - newDefines = null; - // defines have not been changed.. - } else { - defines.clear(); - defines.addFrom(newDefines); - // defines changed, recompile needed - loadShader(assetManager); - } - } - } - - private void loadShader(AssetManager manager) { - // recompute define list - DefineList allDefines = new DefineList(); - allDefines.addFrom(def.getShaderPresetDefines()); - allDefines.addFrom(defines); - - ShaderKey key = new ShaderKey(def.getVertexShaderName(), - def.getFragmentShaderName(), - allDefines, - def.getShaderLanguage()); - shader = manager.loadShader(key); - if (shader == null) { - logger.warning("Failed to reload shader!"); - return; - } - - // refresh the uniform links - //owner.updateUniformLinks(); - - // register the world bound uniforms - worldBindUniforms.clear(); - for (UniformBinding binding : def.getWorldBindings()) { - Uniform uniform = shader.getUniform("g_" + binding.name()); - uniform.setBinding(binding); - if (uniform != null) { - worldBindUniforms.add(uniform); - - } - } - - needReload = false; - } - - public void write(JmeExporter ex) throws IOException { - OutputCapsule oc = ex.getCapsule(this); - oc.write(def, "def", null); - // TODO: - // oc.write(owner, "owner", null); - oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null); - oc.write(defines, "defines", null); - oc.write(shader, "shader", null); - } - - public void read(JmeImporter im) throws IOException { - InputCapsule ic = im.getCapsule(this); - def = (TechniqueDef) ic.readSavable("def", null); - worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null); - defines = (DefineList) ic.readSavable("defines", null); - shader = (Shader) ic.readSavable("shader", null); - //if (shader != null) - // owner.updateUniformLinks(); - } -} +/* + * Copyright (c) 2009-2010 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.material; + +import com.jme3.asset.AssetManager; +import com.jme3.export.*; +import com.jme3.shader.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Logger; + +/** + * Represents a technique instance. + */ +public class Technique implements Savable { + + private static final Logger logger = Logger.getLogger(Technique.class.getName()); + private TechniqueDef def; + private Material owner; + private ArrayList worldBindUniforms; + private DefineList defines; + private Shader shader; + private boolean needReload = true; + + /** + * Creates a new technique instance that implements the given + * technique definition. + * + * @param owner The material that will own this technique + * @param def The technique definition being implemented. + */ + public Technique(Material owner, TechniqueDef def) { + this.owner = owner; + this.def = def; + if (def.isUsingShaders()) { + this.worldBindUniforms = new ArrayList(); + this.defines = new DefineList(); + } + } + + /** + * Serialization only. Do not use. + */ + public Technique() { + } + + /** + * Returns the technique definition that is implemented by this technique + * instance. + * + * @return the technique definition that is implemented by this technique + * instance. + */ + public TechniqueDef getDef() { + return def; + } + + /** + * Returns the shader currently used by this technique instance. + *

+ * Shaders are typically loaded dynamically when the technique is first + * used, therefore, this variable will most likely be null most of the time. + * + * @return the shader currently used by this technique instance. + */ + public Shader getShader() { + return shader; + } + + /** + * Returns a list of uniforms that implements the world parameters + * that were requested by the material definition. + * + * @return a list of uniforms implementing the world parameters. + */ + public List getWorldBindUniforms() { + return worldBindUniforms; + } + + /** + * Called by the material to tell the technique a parameter was modified + */ + void notifySetParam(String paramName, VarType type, Object value) { + String defineName = def.getShaderParamDefine(paramName); + if (defineName != null) { + defines.set(defineName, type, value); + needReload = true; + } + if (shader != null) { + updateUniformParam(paramName, type, value); + } + } + + /** + * Called by the material to tell the technique a parameter was cleared + */ + void notifyClearParam(String paramName) { + String defineName = def.getShaderParamDefine(paramName); + if (defineName != null) { + defines.remove(defineName); + needReload = true; + } + if (shader != null) { + if (!paramName.startsWith("m_")) { + paramName = "m_" + paramName; + } + shader.removeUniform(paramName); + } + } + + void updateUniformParam(String paramName, VarType type, Object value, boolean ifNotOwner) { + Uniform u = shader.getUniform(paramName); + +// if (ifNotOwner && u.getLastChanger() == owner) +// return; + + switch (type) { + case Texture2D: // fall intentional + case Texture3D: + case TextureArray: + case TextureCubeMap: + case Int: + u.setValue(VarType.Int, value); + break; + default: + u.setValue(type, value); + break; + } +// u.setLastChanger(owner); + } + + void updateUniformParam(String paramName, VarType type, Object value) { + updateUniformParam(paramName, type, value, false); + } + + /** + * Returns true if the technique must be reloaded. + *

+ * If a technique needs to reload, then the {@link Material} should + * call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this + * technique. + * + * @return true if the technique must be reloaded. + */ + public boolean isNeedReload() { + return needReload; + } + + /** + * Prepares the technique for use by loading the shader and setting + * the proper defines based on material parameters. + * + * @param assetManager The asset manager to use for loading shaders. + */ + public void makeCurrent(AssetManager assetManager) { + // check if reload is needed.. + if (def.isUsingShaders()) { + DefineList newDefines = new DefineList(); + Collection params = owner.getParams(); + for (MatParam param : params) { + String defineName = def.getShaderParamDefine(param.getName()); + if (defineName != null) { + newDefines.set(defineName, param.getVarType(), param.getValue()); + } + } + + if (!needReload && defines.getCompiled().equals(newDefines.getCompiled())) { + newDefines = null; + // defines have not been changed.. + } else { + defines.clear(); + defines.addFrom(newDefines); + // defines changed, recompile needed + loadShader(assetManager); + } + } + } + + private void loadShader(AssetManager manager) { + // recompute define list + DefineList allDefines = new DefineList(); + allDefines.addFrom(def.getShaderPresetDefines()); + allDefines.addFrom(defines); + + ShaderKey key = new ShaderKey(def.getVertexShaderName(), + def.getFragmentShaderName(), + allDefines, + def.getShaderLanguage()); + shader = manager.loadShader(key); + if (shader == null) { + logger.warning("Failed to reload shader!"); + return; + } + + // refresh the uniform links + //owner.updateUniformLinks(); + + // register the world bound uniforms + worldBindUniforms.clear(); + if (def.getWorldBindings() != null) { + for (UniformBinding binding : def.getWorldBindings()) { + Uniform uniform = shader.getUniform("g_" + binding.name()); + uniform.setBinding(binding); + if (uniform != null) { + worldBindUniforms.add(uniform); + } + } + } + + needReload = false; + } + + public void write(JmeExporter ex) throws IOException { + OutputCapsule oc = ex.getCapsule(this); + oc.write(def, "def", null); + // TODO: + // oc.write(owner, "owner", null); + oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null); + oc.write(defines, "defines", null); + oc.write(shader, "shader", null); + } + + public void read(JmeImporter im) throws IOException { + InputCapsule ic = im.getCapsule(this); + def = (TechniqueDef) ic.readSavable("def", null); + worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null); + defines = (DefineList) ic.readSavable("defines", null); + shader = (Shader) ic.readSavable("shader", null); + //if (shader != null) + // owner.updateUniformLinks(); + } +}