diff --git a/jme3-core/src/main/java/com/jme3/material/MatParamOverride.java b/jme3-core/src/main/java/com/jme3/material/MatParamOverride.java new file mode 100644 index 000000000..af46eba7e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/material/MatParamOverride.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2009-2016 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.shader.VarType; + +public final class MatParamOverride extends MatParam { + + public MatParamOverride(VarType type, String name, Object value) { + super(type, name, value); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 3fbbfbb2d..59d67f5fe 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -820,7 +820,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { * used for rendering, there won't be any delay since the material has * been already been setup for rendering. * - * @param rm The render manager to preload for + * @param renderManager The render manager to preload for */ public void preload(RenderManager renderManager) { if (technique == null) { @@ -834,7 +834,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { return; } - Shader shader = technique.makeCurrent(renderManager, null, rendererCaps); + Shader shader = technique.makeCurrent(renderManager, null, null, rendererCaps); updateShaderMaterialParameters(renderer, shader); renderManager.getRenderer().setShader(shader); } @@ -938,8 +938,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { // Apply render state updateRenderState(renderManager, renderer, techniqueDef); + // Get world overrides + ArrayList overrides = geometry.getWorldOverrides(); + // Select shader to use - Shader shader = technique.makeCurrent(renderManager, lights, rendererCaps); + Shader shader = technique.makeCurrent(renderManager, overrides, lights, rendererCaps); // Begin tracking which uniforms were changed by material. clearUniformsSetByCurrent(shader); diff --git a/jme3-core/src/main/java/com/jme3/material/Technique.java b/jme3-core/src/main/java/com/jme3/material/Technique.java index a0c3e6f80..ea35283f0 100644 --- a/jme3-core/src/main/java/com/jme3/material/Technique.java +++ b/jme3-core/src/main/java/com/jme3/material/Technique.java @@ -41,7 +41,9 @@ import com.jme3.shader.DefineList; import com.jme3.shader.Shader; import com.jme3.shader.VarType; import com.jme3.util.ListMap; +import java.util.ArrayList; import java.util.EnumSet; +import java.util.List; /** * Represents a technique instance. @@ -85,26 +87,8 @@ public final class Technique { if (defineId == null) { return; } - - if (value == null) { - dynamicDefines.set(defineId, 0); - return; - } - - switch (type) { - case Int: - dynamicDefines.set(defineId, (Integer) value); - break; - case Float: - dynamicDefines.set(defineId, (Float) value); - break; - case Boolean: - dynamicDefines.set(defineId, ((Boolean)value)); - break; - default: - dynamicDefines.set(defineId, 1); - break; - } + + dynamicDefines.set(defineId, type, value); } /** @@ -115,6 +99,7 @@ public final class Technique { */ void notifyTechniqueSwitched() { ListMap paramMap = owner.getParamsMap(); + dynamicDefines.clear(); for (int i = 0; i < paramMap.size(); i++) { MatParam param = paramMap.getValue(i); notifyParamChanged(param.getName(), param.getVarType(), param.getValue()); @@ -131,10 +116,23 @@ public final class Technique { * @param rendererCaps The renderer capabilities which the shader should support. * @return A compatible shader. */ - Shader makeCurrent(RenderManager renderManager, LightList lights, EnumSet rendererCaps) { + Shader makeCurrent(RenderManager renderManager, ArrayList overrides, + LightList lights, EnumSet rendererCaps) { TechniqueDefLogic logic = def.getLogic(); AssetManager assetManager = owner.getMaterialDef().getAssetManager(); - return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, dynamicDefines); + + // TODO: remove allocation + DefineList combinedDefines = def.createDefineList(); + combinedDefines.setAll(dynamicDefines); + + for (MatParamOverride override : overrides) { + Integer defineId = def.getShaderParamDefineId(override.name); + if (defineId != null) { + combinedDefines.set(defineId, override.type, override.value); + } + } + + return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, combinedDefines); } /** diff --git a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java index 43419e543..023f298af 100644 --- a/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java +++ b/jme3-core/src/main/java/com/jme3/material/TechniqueDef.java @@ -330,13 +330,13 @@ public class TechniqueDef implements Savable { } /** - * Get the define ID for a given define name. + * Get the define ID for a given material parameter. * - * @param defineName The define name to lookup + * @param paramName The parameter name to look up * @return The define ID, or null if not found. */ - public Integer getShaderParamDefineId(String defineName) { - return paramToDefineId.get(defineName); + public Integer getShaderParamDefineId(String paramName) { + return paramToDefineId.get(paramName); } diff --git a/jme3-core/src/main/java/com/jme3/scene/Spatial.java b/jme3-core/src/main/java/com/jme3/scene/Spatial.java index 15757eee0..6f77f530d 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Spatial.java +++ b/jme3-core/src/main/java/com/jme3/scene/Spatial.java @@ -38,6 +38,7 @@ import com.jme3.collision.Collidable; import com.jme3.export.*; import com.jme3.light.Light; import com.jme3.light.LightList; +import com.jme3.material.MatParamOverride; import com.jme3.material.Material; import com.jme3.math.*; import com.jme3.renderer.Camera; @@ -424,6 +425,29 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab return worldLights; } + /** + * Get the local material parameter overrides. + * + * @return The list of local material parameter overrides. + */ + public ArrayList getLocalOverrides() { + return null; + } + + /** + * Get the world material parameter overrides. + * + * Note that this list is only updated on a call to + * {@link #updateGeometricState()}. After update, the world overrides list + * will contain the {@link #getParent() parent's} world overrides combined + * with this spatial's {@link #getLocalOverrides() local overrides}. + * + * @return The list of world material parameter overrides. + */ + public ArrayList getWorldOverrides() { + return null; + } + /** * getWorldRotation retrieves the absolute rotation of the * Spatial. diff --git a/jme3-core/src/main/java/com/jme3/shader/DefineList.java b/jme3-core/src/main/java/com/jme3/shader/DefineList.java index a3edbcbe7..d9b5782aa 100644 --- a/jme3-core/src/main/java/com/jme3/shader/DefineList.java +++ b/jme3-core/src/main/java/com/jme3/shader/DefineList.java @@ -31,6 +31,7 @@ */ package com.jme3.shader; +import java.util.Arrays; import java.util.List; /** @@ -41,7 +42,7 @@ import java.util.List; public final class DefineList { public static final int MAX_DEFINES = 64; - + private long hash; private final int[] vals; @@ -76,6 +77,41 @@ public final class DefineList { set(id, val ? 1 : 0); } + public void set(int id, VarType type, Object value) { + if (value == null) { + set(id, 0); + return; + } + + switch (type) { + case Int: + set(id, (Integer) value); + break; + case Float: + set(id, (Float) value); + break; + case Boolean: + set(id, ((Boolean) value)); + break; + default: + set(id, 1); + break; + } + } + + public void setAll(DefineList other) { + for (int i = 0; i < other.vals.length; i++) { + if (other.vals[i] != 0) { + vals[i] = other.vals[i]; + } + } + } + + public void clear() { + hash = 0; + Arrays.fill(vals, 0); + } + public boolean getBoolean(int id) { return vals[id] != 0; }