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
3.0
rem..om 12 years ago
parent 0186a20983
commit 723e3c0e30
  1. 521
      engine/src/core/com/jme3/material/Technique.java
  2. 466
      engine/src/core/com/jme3/shader/DefineList.java
  3. 1257
      engine/src/core/com/jme3/shadow/AbstractShadowRenderer.java

@ -1,261 +1,260 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012 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.renderer.Caps; import com.jme3.renderer.Caps;
import com.jme3.shader.*; import com.jme3.shader.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.EnumSet; import java.util.EnumSet;
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.
* Specify <code>null</code> for value if the param is to be cleared. * Specify <code>null</code> for value if the param is to be cleared.
*/ */
void notifyParamChanged(String paramName, VarType type, Object value) { void notifyParamChanged(String paramName, VarType type, Object value) {
// Check if there's a define binding associated with this // Check if there's a define binding associated with this
// parameter. // parameter.
String defineName = def.getShaderParamDefine(paramName); String defineName = def.getShaderParamDefine(paramName);
if (defineName != null) { if (defineName != null) {
// There is a define. Change it on the define list. // There is a define. Change it on the define list.
// The "needReload" variable will determine // The "needReload" variable will determine
// if the shader will be reloaded when the material // if the shader will be reloaded when the material
// is rendered. // is rendered.
if (value == null) { if (value == null) {
// Clear the define. // Clear the define.
needReload = defines.remove(defineName) || needReload; needReload = defines.remove(defineName) || needReload;
} else { } else {
// Set the define. // Set the define.
needReload = defines.set(defineName, type, value) || needReload; needReload = defines.set(defineName, type, value) || needReload;
} }
} }
} }
void updateUniformParam(String paramName, VarType type, Object value) { void updateUniformParam(String paramName, VarType type, Object value) {
if (paramName == null) { if (paramName == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
Uniform u = shader.getUniform(paramName); Uniform u = shader.getUniform(paramName);
switch (type) { switch (type) {
case TextureBuffer: case TextureBuffer:
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;
} }
} }
/** /**
* 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, boolean techniqueSwitched, EnumSet<Caps> rendererCaps) { public void makeCurrent(AssetManager assetManager, boolean techniqueSwitched, EnumSet<Caps> rendererCaps) {
if (!def.isUsingShaders()) { if (!def.isUsingShaders()) {
// No shaders are used, no processing is neccessary. // No shaders are used, no processing is neccessary.
return; return;
} }
if (techniqueSwitched) { if (techniqueSwitched) {
// If the technique was switched, check if the define list changed // If the technique was switched, check if the define list changed
// based on material parameters. // based on material parameters.
DefineList newDefines = new DefineList();
Collection<MatParam> params = owner.getParams(); Collection<MatParam> params = owner.getParams();
for (MatParam param : params) {
String defineName = def.getShaderParamDefine(param.getName()); if (!defines.equalsParams(params,def)) {
if (defineName != null) { // Defines were changed, update define list
newDefines.set(defineName, param.getVarType(), param.getValue()); defines.clear();
} for (MatParam param : params) {
} String defineName = def.getShaderParamDefine(param.getName());
if (defineName != null) {
if (!defines.getCompiled().equals(newDefines.getCompiled())) { defines.set(defineName, param.getVarType(), param.getValue());
// Defines were changed, update define list }
defines.clear(); }
defines.addFrom(newDefines); needReload = true;
needReload = true; }
} }
}
if (needReload) {
if (needReload) { loadShader(assetManager,rendererCaps);
loadShader(assetManager,rendererCaps); }
} }
}
private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
private void loadShader(AssetManager manager,EnumSet<Caps> rendererCaps) {
if (getDef().isUsingShaderNodes()) {
if (getDef().isUsingShaderNodes()) { shader = manager.getShaderGenerator(rendererCaps).generateShader(this);
shader = manager.getShaderGenerator(rendererCaps).generateShader(this); } else {
} else { ShaderKey key = new ShaderKey(def.getVertexShaderName(),
ShaderKey key = new ShaderKey(def.getVertexShaderName(), def.getFragmentShaderName(),
def.getFragmentShaderName(), getAllDefines(),
getAllDefines(), def.getVertexShaderLanguage(),
def.getVertexShaderLanguage(), def.getFragmentShaderLanguage());
def.getFragmentShaderLanguage()); shader = manager.loadShader(key);
shader = manager.loadShader(key);
}
} // register the world bound uniforms
// register the world bound uniforms worldBindUniforms.clear();
worldBindUniforms.clear(); if (def.getWorldBindings() != null) {
if (def.getWorldBindings() != null) { for (UniformBinding binding : def.getWorldBindings()) {
for (UniformBinding binding : def.getWorldBindings()) { Uniform uniform = shader.getUniform("g_" + binding.name());
Uniform uniform = shader.getUniform("g_" + binding.name()); uniform.setBinding(binding);
uniform.setBinding(binding); if (uniform != null) {
if (uniform != null) { worldBindUniforms.add(uniform);
worldBindUniforms.add(uniform); }
} }
} }
} needReload = false;
needReload = false; }
}
/**
/** * Computes the define list
* Computes the define list * @return the complete define list
* @return the complete define list */
*/ public DefineList getAllDefines() {
public DefineList getAllDefines() { DefineList allDefines = new DefineList();
DefineList allDefines = new DefineList(); allDefines.addFrom(def.getShaderPresetDefines());
allDefines.addFrom(def.getShaderPresetDefines()); allDefines.addFrom(defines);
allDefines.addFrom(defines); return allDefines;
return allDefines; }
}
/*
/* public void write(JmeExporter ex) throws IOException {
public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this);
OutputCapsule oc = ex.getCapsule(this); oc.write(def, "def", null);
oc.write(def, "def", null); oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null);
oc.writeSavableArrayList(worldBindUniforms, "worldBindUniforms", null); oc.write(defines, "defines", null);
oc.write(defines, "defines", null); oc.write(shader, "shader", null);
oc.write(shader, "shader", null); }
}
public void read(JmeImporter im) throws IOException {
public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this);
InputCapsule ic = im.getCapsule(this); def = (TechniqueDef) ic.readSavable("def", null);
def = (TechniqueDef) ic.readSavable("def", null); worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null);
worldBindUniforms = ic.readSavableArrayList("worldBindUniforms", null); defines = (DefineList) ic.readSavable("defines", null);
defines = (DefineList) ic.readSavable("defines", null); shader = (Shader) ic.readSavable("shader", null);
shader = (Shader) ic.readSavable("shader", null); }
} */
*/ }
}

@ -1,203 +1,263 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012 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.shader; package com.jme3.shader;
import com.jme3.export.*; import com.jme3.export.*;
import java.io.IOException; import com.jme3.material.MatParam;
import java.util.Map; import com.jme3.material.TechniqueDef;
import java.util.TreeMap;
import java.io.IOException;
public class DefineList implements Savable, Cloneable { import java.util.Collection;
import java.util.Map;
private static final String ONE = "1"; import java.util.TreeMap;
private TreeMap<String, String> defines = new TreeMap<String, String>(); public class DefineList implements Savable, Cloneable {
private String compiled = null;
private int cachedHashCode = 0; private static final String ONE = "1";
public void write(JmeExporter ex) throws IOException{ private TreeMap<String, String> defines = new TreeMap<String, String>();
OutputCapsule oc = ex.getCapsule(this); private String compiled = null;
private int cachedHashCode = 0;
String[] keys = new String[defines.size()];
String[] vals = new String[defines.size()]; public void write(JmeExporter ex) throws IOException{
OutputCapsule oc = ex.getCapsule(this);
int i = 0;
for (Map.Entry<String, String> define : defines.entrySet()){ String[] keys = new String[defines.size()];
keys[i] = define.getKey(); String[] vals = new String[defines.size()];
vals[i] = define.getValue();
i++; int i = 0;
} for (Map.Entry<String, String> define : defines.entrySet()){
keys[i] = define.getKey();
oc.write(keys, "keys", null); vals[i] = define.getValue();
oc.write(vals, "vals", null); i++;
} }
public void read(JmeImporter im) throws IOException{ oc.write(keys, "keys", null);
InputCapsule ic = im.getCapsule(this); oc.write(vals, "vals", null);
}
String[] keys = ic.readStringArray("keys", null);
String[] vals = ic.readStringArray("vals", null); public void read(JmeImporter im) throws IOException{
for (int i = 0; i < keys.length; i++){ InputCapsule ic = im.getCapsule(this);
defines.put(keys[i], vals[i]);
} String[] keys = ic.readStringArray("keys", null);
} String[] vals = ic.readStringArray("vals", null);
for (int i = 0; i < keys.length; i++){
public void clear() { defines.put(keys[i], vals[i]);
defines.clear(); }
compiled = ""; }
cachedHashCode = 0;
} public void clear() {
defines.clear();
public String get(String key){ compiled = "";
return defines.get(key); cachedHashCode = 0;
} }
@Override public String get(String key){
public DefineList clone() { return defines.get(key);
try { }
DefineList clone = (DefineList) super.clone();
clone.cachedHashCode = 0; @Override
clone.compiled = null; public DefineList clone() {
clone.defines = (TreeMap<String, String>) defines.clone(); try {
return clone; DefineList clone = (DefineList) super.clone();
} catch (CloneNotSupportedException ex) { clone.cachedHashCode = 0;
throw new AssertionError(); clone.compiled = null;
} clone.defines = (TreeMap<String, String>) defines.clone();
} return clone;
} catch (CloneNotSupportedException ex) {
public boolean set(String key, VarType type, Object val){ throw new AssertionError();
if (val == null){ }
defines.remove(key); }
compiled = null;
cachedHashCode = 0; public boolean set(String key, VarType type, Object val){
return true; if (val == null){
} defines.remove(key);
compiled = null;
switch (type){ cachedHashCode = 0;
case Boolean: return true;
if (((Boolean) val).booleanValue()) { }
// same literal, != will work
if (defines.put(key, ONE) != ONE) { switch (type){
compiled = null; case Boolean:
cachedHashCode = 0; if (((Boolean) val).booleanValue()) {
return true; // same literal, != will work
} if (defines.put(key, ONE) != ONE) {
} else if (defines.containsKey(key)) { compiled = null;
defines.remove(key); cachedHashCode = 0;
compiled = null; return true;
cachedHashCode = 0; }
return true; } else if (defines.containsKey(key)) {
} defines.remove(key);
compiled = null;
break; cachedHashCode = 0;
case Float: return true;
case Int: }
String newValue = val.toString();
String original = defines.put(key, newValue); break;
if (!val.equals(original)) { case Float:
compiled = null; case Int:
cachedHashCode = 0; String newValue = val.toString();
return true; String original = defines.put(key, newValue);
} if (!val.equals(original)) {
break; compiled = null;
default: cachedHashCode = 0;
// same literal, != will work return true;
if (defines.put(key, ONE) != ONE) { }
compiled = null; break;
cachedHashCode = 0; default:
return true; // same literal, != will work
} if (defines.put(key, ONE) != ONE) {
break; compiled = null;
} cachedHashCode = 0;
return true;
return false; }
} break;
}
public boolean remove(String key){
if (defines.remove(key) != null) { return false;
compiled = null; }
cachedHashCode = 0;
return true; public boolean remove(String key){
} if (defines.remove(key) != null) {
return false; compiled = null;
} cachedHashCode = 0;
return true;
public void addFrom(DefineList other){ }
if (other == null) { return false;
return; }
}
compiled = null; public void addFrom(DefineList other){
cachedHashCode = 0; if (other == null) {
defines.putAll(other.defines); return;
} }
compiled = null;
public String getCompiled(){ cachedHashCode = 0;
if (compiled == null){ defines.putAll(other.defines);
StringBuilder sb = new StringBuilder(); }
for (Map.Entry<String, String> entry : defines.entrySet()){
sb.append("#define ").append(entry.getKey()).append(" "); public String getCompiled(){
sb.append(entry.getValue()).append('\n'); if (compiled == null){
} StringBuilder sb = new StringBuilder();
compiled = sb.toString(); for (Map.Entry<String, String> entry : defines.entrySet()){
} sb.append("#define ").append(entry.getKey()).append(" ");
return compiled; sb.append(entry.getValue()).append('\n');
} }
compiled = sb.toString();
@Override }
public boolean equals(Object obj) { return compiled;
final DefineList other = (DefineList) obj; }
return defines.equals(other.defines);
} @Override
public boolean equals(Object obj) {
@Override final DefineList other = (DefineList) obj;
public int hashCode() { return defines.equals(other.defines);
if (cachedHashCode == 0) { }
cachedHashCode = defines.hashCode();
} public boolean equalsParams(Collection<MatParam> params, TechniqueDef def) {
return cachedHashCode;
} int size = 0;
@Override for (MatParam param : params) {
public String toString(){ String key = def.getShaderParamDefine(param.getName());
StringBuilder sb = new StringBuilder(); if (key != null) {
int i = 0; Object val = param.getValue();
for (Map.Entry<String, String> entry : defines.entrySet()) { if (val != null) {
sb.append(entry.getKey()).append("=").append(entry.getValue());
if (i != defines.size() - 1) { switch (param.getVarType()) {
sb.append(", "); case Boolean: {
} String current = defines.get(key);
i++; if (((Boolean) val).booleanValue()) {
} if (current == null || current != ONE) {
return sb.toString(); 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…
Cancel
Save