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. 120
      engine/src/core/com/jme3/material/Material.java
  2. 177
      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
public static final int SAVABLE_VERSION = 2;
private static final Logger logger = Logger.getLogger(Material.class.getName());
private static final RenderState additiveLight = 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;
// Load default values from definition (if any)
for (MatParam param : def.getMaterialParams()){
if (param.getValue() != null){
for (MatParam param : def.getMaterialParams()) {
if (param.getValue() != null) {
setParam(param.getName(), param.getVarType(), param.getValue());
}
}
@ -133,14 +132,14 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
public String getAssetName() {
return key != null ? key.getName() : null;
}
/**
* @return the name of the material (not the same as the asset name), the returned value can be null
*/
public String getName() {
return name;
}
return name;
}
/**
* This method sets the name of the material.
* The name is not the same as the asset name.
@ -148,8 +147,8 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
* @param name the name of the material
*/
public void setName(String name) {
this.name = name;
}
this.name = name;
}
public void setKey(AssetKey key) {
this.key = key;
@ -204,12 +203,12 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
@Override
public boolean equals(Object obj) {
if(obj instanceof Material){
return ((Material)obj).compareTo(this) == 0;
if (obj instanceof Material) {
return ((Material) obj).compareTo(this) == 0;
}
return super.equals(obj);
}
/**
* Clones this material. The result is returned.
*/
@ -232,10 +231,85 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
return mat;
} 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;
}
/**
* Returns the currently active technique.
* <p>
@ -386,7 +460,7 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
if (type != null && paramDef.getVarType() != type) {
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;
@ -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
//one vec4 less and a vec4 that becomes a vec3
//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);
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;
int ver = ic.getSavableVersion(Material.class);
if (ver < 1){
if (ver < 1) {
applyDefaultValues = true;
}
if (ver < 2){
if (ver < 2) {
guessRenderStateApply = true;
}
if (im.getFormatVersion() == 0) {
@ -1117,24 +1191,24 @@ public class Material implements Asset, Cloneable, Savable, Comparable<Material>
param.setName(checkSetParam(param.getVarType(), param.getName()));
paramValues.put(param.getName(), param);
}
if (applyDefaultValues){
if (applyDefaultValues) {
// compatability with old versions where default vars were
// not available
for (MatParam param : def.getMaterialParams()){
if (param.getValue() != null && paramValues.get(param.getName()) == null){
for (MatParam param : def.getMaterialParams()) {
if (param.getValue() != null && paramValues.get(param.getName()) == null) {
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
// if value != default then set apply to true
additionalState.applyPolyOffset = additionalState.offsetEnabled;
additionalState.applyAlphaFallOff = additionalState.alphaTest;
additionalState.applyAlphaTest = additionalState.alphaTest;
additionalState.applyBlendMode = additionalState.blendMode != BlendMode.Off;
additionalState.applyColorWrite = !additionalState.colorWrite;
additionalState.applyColorWrite = !additionalState.colorWrite;
additionalState.applyCullMode = additionalState.cullMode != FaceCullMode.Back;
additionalState.applyDepthTest = !additionalState.depthTest;
additionalState.applyDepthWrite = !additionalState.depthWrite;

@ -59,13 +59,11 @@ public class RenderState implements Cloneable, Savable {
* </ul>
*/
public static final RenderState DEFAULT = new RenderState();
/**
* The <code>NULL</code> render state is identical to the {@link RenderState#DEFAULT}
* render state except that depth testing and face culling are disabled.
*/
public static final RenderState NULL = new RenderState();
/**
* The <code>ADDITIONAL</code> render state is identical to the
* {@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,
/**
* Increment the value in the stencil buffer, clamp once reaching
* the maximum value.
*/
Increment,
/**
* Increment the value in the stencil buffer and wrap to 0 when
* reaching the maximum value.
@ -253,7 +249,6 @@ public class RenderState implements Cloneable, Savable {
* value when reaching 0.
*/
DecrementWrap,
/**
* 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.applyPolyOffset = false;
}
boolean pointSprite = false;
boolean applyPointSprite = true;
boolean wireframe = false;
boolean applyWireFrame = true;
FaceCullMode cullMode = FaceCullMode.Back;
boolean applyCullMode = true;
boolean depthWrite = true;
boolean applyDepthWrite = true;
boolean depthTest = true;
boolean applyDepthTest = true;
boolean colorWrite = true;
boolean applyColorWrite = true;
BlendMode blendMode = BlendMode.Off;
boolean applyBlendMode = true;
boolean alphaTest = false;
boolean applyAlphaTest = true;
float alphaFallOff = 0;
boolean applyAlphaFallOff = true;
float offsetFactor = 0;
float offsetUnits = 0;
boolean offsetEnabled = false;
boolean applyPolyOffset = true;
boolean stencilTest = false;
boolean applyStencilTest = false;
StencilOperation frontStencilStencilFailOperation = StencilOperation.Keep;
@ -320,7 +304,7 @@ public class RenderState implements Cloneable, Savable {
StencilOperation backStencilDepthPassOperation = StencilOperation.Keep;
TestFunction frontStencilFunction = TestFunction.Always;
TestFunction backStencilFunction = TestFunction.Always;
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.write(pointSprite, "pointSprite", false);
@ -344,19 +328,19 @@ public class RenderState implements Cloneable, Savable {
oc.write(backStencilDepthPassOperation, "backStencilDepthPassOperation", StencilOperation.Keep);
oc.write(frontStencilFunction, "frontStencilFunction", TestFunction.Always);
oc.write(backStencilFunction, "backStencilFunction", TestFunction.Always);
// Only "additional render state" has them set to false by default
oc.write(applyPointSprite, "applyPointSprite", true);
oc.write(applyWireFrame, "applyWireFrame", true);
oc.write(applyCullMode, "applyCullMode", true);
oc.write(applyDepthWrite, "applyDepthWrite", true);
oc.write(applyDepthTest, "applyDepthTest", true);
oc.write(applyColorWrite, "applyColorWrite", true);
oc.write(applyBlendMode, "applyBlendMode", true);
oc.write(applyAlphaTest, "applyAlphaTest", true);
oc.write(applyPointSprite, "applyPointSprite", true);
oc.write(applyWireFrame, "applyWireFrame", true);
oc.write(applyCullMode, "applyCullMode", true);
oc.write(applyDepthWrite, "applyDepthWrite", true);
oc.write(applyDepthTest, "applyDepthTest", true);
oc.write(applyColorWrite, "applyColorWrite", true);
oc.write(applyBlendMode, "applyBlendMode", true);
oc.write(applyAlphaTest, "applyAlphaTest", true);
oc.write(applyAlphaFallOff, "applyAlphaFallOff", true);
oc.write(applyPolyOffset, "applyPolyOffset", true);
oc.write(applyPolyOffset, "applyPolyOffset", true);
}
public void read(JmeImporter im) throws IOException {
@ -382,17 +366,17 @@ public class RenderState implements Cloneable, Savable {
backStencilDepthPassOperation = ic.readEnum("backStencilDepthPassOperation", StencilOperation.class, StencilOperation.Keep);
frontStencilFunction = ic.readEnum("frontStencilFunction", TestFunction.class, TestFunction.Always);
backStencilFunction = ic.readEnum("backStencilFunction", TestFunction.class, TestFunction.Always);
applyPointSprite = ic.readBoolean("applyPointSprite", true);
applyWireFrame = ic.readBoolean("applyWireFrame", true);
applyCullMode = ic.readBoolean("applyCullMode", true);
applyDepthWrite = ic.readBoolean("applyDepthWrite", true);
applyDepthTest = ic.readBoolean("applyDepthTest", true);
applyColorWrite = ic.readBoolean("applyColorWrite", true);
applyBlendMode = ic.readBoolean("applyBlendMode", true);
applyAlphaTest = ic.readBoolean("applyAlphaTest", true);
applyPointSprite = ic.readBoolean("applyPointSprite", true);
applyWireFrame = ic.readBoolean("applyWireFrame", true);
applyCullMode = ic.readBoolean("applyCullMode", true);
applyDepthWrite = ic.readBoolean("applyDepthWrite", true);
applyDepthTest = ic.readBoolean("applyDepthTest", true);
applyColorWrite = ic.readBoolean("applyColorWrite", true);
applyBlendMode = ic.readBoolean("applyBlendMode", true);
applyAlphaTest = ic.readBoolean("applyAlphaTest", 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.
*
@ -1033,29 +1114,29 @@ public class RenderState implements Cloneable, Savable {
state.offsetFactor = offsetFactor;
state.offsetUnits = offsetUnits;
}
if (additionalState.applyStencilTest){
if (additionalState.applyStencilTest) {
state.stencilTest = additionalState.stencilTest;
state.frontStencilStencilFailOperation = additionalState.frontStencilStencilFailOperation;
state.frontStencilDepthFailOperation = additionalState.frontStencilDepthFailOperation;
state.frontStencilDepthPassOperation = additionalState.frontStencilDepthPassOperation;
state.frontStencilDepthFailOperation = additionalState.frontStencilDepthFailOperation;
state.frontStencilDepthPassOperation = additionalState.frontStencilDepthPassOperation;
state.backStencilStencilFailOperation = additionalState.backStencilStencilFailOperation;
state.backStencilDepthFailOperation = additionalState.backStencilDepthFailOperation;
state.backStencilDepthPassOperation = additionalState.backStencilDepthPassOperation;
state.backStencilDepthFailOperation = additionalState.backStencilDepthFailOperation;
state.backStencilDepthPassOperation = additionalState.backStencilDepthPassOperation;
state.frontStencilFunction = additionalState.frontStencilFunction;
state.backStencilFunction = additionalState.backStencilFunction;
}else{
} else {
state.stencilTest = stencilTest;
state.frontStencilStencilFailOperation = frontStencilStencilFailOperation;
state.frontStencilDepthFailOperation = frontStencilDepthFailOperation;
state.frontStencilDepthPassOperation = frontStencilDepthPassOperation;
state.frontStencilDepthFailOperation = frontStencilDepthFailOperation;
state.frontStencilDepthPassOperation = frontStencilDepthPassOperation;
state.backStencilStencilFailOperation = backStencilStencilFailOperation;
state.backStencilDepthFailOperation = backStencilDepthFailOperation;
state.backStencilDepthPassOperation = backStencilDepthPassOperation;
state.backStencilDepthFailOperation = backStencilDepthFailOperation;
state.backStencilDepthPassOperation = backStencilDepthPassOperation;
state.frontStencilFunction = frontStencilFunction;
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