* Prevent crash when material technique has no world bindings defined. Fixes issue 454

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9129 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Sha..om 13 years ago
parent 230398c45b
commit b53a825d35
  1. 525
      engine/src/core/com/jme3/material/Technique.java

@ -1,262 +1,263 @@
/* /*
* Copyright (c) 2009-2010 jMonkeyEngine * Copyright (c) 2009-2010 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.material; package com.jme3.material;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.shader.*; import com.jme3.shader.*;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* Represents a technique instance. * Represents a technique instance.
*/ */
public class Technique implements Savable { public class Technique implements Savable {
private static final Logger logger = Logger.getLogger(Technique.class.getName()); private static final Logger logger = Logger.getLogger(Technique.class.getName());
private TechniqueDef def; private TechniqueDef def;
private Material owner; private Material owner;
private ArrayList<Uniform> worldBindUniforms; private ArrayList<Uniform> worldBindUniforms;
private DefineList defines; private DefineList defines;
private Shader shader; private Shader shader;
private boolean needReload = true; private boolean needReload = true;
/** /**
* Creates a new technique instance that implements the given * Creates a new technique instance that implements the given
* technique definition. * technique definition.
* *
* @param owner The material that will own this technique * @param owner The material that will own this technique
* @param def The technique definition being implemented. * @param def The technique definition being implemented.
*/ */
public Technique(Material owner, TechniqueDef def) { public Technique(Material owner, TechniqueDef def) {
this.owner = owner; this.owner = owner;
this.def = def; this.def = def;
if (def.isUsingShaders()) { if (def.isUsingShaders()) {
this.worldBindUniforms = new ArrayList<Uniform>(); this.worldBindUniforms = new ArrayList<Uniform>();
this.defines = new DefineList(); this.defines = new DefineList();
} }
} }
/** /**
* Serialization only. Do not use. * Serialization only. Do not use.
*/ */
public Technique() { public Technique() {
} }
/** /**
* Returns the technique definition that is implemented by this technique * Returns the technique definition that is implemented by this technique
* instance. * instance.
* *
* @return the technique definition that is implemented by this technique * @return the technique definition that is implemented by this technique
* instance. * instance.
*/ */
public TechniqueDef getDef() { public TechniqueDef getDef() {
return def; return def;
} }
/** /**
* Returns the shader currently used by this technique instance. * Returns the shader currently used by this technique instance.
* <p> * <p>
* Shaders are typically loaded dynamically when the technique is first * Shaders are typically loaded dynamically when the technique is first
* used, therefore, this variable will most likely be null most of the time. * used, therefore, this variable will most likely be null most of the time.
* *
* @return the shader currently used by this technique instance. * @return the shader currently used by this technique instance.
*/ */
public Shader getShader() { public Shader getShader() {
return shader; return shader;
} }
/** /**
* Returns a list of uniforms that implements the world parameters * Returns a list of uniforms that implements the world parameters
* that were requested by the material definition. * that were requested by the material definition.
* *
* @return a list of uniforms implementing the world parameters. * @return a list of uniforms implementing the world parameters.
*/ */
public List<Uniform> getWorldBindUniforms() { public List<Uniform> getWorldBindUniforms() {
return worldBindUniforms; return worldBindUniforms;
} }
/** /**
* Called by the material to tell the technique a parameter was modified * Called by the material to tell the technique a parameter was modified
*/ */
void notifySetParam(String paramName, VarType type, Object value) { void notifySetParam(String paramName, VarType type, Object value) {
String defineName = def.getShaderParamDefine(paramName); String defineName = def.getShaderParamDefine(paramName);
if (defineName != null) { if (defineName != null) {
defines.set(defineName, type, value); defines.set(defineName, type, value);
needReload = true; needReload = true;
} }
if (shader != null) { if (shader != null) {
updateUniformParam(paramName, type, value); updateUniformParam(paramName, type, value);
} }
} }
/** /**
* Called by the material to tell the technique a parameter was cleared * Called by the material to tell the technique a parameter was cleared
*/ */
void notifyClearParam(String paramName) { void notifyClearParam(String paramName) {
String defineName = def.getShaderParamDefine(paramName); String defineName = def.getShaderParamDefine(paramName);
if (defineName != null) { if (defineName != null) {
defines.remove(defineName); defines.remove(defineName);
needReload = true; needReload = true;
} }
if (shader != null) { if (shader != null) {
if (!paramName.startsWith("m_")) { if (!paramName.startsWith("m_")) {
paramName = "m_" + paramName; paramName = "m_" + paramName;
} }
shader.removeUniform(paramName); shader.removeUniform(paramName);
} }
} }
void updateUniformParam(String paramName, VarType type, Object value, boolean ifNotOwner) { void updateUniformParam(String paramName, VarType type, Object value, boolean ifNotOwner) {
Uniform u = shader.getUniform(paramName); Uniform u = shader.getUniform(paramName);
// if (ifNotOwner && u.getLastChanger() == owner) // if (ifNotOwner && u.getLastChanger() == owner)
// return; // return;
switch (type) { switch (type) {
case Texture2D: // fall intentional case Texture2D: // fall intentional
case Texture3D: case Texture3D:
case TextureArray: case TextureArray:
case TextureCubeMap: case TextureCubeMap:
case Int: case Int:
u.setValue(VarType.Int, value); u.setValue(VarType.Int, value);
break; break;
default: default:
u.setValue(type, value); u.setValue(type, value);
break; break;
} }
// u.setLastChanger(owner); // u.setLastChanger(owner);
} }
void updateUniformParam(String paramName, VarType type, Object value) { void updateUniformParam(String paramName, VarType type, Object value) {
updateUniformParam(paramName, type, value, false); updateUniformParam(paramName, type, value, false);
} }
/** /**
* Returns true if the technique must be reloaded. * Returns true if the technique must be reloaded.
* <p> * <p>
* If a technique needs to reload, then the {@link Material} should * If a technique needs to reload, then the {@link Material} should
* call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this * call {@link #makeCurrent(com.jme3.asset.AssetManager) } on this
* technique. * technique.
* *
* @return true if the technique must be reloaded. * @return true if the technique must be reloaded.
*/ */
public boolean isNeedReload() { public boolean isNeedReload() {
return needReload; return needReload;
} }
/** /**
* Prepares the technique for use by loading the shader and setting * Prepares the technique for use by loading the shader and setting
* the proper defines based on material parameters. * the proper defines based on material parameters.
* *
* @param assetManager The asset manager to use for loading shaders. * @param assetManager The asset manager to use for loading shaders.
*/ */
public void makeCurrent(AssetManager assetManager) { public void makeCurrent(AssetManager assetManager) {
// check if reload is needed.. // check if reload is needed..
if (def.isUsingShaders()) { if (def.isUsingShaders()) {
DefineList newDefines = new DefineList(); DefineList newDefines = new DefineList();
Collection<MatParam> params = owner.getParams(); Collection<MatParam> params = owner.getParams();
for (MatParam param : params) { for (MatParam param : params) {
String defineName = def.getShaderParamDefine(param.getName()); String defineName = def.getShaderParamDefine(param.getName());
if (defineName != null) { if (defineName != null) {
newDefines.set(defineName, param.getVarType(), param.getValue()); newDefines.set(defineName, param.getVarType(), param.getValue());
} }
} }
if (!needReload && defines.getCompiled().equals(newDefines.getCompiled())) { if (!needReload && defines.getCompiled().equals(newDefines.getCompiled())) {
newDefines = null; newDefines = null;
// defines have not been changed.. // defines have not been changed..
} else { } else {
defines.clear(); defines.clear();
defines.addFrom(newDefines); defines.addFrom(newDefines);
// defines changed, recompile needed // defines changed, recompile needed
loadShader(assetManager); loadShader(assetManager);
} }
} }
} }
private void loadShader(AssetManager manager) { private void loadShader(AssetManager manager) {
// recompute define list // recompute define list
DefineList allDefines = new DefineList(); DefineList allDefines = new DefineList();
allDefines.addFrom(def.getShaderPresetDefines()); allDefines.addFrom(def.getShaderPresetDefines());
allDefines.addFrom(defines); allDefines.addFrom(defines);
ShaderKey key = new ShaderKey(def.getVertexShaderName(), ShaderKey key = new ShaderKey(def.getVertexShaderName(),
def.getFragmentShaderName(), def.getFragmentShaderName(),
allDefines, allDefines,
def.getShaderLanguage()); def.getShaderLanguage());
shader = manager.loadShader(key); shader = manager.loadShader(key);
if (shader == null) { if (shader == null) {
logger.warning("Failed to reload shader!"); logger.warning("Failed to reload shader!");
return; return;
} }
// refresh the uniform links // refresh the uniform links
//owner.updateUniformLinks(); //owner.updateUniformLinks();
// register the world bound uniforms // register the world bound uniforms
worldBindUniforms.clear(); worldBindUniforms.clear();
for (UniformBinding binding : def.getWorldBindings()) { if (def.getWorldBindings() != null) {
Uniform uniform = shader.getUniform("g_" + binding.name()); for (UniformBinding binding : def.getWorldBindings()) {
uniform.setBinding(binding); Uniform uniform = shader.getUniform("g_" + binding.name());
if (uniform != null) { uniform.setBinding(binding);
worldBindUniforms.add(uniform); if (uniform != null) {
worldBindUniforms.add(uniform);
} }
} }
}
needReload = false;
} needReload = false;
}
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); public void write(JmeExporter ex) throws IOException {
oc.write(def, "def", null); OutputCapsule oc = ex.getCapsule(this);
// TODO: oc.write(def, "def", null);
// oc.write(owner, "owner", null); // TODO:
oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null); // oc.write(owner, "owner", null);
oc.write(defines, "defines", null); oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null);
oc.write(shader, "shader", null); oc.write(defines, "defines", null);
} oc.write(shader, "shader", null);
}
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this); public void read(JmeImporter im) throws IOException {
def = (TechniqueDef) ic.readSavable("def", null); InputCapsule ic = im.getCapsule(this);
worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null); def = (TechniqueDef) ic.readSavable("def", null);
defines = (DefineList) ic.readSavable("defines", null); worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null);
shader = (Shader) ic.readSavable("shader", null); defines = (DefineList) ic.readSavable("defines", null);
//if (shader != null) shader = (Shader) ic.readSavable("shader", null);
// owner.updateUniformLinks(); //if (shader != null)
} // owner.updateUniformLinks();
} }
}

Loading…
Cancel
Save