Commit patch from abies that drastically reduce the garbage creation when switching techniques. It also reduce grabage collection for the AbdtractShadowRenderer.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10497 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
0186a20983
commit
723e3c0e30
@ -1,261 +1,260 @@
|
||||
/*
|
||||
* 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.material;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.renderer.Caps;
|
||||
import com.jme3.shader.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
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.
|
||||
* Specify <code>null</code> for value if the param is to be cleared.
|
||||
*/
|
||||
void notifyParamChanged(String paramName, VarType type, Object value) {
|
||||
// Check if there's a define binding associated with this
|
||||
// parameter.
|
||||
String defineName = def.getShaderParamDefine(paramName);
|
||||
if (defineName != null) {
|
||||
// There is a define. Change it on the define list.
|
||||
// The "needReload" variable will determine
|
||||
// if the shader will be reloaded when the material
|
||||
// is rendered.
|
||||
|
||||
if (value == null) {
|
||||
// Clear the define.
|
||||
needReload = defines.remove(defineName) || needReload;
|
||||
} else {
|
||||
// Set the define.
|
||||
needReload = defines.set(defineName, type, value) || needReload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateUniformParam(String paramName, VarType type, Object value) {
|
||||
if (paramName == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
Uniform u = shader.getUniform(paramName);
|
||||
switch (type) {
|
||||
case TextureBuffer:
|
||||
case Texture2D: // fall intentional
|
||||
case Texture3D:
|
||||
case TextureArray:
|
||||
case TextureCubeMap:
|
||||
case Int:
|
||||
u.setValue(VarType.Int, value);
|
||||
break;
|
||||
default:
|
||||
u.setValue(type, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, boolean techniqueSwitched, EnumSet<Caps> rendererCaps) {
|
||||
if (!def.isUsingShaders()) {
|
||||
// No shaders are used, no processing is neccessary.
|
||||
return;
|
||||
}
|
||||
|
||||
if (techniqueSwitched) {
|
||||
// If the technique was switched, check if the define list changed
|
||||
// based on material parameters.
|
||||
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 (!defines.getCompiled().equals(newDefines.getCompiled())) {
|
||||
// Defines were changed, update define list
|
||||
defines.clear();
|
||||
defines.addFrom(newDefines);
|
||||
needReload = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needReload) {
|
||||
loadShader(assetManager,rendererCaps);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
|
||||
|
||||
if (getDef().isUsingShaderNodes()) {
|
||||
shader = manager.getShaderGenerator(rendererCaps).generateShader(this);
|
||||
} else {
|
||||
ShaderKey key = new ShaderKey(def.getVertexShaderName(),
|
||||
def.getFragmentShaderName(),
|
||||
getAllDefines(),
|
||||
def.getVertexShaderLanguage(),
|
||||
def.getFragmentShaderLanguage());
|
||||
shader = manager.loadShader(key);
|
||||
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the define list
|
||||
* @return the complete define list
|
||||
*/
|
||||
public DefineList getAllDefines() {
|
||||
DefineList allDefines = new DefineList();
|
||||
allDefines.addFrom(def.getShaderPresetDefines());
|
||||
allDefines.addFrom(defines);
|
||||
return allDefines;
|
||||
}
|
||||
|
||||
/*
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(def, "def", 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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
/*
|
||||
* 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.material;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.renderer.Caps;
|
||||
import com.jme3.shader.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
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.
|
||||
* Specify <code>null</code> for value if the param is to be cleared.
|
||||
*/
|
||||
void notifyParamChanged(String paramName, VarType type, Object value) {
|
||||
// Check if there's a define binding associated with this
|
||||
// parameter.
|
||||
String defineName = def.getShaderParamDefine(paramName);
|
||||
if (defineName != null) {
|
||||
// There is a define. Change it on the define list.
|
||||
// The "needReload" variable will determine
|
||||
// if the shader will be reloaded when the material
|
||||
// is rendered.
|
||||
|
||||
if (value == null) {
|
||||
// Clear the define.
|
||||
needReload = defines.remove(defineName) || needReload;
|
||||
} else {
|
||||
// Set the define.
|
||||
needReload = defines.set(defineName, type, value) || needReload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateUniformParam(String paramName, VarType type, Object value) {
|
||||
if (paramName == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
Uniform u = shader.getUniform(paramName);
|
||||
switch (type) {
|
||||
case TextureBuffer:
|
||||
case Texture2D: // fall intentional
|
||||
case Texture3D:
|
||||
case TextureArray:
|
||||
case TextureCubeMap:
|
||||
case Int:
|
||||
u.setValue(VarType.Int, value);
|
||||
break;
|
||||
default:
|
||||
u.setValue(type, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, boolean techniqueSwitched, EnumSet<Caps> rendererCaps) {
|
||||
if (!def.isUsingShaders()) {
|
||||
// No shaders are used, no processing is neccessary.
|
||||
return;
|
||||
}
|
||||
|
||||
if (techniqueSwitched) {
|
||||
// If the technique was switched, check if the define list changed
|
||||
// based on material parameters.
|
||||
|
||||
Collection<MatParam> params = owner.getParams();
|
||||
|
||||
if (!defines.equalsParams(params,def)) {
|
||||
// Defines were changed, update define list
|
||||
defines.clear();
|
||||
for (MatParam param : params) {
|
||||
String defineName = def.getShaderParamDefine(param.getName());
|
||||
if (defineName != null) {
|
||||
defines.set(defineName, param.getVarType(), param.getValue());
|
||||
}
|
||||
}
|
||||
needReload = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needReload) {
|
||||
loadShader(assetManager,rendererCaps);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
|
||||
|
||||
if (getDef().isUsingShaderNodes()) {
|
||||
shader = manager.getShaderGenerator(rendererCaps).generateShader(this);
|
||||
} else {
|
||||
ShaderKey key = new ShaderKey(def.getVertexShaderName(),
|
||||
def.getFragmentShaderName(),
|
||||
getAllDefines(),
|
||||
def.getVertexShaderLanguage(),
|
||||
def.getFragmentShaderLanguage());
|
||||
shader = manager.loadShader(key);
|
||||
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the define list
|
||||
* @return the complete define list
|
||||
*/
|
||||
public DefineList getAllDefines() {
|
||||
DefineList allDefines = new DefineList();
|
||||
allDefines.addFrom(def.getShaderPresetDefines());
|
||||
allDefines.addFrom(defines);
|
||||
return allDefines;
|
||||
}
|
||||
|
||||
/*
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(def, "def", 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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
@ -1,203 +1,263 @@
|
||||
/*
|
||||
* 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.export.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class DefineList implements Savable, Cloneable {
|
||||
|
||||
private static final String ONE = "1";
|
||||
|
||||
private TreeMap<String, String> defines = new TreeMap<String, String>();
|
||||
private String compiled = null;
|
||||
private int cachedHashCode = 0;
|
||||
|
||||
public void write(JmeExporter ex) throws IOException{
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
|
||||
String[] keys = new String[defines.size()];
|
||||
String[] vals = new String[defines.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String> define : defines.entrySet()){
|
||||
keys[i] = define.getKey();
|
||||
vals[i] = define.getValue();
|
||||
i++;
|
||||
}
|
||||
|
||||
oc.write(keys, "keys", null);
|
||||
oc.write(vals, "vals", null);
|
||||
}
|
||||
|
||||
public void read(JmeImporter im) throws IOException{
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
|
||||
String[] keys = ic.readStringArray("keys", null);
|
||||
String[] vals = ic.readStringArray("vals", null);
|
||||
for (int i = 0; i < keys.length; i++){
|
||||
defines.put(keys[i], vals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
defines.clear();
|
||||
compiled = "";
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
public String get(String key){
|
||||
return defines.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefineList clone() {
|
||||
try {
|
||||
DefineList clone = (DefineList) super.clone();
|
||||
clone.cachedHashCode = 0;
|
||||
clone.compiled = null;
|
||||
clone.defines = (TreeMap<String, String>) defines.clone();
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean set(String key, VarType type, Object val){
|
||||
if (val == null){
|
||||
defines.remove(key);
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (type){
|
||||
case Boolean:
|
||||
if (((Boolean) val).booleanValue()) {
|
||||
// same literal, != will work
|
||||
if (defines.put(key, ONE) != ONE) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
} else if (defines.containsKey(key)) {
|
||||
defines.remove(key);
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case Float:
|
||||
case Int:
|
||||
String newValue = val.toString();
|
||||
String original = defines.put(key, newValue);
|
||||
if (!val.equals(original)) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// same literal, != will work
|
||||
if (defines.put(key, ONE) != ONE) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean remove(String key){
|
||||
if (defines.remove(key) != null) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addFrom(DefineList other){
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
defines.putAll(other.defines);
|
||||
}
|
||||
|
||||
public String getCompiled(){
|
||||
if (compiled == null){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : defines.entrySet()){
|
||||
sb.append("#define ").append(entry.getKey()).append(" ");
|
||||
sb.append(entry.getValue()).append('\n');
|
||||
}
|
||||
compiled = sb.toString();
|
||||
}
|
||||
return compiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
final DefineList other = (DefineList) obj;
|
||||
return defines.equals(other.defines);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (cachedHashCode == 0) {
|
||||
cachedHashCode = defines.hashCode();
|
||||
}
|
||||
return cachedHashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String> entry : defines.entrySet()) {
|
||||
sb.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
if (i != defines.size() - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.export.*;
|
||||
import com.jme3.material.MatParam;
|
||||
import com.jme3.material.TechniqueDef;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class DefineList implements Savable, Cloneable {
|
||||
|
||||
private static final String ONE = "1";
|
||||
|
||||
private TreeMap<String, String> defines = new TreeMap<String, String>();
|
||||
private String compiled = null;
|
||||
private int cachedHashCode = 0;
|
||||
|
||||
public void write(JmeExporter ex) throws IOException{
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
|
||||
String[] keys = new String[defines.size()];
|
||||
String[] vals = new String[defines.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String> define : defines.entrySet()){
|
||||
keys[i] = define.getKey();
|
||||
vals[i] = define.getValue();
|
||||
i++;
|
||||
}
|
||||
|
||||
oc.write(keys, "keys", null);
|
||||
oc.write(vals, "vals", null);
|
||||
}
|
||||
|
||||
public void read(JmeImporter im) throws IOException{
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
|
||||
String[] keys = ic.readStringArray("keys", null);
|
||||
String[] vals = ic.readStringArray("vals", null);
|
||||
for (int i = 0; i < keys.length; i++){
|
||||
defines.put(keys[i], vals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
defines.clear();
|
||||
compiled = "";
|
||||
cachedHashCode = 0;
|
||||
}
|
||||
|
||||
public String get(String key){
|
||||
return defines.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefineList clone() {
|
||||
try {
|
||||
DefineList clone = (DefineList) super.clone();
|
||||
clone.cachedHashCode = 0;
|
||||
clone.compiled = null;
|
||||
clone.defines = (TreeMap<String, String>) defines.clone();
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean set(String key, VarType type, Object val){
|
||||
if (val == null){
|
||||
defines.remove(key);
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (type){
|
||||
case Boolean:
|
||||
if (((Boolean) val).booleanValue()) {
|
||||
// same literal, != will work
|
||||
if (defines.put(key, ONE) != ONE) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
} else if (defines.containsKey(key)) {
|
||||
defines.remove(key);
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
case Float:
|
||||
case Int:
|
||||
String newValue = val.toString();
|
||||
String original = defines.put(key, newValue);
|
||||
if (!val.equals(original)) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// same literal, != will work
|
||||
if (defines.put(key, ONE) != ONE) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean remove(String key){
|
||||
if (defines.remove(key) != null) {
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addFrom(DefineList other){
|
||||
if (other == null) {
|
||||
return;
|
||||
}
|
||||
compiled = null;
|
||||
cachedHashCode = 0;
|
||||
defines.putAll(other.defines);
|
||||
}
|
||||
|
||||
public String getCompiled(){
|
||||
if (compiled == null){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : defines.entrySet()){
|
||||
sb.append("#define ").append(entry.getKey()).append(" ");
|
||||
sb.append(entry.getValue()).append('\n');
|
||||
}
|
||||
compiled = sb.toString();
|
||||
}
|
||||
return compiled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
final DefineList other = (DefineList) obj;
|
||||
return defines.equals(other.defines);
|
||||
}
|
||||
|
||||
public boolean equalsParams(Collection<MatParam> params, TechniqueDef def) {
|
||||
|
||||
int size = 0;
|
||||
|
||||
for (MatParam param : params) {
|
||||
String key = def.getShaderParamDefine(param.getName());
|
||||
if (key != null) {
|
||||
Object val = param.getValue();
|
||||
if (val != null) {
|
||||
|
||||
switch (param.getVarType()) {
|
||||
case Boolean: {
|
||||
String current = defines.get(key);
|
||||
if (((Boolean) val).booleanValue()) {
|
||||
if (current == null || current != ONE) {
|
||||
return false;
|
||||
}
|
||||
size++;
|
||||
} else {
|
||||
if (current != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Float:
|
||||
case Int: {
|
||||
String newValue = val.toString();
|
||||
String current = defines.get(key);
|
||||
if (!newValue.equals(current)) {
|
||||
return false;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
if (!defines.containsKey(key)) {
|
||||
return false;
|
||||
}
|
||||
size++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (size != defines.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (cachedHashCode == 0) {
|
||||
cachedHashCode = defines.hashCode();
|
||||
}
|
||||
return cachedHashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 0;
|
||||
for (Map.Entry<String, String> entry : defines.entrySet()) {
|
||||
sb.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
if (i != defines.size() - 1) {
|
||||
sb.append(", ");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user