diff options
Diffstat (limited to 'engine/src/core/com/jme3/material/Technique.java')
-rw-r--r-- | engine/src/core/com/jme3/material/Technique.java | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/material/Technique.java b/engine/src/core/com/jme3/material/Technique.java new file mode 100644 index 0000000..5ae20a5 --- /dev/null +++ b/engine/src/core/com/jme3/material/Technique.java @@ -0,0 +1,261 @@ +/* + * 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<Uniform> 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<Uniform>(); + 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. + * <p> + * 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<Uniform> 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) { + needReload = defines.set(defineName, type, value); + } + 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) { + needReload = defines.remove(defineName); + } + 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. + * <p> + * 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<MatParam> 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(); + } +} |