Material has now a isEqual method that compares materialDef, material params and material additional render state

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9256 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 13 years ago
parent 533fb86c50
commit 55b8188d20
  1. 110
      engine/src/core/com/jme3/material/Material.java
  2. 169
      engine/src/core/com/jme3/material/RenderState.java
  3. 109
      engine/src/test/jme3test/material/TestMaterialCompare.java

@ -69,7 +69,6 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
// Version #2: Fixed issue with RenderState.apply*** flags not getting exported // Version #2: Fixed issue with RenderState.apply*** flags not getting exported
public static final int SAVABLE_VERSION = 2; public static final int SAVABLE_VERSION = 2;
private static final Logger logger = Logger.getLogger(Material.class.getName()); private static final Logger logger = Logger.getLogger(Material.class.getName());
private static final RenderState additiveLight = new RenderState(); private static final RenderState additiveLight = new RenderState();
private static final RenderState depthOnly = new RenderState(); private static final RenderState depthOnly = new RenderState();
@ -105,8 +104,8 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
this.def = def; this.def = def;
// Load default values from definition (if any) // Load default values from definition (if any)
for (MatParam param : def.getMaterialParams()){ for (MatParam param : def.getMaterialParams()) {
if (param.getValue() != null){ if (param.getValue() != null) {
setParam(param.getName(), param.getVarType(), param.getValue()); setParam(param.getName(), param.getVarType(), param.getValue());
} }
} }
@ -138,8 +137,8 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
* @return the name of the material (not the same as the asset name), the returned value can be null * @return the name of the material (not the same as the asset name), the returned value can be null
*/ */
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* This method sets the name of the material. * This method sets the name of the material.
@ -148,8 +147,8 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
* @param name the name of the material * @param name the name of the material
*/ */
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public void setKey(AssetKey key) { public void setKey(AssetKey key) {
this.key = key; this.key = key;
@ -204,8 +203,8 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(obj instanceof Material){ if (obj instanceof Material) {
return ((Material)obj).compareTo(this) == 0; return ((Material) obj).compareTo(this) == 0;
} }
return super.equals(obj); return super.equals(obj);
} }
@ -232,8 +231,83 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
return mat; return mat;
} catch (CloneNotSupportedException ex) { } catch (CloneNotSupportedException ex) {
throw new AssertionError(); throw new AssertionError(ex);
}
}
/**
* Compares two materials and returns true if they are equal.
* This methods compare definition, params, additional render states
* The difference with the equals method is that it's truely comaring the objects. (equals compare the sort ids for geometry sorting)
* @param mat the material to cmpare to this material
* @return true if the materials are equal.
*/
public boolean isEqual(Material mat) {
//early exit if the material are the same object
if (this == mat) {
return true;
}
//comparing matrial definition
if (this.getMaterialDef() != mat.getMaterialDef()) {
return false;
}
//early exit if the size of the params is different
if (paramValues.size() != mat.paramValues.size()) {
return false;
}
//comparing params
for (String paramKey : paramValues.keySet()) {
MatParam paramOrig = getParam(paramKey);
MatParam param = mat.getParam(paramKey);
//this param does not exist in compared mat
if (param == null) {
return false;
}
//params exist in both materials but they not of the same type
if (param.type != paramOrig.type) {
return false;
}
if (param instanceof MatParamTexture) {
MatParamTexture tex = (MatParamTexture) param;
MatParamTexture texOrig = (MatParamTexture) paramOrig;
//comparing textures
if (getTextureId(tex) != getTextureId(texOrig)) {
return false;
}
} else {
if (!param.getValue().equals(paramOrig.getValue())) {
return false;
}
}
}
//comparing additional render states
if (additionalState == null) {
if (mat.additionalState != null) {
return false;
}
} else {
if (!additionalState.equals(mat.additionalState)) {
return false;
}
}
return true;
}
private int getTextureId(MatParamTexture param) {
if (param.getTextureValue() != null && param.getTextureValue().getImage() != null) {
return param.getTextureValue().getImage().getId();
} }
return -1;
} }
/** /**
@ -386,7 +460,7 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
if (type != null && paramDef.getVarType() != type) { if (type != null && paramDef.getVarType() != type) {
logger.log(Level.WARNING, "Material parameter being set: {0} with " logger.log(Level.WARNING, "Material parameter being set: {0} with "
+ "type {1} doesn''t match definition types {2}", new Object[]{name, type.name(), paramDef.getVarType()} ); + "type {1} doesn''t match definition types {2}", new Object[]{name, type.name(), paramDef.getVarType()});
} }
return newName; return newName;
@ -785,7 +859,7 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
//We transform the spot directoin in view space here to save 5 varying later in the lighting shader //We transform the spot directoin in view space here to save 5 varying later in the lighting shader
//one vec4 less and a vec4 that becomes a vec3 //one vec4 less and a vec4 that becomes a vec3
//the downside is that spotAngleCos decoding happen now in the frag shader. //the downside is that spotAngleCos decoding happen now in the frag shader.
tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(),0); tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0);
rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos); tmpLightDirection.set(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos);
@ -1064,10 +1138,10 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
boolean guessRenderStateApply = false; boolean guessRenderStateApply = false;
int ver = ic.getSavableVersion(Material.class); int ver = ic.getSavableVersion(Material.class);
if (ver < 1){ if (ver < 1) {
applyDefaultValues = true; applyDefaultValues = true;
} }
if (ver < 2){ if (ver < 2) {
guessRenderStateApply = true; guessRenderStateApply = true;
} }
if (im.getFormatVersion() == 0) { if (im.getFormatVersion() == 0) {
@ -1118,16 +1192,16 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
paramValues.put(param.getName(), param); paramValues.put(param.getName(), param);
} }
if (applyDefaultValues){ if (applyDefaultValues) {
// compatability with old versions where default vars were // compatability with old versions where default vars were
// not available // not available
for (MatParam param : def.getMaterialParams()){ for (MatParam param : def.getMaterialParams()) {
if (param.getValue() != null && paramValues.get(param.getName()) == null){ if (param.getValue() != null && paramValues.get(param.getName()) == null) {
setParam(param.getName(), param.getVarType(), param.getValue()); setParam(param.getName(), param.getVarType(), param.getValue());
} }
} }
} }
if (guessRenderStateApply && additionalState != null){ if (guessRenderStateApply && additionalState != null) {
// Try to guess values of "apply" render state based on defaults // Try to guess values of "apply" render state based on defaults
// if value != default then set apply to true // if value != default then set apply to true
additionalState.applyPolyOffset = additionalState.offsetEnabled; additionalState.applyPolyOffset = additionalState.offsetEnabled;

@ -59,13 +59,11 @@ public class RenderState implements Cloneable, Savable {
* </ul> * </ul>
*/ */
public static final RenderState DEFAULT = new RenderState(); public static final RenderState DEFAULT = new RenderState();
/** /**
* The <code>NULL</code> render state is identical to the {@link RenderState#DEFAULT} * The <code>NULL</code> render state is identical to the {@link RenderState#DEFAULT}
* render state except that depth testing and face culling are disabled. * render state except that depth testing and face culling are disabled.
*/ */
public static final RenderState NULL = new RenderState(); public static final RenderState NULL = new RenderState();
/** /**
* The <code>ADDITIONAL</code> render state is identical to the * The <code>ADDITIONAL</code> render state is identical to the
* {@link RenderState#DEFAULT} render state except that all apply * {@link RenderState#DEFAULT} render state except that all apply
@ -232,13 +230,11 @@ public class RenderState implements Cloneable, Savable {
* Replace the value in the stencil buffer with the reference value. * Replace the value in the stencil buffer with the reference value.
*/ */
Replace, Replace,
/** /**
* Increment the value in the stencil buffer, clamp once reaching * Increment the value in the stencil buffer, clamp once reaching
* the maximum value. * the maximum value.
*/ */
Increment, Increment,
/** /**
* Increment the value in the stencil buffer and wrap to 0 when * Increment the value in the stencil buffer and wrap to 0 when
* reaching the maximum value. * reaching the maximum value.
@ -253,7 +249,6 @@ public class RenderState implements Cloneable, Savable {
* value when reaching 0. * value when reaching 0.
*/ */
DecrementWrap, DecrementWrap,
/** /**
* Does a bitwise invert of the value in the stencil buffer. * Does a bitwise invert of the value in the stencil buffer.
*/ */
@ -277,39 +272,28 @@ public class RenderState implements Cloneable, Savable {
ADDITIONAL.applyAlphaFallOff = false; ADDITIONAL.applyAlphaFallOff = false;
ADDITIONAL.applyPolyOffset = false; ADDITIONAL.applyPolyOffset = false;
} }
boolean pointSprite = false; boolean pointSprite = false;
boolean applyPointSprite = true; boolean applyPointSprite = true;
boolean wireframe = false; boolean wireframe = false;
boolean applyWireFrame = true; boolean applyWireFrame = true;
FaceCullMode cullMode = FaceCullMode.Back; FaceCullMode cullMode = FaceCullMode.Back;
boolean applyCullMode = true; boolean applyCullMode = true;
boolean depthWrite = true; boolean depthWrite = true;
boolean applyDepthWrite = true; boolean applyDepthWrite = true;
boolean depthTest = true; boolean depthTest = true;
boolean applyDepthTest = true; boolean applyDepthTest = true;
boolean colorWrite = true; boolean colorWrite = true;
boolean applyColorWrite = true; boolean applyColorWrite = true;
BlendMode blendMode = BlendMode.Off; BlendMode blendMode = BlendMode.Off;
boolean applyBlendMode = true; boolean applyBlendMode = true;
boolean alphaTest = false; boolean alphaTest = false;
boolean applyAlphaTest = true; boolean applyAlphaTest = true;
float alphaFallOff = 0; float alphaFallOff = 0;
boolean applyAlphaFallOff = true; boolean applyAlphaFallOff = true;
float offsetFactor = 0; float offsetFactor = 0;
float offsetUnits = 0; float offsetUnits = 0;
boolean offsetEnabled = false; boolean offsetEnabled = false;
boolean applyPolyOffset = true; boolean applyPolyOffset = true;
boolean stencilTest = false; boolean stencilTest = false;
boolean applyStencilTest = false; boolean applyStencilTest = false;
StencilOperation frontStencilStencilFailOperation = StencilOperation.Keep; StencilOperation frontStencilStencilFailOperation = StencilOperation.Keep;
@ -346,16 +330,16 @@ public class RenderState implements Cloneable, Savable {
oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always); oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always);
// Only "additional render state" has them set to false by default // Only "additional render state" has them set to false by default
oc.write(applyPointSprite, "applyPointSprite", true); oc.write(applyPointSprite, "applyPointSprite", true);
oc.write(applyWireFrame, "applyWireFrame", true); oc.write(applyWireFrame, "applyWireFrame", true);
oc.write(applyCullMode, "applyCullMode", true); oc.write(applyCullMode, "applyCullMode", true);
oc.write(applyDepthWrite, "applyDepthWrite", true); oc.write(applyDepthWrite, "applyDepthWrite", true);
oc.write(applyDepthTest, "applyDepthTest", true); oc.write(applyDepthTest, "applyDepthTest", true);
oc.write(applyColorWrite, "applyColorWrite", true); oc.write(applyColorWrite, "applyColorWrite", true);
oc.write(applyBlendMode, "applyBlendMode", true); oc.write(applyBlendMode, "applyBlendMode", true);
oc.write(applyAlphaTest, "applyAlphaTest", true); oc.write(applyAlphaTest, "applyAlphaTest", true);
oc.write(applyAlphaFallOff, "applyAlphaFallOff", true); oc.write(applyAlphaFallOff, "applyAlphaFallOff", true);
oc.write(applyPolyOffset, "applyPolyOffset", true); oc.write(applyPolyOffset, "applyPolyOffset", true);
} }
@ -383,16 +367,16 @@ public class RenderState implements Cloneable, Savable {
frontStencilFunction = ic.readEnum("frontStencilFunction", TestFunction.class, TestFunction.Always); frontStencilFunction = ic.readEnum("frontStencilFunction", TestFunction.class, TestFunction.Always);
backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always); backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always);
applyPointSprite = ic.readBoolean("applyPointSprite", true); applyPointSprite = ic.readBoolean("applyPointSprite", true);
applyWireFrame = ic.readBoolean("applyWireFrame", true); applyWireFrame = ic.readBoolean("applyWireFrame", true);
applyCullMode = ic.readBoolean("applyCullMode", true); applyCullMode = ic.readBoolean("applyCullMode", true);
applyDepthWrite = ic.readBoolean("applyDepthWrite", true); applyDepthWrite = ic.readBoolean("applyDepthWrite", true);
applyDepthTest = ic.readBoolean("applyDepthTest", true); applyDepthTest = ic.readBoolean("applyDepthTest", true);
applyColorWrite = ic.readBoolean("applyColorWrite", true); applyColorWrite = ic.readBoolean("applyColorWrite", true);
applyBlendMode = ic.readBoolean("applyBlendMode", true); applyBlendMode = ic.readBoolean("applyBlendMode", true);
applyAlphaTest = ic.readBoolean("applyAlphaTest", true); applyAlphaTest = ic.readBoolean("applyAlphaTest", true);
applyAlphaFallOff = ic.readBoolean("applyAlphaFallOff", true); applyAlphaFallOff = ic.readBoolean("applyAlphaFallOff", true);
applyPolyOffset = ic.readBoolean("applyPolyOffset", true); applyPolyOffset = ic.readBoolean("applyPolyOffset", true);
} }
/** /**
@ -409,6 +393,103 @@ public class RenderState implements Cloneable, Savable {
} }
} }
/**
* returns true if the given renderState is equall to this one
* @param o the renderState to compate to
* @return true if the renderStates are equal
*/
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof RenderState)) {
return false;
}
RenderState rs = (RenderState) o;
if (pointSprite != rs.pointSprite) {
return false;
}
if (wireframe != rs.wireframe) {
return false;
}
if (cullMode != rs.cullMode) {
return false;
}
if (depthWrite != rs.depthWrite) {
return false;
}
if (depthTest != rs.depthTest) {
return false;
}
if (colorWrite != rs.colorWrite) {
return false;
}
if (blendMode != rs.blendMode) {
return false;
}
if (alphaTest != rs.alphaTest) {
return false;
}
if (alphaFallOff != rs.alphaFallOff) {
return false;
}
if (offsetEnabled != rs.offsetEnabled) {
return false;
}
if (offsetFactor != rs.offsetFactor) {
return false;
}
if (offsetUnits != rs.offsetUnits) {
return false;
}
if (stencilTest != rs.stencilTest) {
return false;
}
if (stencilTest) {
if (frontStencilStencilFailOperation != rs.frontStencilStencilFailOperation) {
return false;
}
if (frontStencilDepthFailOperation != rs.frontStencilDepthFailOperation) {
return false;
}
if (frontStencilDepthPassOperation != rs.frontStencilDepthPassOperation) {
return false;
}
if (backStencilStencilFailOperation != rs.backStencilStencilFailOperation) {
return false;
}
if (backStencilDepthFailOperation != rs.backStencilDepthFailOperation) {
return false;
}
if (backStencilDepthPassOperation != rs.backStencilDepthPassOperation) {
return false;
}
if (frontStencilFunction != rs.frontStencilFunction) {
return false;
}
if (backStencilFunction != rs.backStencilFunction) {
return false;
}
}
return true;
}
/** /**
* Enables point sprite mode. * Enables point sprite mode.
* *
@ -1033,29 +1114,29 @@ public class RenderState implements Cloneable, Savable {
state.offsetFactor = offsetFactor; state.offsetFactor = offsetFactor;
state.offsetUnits = offsetUnits; state.offsetUnits = offsetUnits;
} }
if (additionalState.applyStencilTest){ if (additionalState.applyStencilTest) {
state.stencilTest = additionalState.stencilTest; state.stencilTest = additionalState.stencilTest;
state.frontStencilStencilFailOperation = additionalState.frontStencilStencilFailOperation; state.frontStencilStencilFailOperation = additionalState.frontStencilStencilFailOperation;
state.frontStencilDepthFailOperation = additionalState.frontStencilDepthFailOperation; state.frontStencilDepthFailOperation = additionalState.frontStencilDepthFailOperation;
state.frontStencilDepthPassOperation = additionalState.frontStencilDepthPassOperation; state.frontStencilDepthPassOperation = additionalState.frontStencilDepthPassOperation;
state.backStencilStencilFailOperation = additionalState.backStencilStencilFailOperation; state.backStencilStencilFailOperation = additionalState.backStencilStencilFailOperation;
state.backStencilDepthFailOperation = additionalState.backStencilDepthFailOperation; state.backStencilDepthFailOperation = additionalState.backStencilDepthFailOperation;
state.backStencilDepthPassOperation = additionalState.backStencilDepthPassOperation; state.backStencilDepthPassOperation = additionalState.backStencilDepthPassOperation;
state.frontStencilFunction = additionalState.frontStencilFunction; state.frontStencilFunction = additionalState.frontStencilFunction;
state.backStencilFunction = additionalState.backStencilFunction; state.backStencilFunction = additionalState.backStencilFunction;
}else{ } else {
state.stencilTest = stencilTest; state.stencilTest = stencilTest;
state.frontStencilStencilFailOperation = frontStencilStencilFailOperation; state.frontStencilStencilFailOperation = frontStencilStencilFailOperation;
state.frontStencilDepthFailOperation = frontStencilDepthFailOperation; state.frontStencilDepthFailOperation = frontStencilDepthFailOperation;
state.frontStencilDepthPassOperation = frontStencilDepthPassOperation; state.frontStencilDepthPassOperation = frontStencilDepthPassOperation;
state.backStencilStencilFailOperation = backStencilStencilFailOperation; state.backStencilStencilFailOperation = backStencilStencilFailOperation;
state.backStencilDepthFailOperation = backStencilDepthFailOperation; state.backStencilDepthFailOperation = backStencilDepthFailOperation;
state.backStencilDepthPassOperation = backStencilDepthPassOperation; state.backStencilDepthPassOperation = backStencilDepthPassOperation;
state.frontStencilFunction = frontStencilFunction; state.frontStencilFunction = frontStencilFunction;
state.backStencilFunction = backStencilFunction; state.backStencilFunction = backStencilFunction;

@ -0,0 +1,109 @@
/*
* 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 jme3test.material;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TestMaterialCompare extends SimpleApplication {
public static void main(String[] args) {
TestMaterialCompare app = new TestMaterialCompare();
app.start();
}
@Override
public void simpleInitApp() {
Logger.getLogger("com.jme3").setLevel(Level.SEVERE);
//clonned mats
Material mat1 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat1.setName("mat1");
mat1.setColor("Color", ColorRGBA.Blue);
Material mat2 = mat1.clone();
mat2.setName("mat2");
testMats(mat1,mat2,true);
//clonned mat with different additional render state
Material mat3 = mat1.clone();;
mat3.setName("mat3");
mat3.getAdditionalRenderState().setBlendMode(BlendMode.ModulateX2);
testMats(mat1,mat3,false);
//two separately loaded materials
Material mat4 = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
mat4.setName("mat4");
Material mat5 = assetManager.loadMaterial("Models/Sign Post/Sign Post.j3m");
mat5.setName("mat5");
testMats(mat4,mat5,true);
//two materials created the same way
Material mat6 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat6.setName("mat6");
mat6.setColor("Color", ColorRGBA.Blue);
testMats(mat1,mat6,true);
//changing a material param
mat6.setColor("Color", ColorRGBA.Green);
testMats(mat1,mat6,false);
}
private void testMats(Material mat1, Material mat2, boolean expected) {
if (mat2.isEqual(mat1)) {
System.out.print(mat1.getName() + " equals " + mat2.getName());
if(expected){
System.out.println(" success");
}else{
System.out.println(" fail");
}
}else{
System.out.print(mat1.getName() + " is not equal " + mat2.getName());
if(!expected){
System.out.println(" success");
}else{
System.out.println(" fail");
}
}
}
@Override
public void simpleUpdate(float tpf) {
}
}
Loading…
Cancel
Save