MPO: implement propagation and add test
This commit is contained in:
parent
ba22487c38
commit
42d76cfd29
@ -35,6 +35,10 @@ import com.jme3.shader.VarType;
|
|||||||
|
|
||||||
public final class MatParamOverride extends MatParam {
|
public final class MatParamOverride extends MatParam {
|
||||||
|
|
||||||
|
public MatParamOverride() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public MatParamOverride(VarType type, String name, Object value) {
|
public MatParamOverride(VarType type, String name, Object value) {
|
||||||
super(type, name, value);
|
super(type, name, value);
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,18 @@ public class Node extends Spatial {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setMatParamOverrideRefresh() {
|
||||||
|
super.setMatParamOverrideRefresh();
|
||||||
|
for (Spatial child : children.getArray()) {
|
||||||
|
if ((child.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.setMatParamOverrideRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateWorldBound(){
|
protected void updateWorldBound(){
|
||||||
super.updateWorldBound();
|
super.updateWorldBound();
|
||||||
@ -243,6 +255,10 @@ public class Node extends Spatial {
|
|||||||
updateWorldLightList();
|
updateWorldLightList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
||||||
|
updateMatParamOverrides();
|
||||||
|
}
|
||||||
|
|
||||||
if ((refreshFlags & RF_TRANSFORM) != 0){
|
if ((refreshFlags & RF_TRANSFORM) != 0){
|
||||||
// combine with parent transforms- same for all spatial
|
// combine with parent transforms- same for all spatial
|
||||||
// subclasses.
|
// subclasses.
|
||||||
@ -350,6 +366,7 @@ public class Node extends Spatial {
|
|||||||
// transform update down the tree-
|
// transform update down the tree-
|
||||||
child.setTransformRefresh();
|
child.setTransformRefresh();
|
||||||
child.setLightListRefresh();
|
child.setLightListRefresh();
|
||||||
|
child.setMatParamOverrideRefresh();
|
||||||
if (logger.isLoggable(Level.FINE)) {
|
if (logger.isLoggable(Level.FINE)) {
|
||||||
logger.log(Level.FINE,"Child ({0}) attached to this node ({1})",
|
logger.log(Level.FINE,"Child ({0}) attached to this node ({1})",
|
||||||
new Object[]{child.getName(), getName()});
|
new Object[]{child.getName(), getName()});
|
||||||
@ -432,6 +449,7 @@ public class Node extends Spatial {
|
|||||||
child.setTransformRefresh();
|
child.setTransformRefresh();
|
||||||
// lights are also inherited from parent
|
// lights are also inherited from parent
|
||||||
child.setLightListRefresh();
|
child.setLightListRefresh();
|
||||||
|
child.setMatParamOverrideRefresh();
|
||||||
|
|
||||||
invalidateUpdateList();
|
invalidateUpdateList();
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
protected static final int RF_TRANSFORM = 0x01, // need light resort + combine transforms
|
protected static final int RF_TRANSFORM = 0x01, // need light resort + combine transforms
|
||||||
RF_BOUND = 0x02,
|
RF_BOUND = 0x02,
|
||||||
RF_LIGHTLIST = 0x04, // changes in light lists
|
RF_LIGHTLIST = 0x04, // changes in light lists
|
||||||
RF_CHILD_LIGHTLIST = 0x08; // some child need geometry update
|
RF_CHILD_LIGHTLIST = 0x08, // some child need geometry update
|
||||||
|
RF_MATPARAM_OVERRIDE = 0x10;
|
||||||
|
|
||||||
protected CullHint cullHint = CullHint.Inherit;
|
protected CullHint cullHint = CullHint.Inherit;
|
||||||
protected BatchHint batchHint = BatchHint.Inherit;
|
protected BatchHint batchHint = BatchHint.Inherit;
|
||||||
@ -133,6 +134,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
*/
|
*/
|
||||||
protected LightList localLights;
|
protected LightList localLights;
|
||||||
protected transient LightList worldLights;
|
protected transient LightList worldLights;
|
||||||
|
|
||||||
|
protected ArrayList<MatParamOverride> localOverrides;
|
||||||
|
protected ArrayList<MatParamOverride> worldOverrides;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This spatial's name.
|
* This spatial's name.
|
||||||
*/
|
*/
|
||||||
@ -200,6 +205,9 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
localLights = new LightList(this);
|
localLights = new LightList(this);
|
||||||
worldLights = new LightList(this);
|
worldLights = new LightList(this);
|
||||||
|
|
||||||
|
localOverrides = new ArrayList<MatParamOverride>();
|
||||||
|
worldOverrides = new ArrayList<MatParamOverride>();
|
||||||
|
|
||||||
refreshFlags |= RF_BOUND;
|
refreshFlags |= RF_BOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,19 +283,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
// to update lights.
|
// to update lights.
|
||||||
Spatial p = parent;
|
Spatial p = parent;
|
||||||
while (p != null) {
|
while (p != null) {
|
||||||
//if (p.refreshFlags != 0) {
|
|
||||||
// any refresh flag is sufficient,
|
|
||||||
// as each propagates to the root Node
|
|
||||||
|
|
||||||
// 2015/2/8:
|
|
||||||
// This is not true, because using e.g. getWorldBound()
|
|
||||||
// or getWorldTransform() activates a "partial refresh"
|
|
||||||
// which does not update the lights but does clear
|
|
||||||
// the refresh flags on the ancestors!
|
|
||||||
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if ((p.refreshFlags & RF_CHILD_LIGHTLIST) != 0) {
|
if ((p.refreshFlags & RF_CHILD_LIGHTLIST) != 0) {
|
||||||
// The parent already has this flag,
|
// The parent already has this flag,
|
||||||
// so must all ancestors.
|
// so must all ancestors.
|
||||||
@ -299,6 +294,19 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setMatParamOverrideRefresh() {
|
||||||
|
refreshFlags |= RF_MATPARAM_OVERRIDE;
|
||||||
|
Spatial p = parent;
|
||||||
|
while (p != null) {
|
||||||
|
if ((p.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.refreshFlags |= RF_MATPARAM_OVERRIDE;
|
||||||
|
p = p.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate that the bounding of this spatial has changed and that
|
* Indicate that the bounding of this spatial has changed and that
|
||||||
* a refresh is required.
|
* a refresh is required.
|
||||||
@ -428,7 +436,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
* @return The list of local material parameter overrides.
|
* @return The list of local material parameter overrides.
|
||||||
*/
|
*/
|
||||||
public ArrayList<MatParamOverride> getLocalOverrides() {
|
public ArrayList<MatParamOverride> getLocalOverrides() {
|
||||||
return null;
|
return localOverrides;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -442,7 +450,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
* @return The list of world material parameter overrides.
|
* @return The list of world material parameter overrides.
|
||||||
*/
|
*/
|
||||||
public ArrayList<MatParamOverride> getWorldOverrides() {
|
public ArrayList<MatParamOverride> getWorldOverrides() {
|
||||||
return null;
|
return worldOverrides;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -576,15 +584,49 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
worldLights.update(localLights, null);
|
worldLights.update(localLights, null);
|
||||||
refreshFlags &= ~RF_LIGHTLIST;
|
refreshFlags &= ~RF_LIGHTLIST;
|
||||||
} else {
|
} else {
|
||||||
if ((parent.refreshFlags & RF_LIGHTLIST) == 0) {
|
assert (parent.refreshFlags & RF_LIGHTLIST) == 0;
|
||||||
worldLights.update(localLights, parent.worldLights);
|
worldLights.update(localLights, parent.worldLights);
|
||||||
refreshFlags &= ~RF_LIGHTLIST;
|
refreshFlags &= ~RF_LIGHTLIST;
|
||||||
} else {
|
|
||||||
assert false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateMatParamOverrides() {
|
||||||
|
refreshFlags &= ~RF_MATPARAM_OVERRIDE;
|
||||||
|
|
||||||
|
worldOverrides.clear();
|
||||||
|
if (parent == null) {
|
||||||
|
worldOverrides.addAll(localOverrides);
|
||||||
|
} else {
|
||||||
|
assert (parent.refreshFlags & RF_MATPARAM_OVERRIDE) == 0;
|
||||||
|
worldOverrides.addAll(localOverrides);
|
||||||
|
worldOverrides.addAll(parent.worldOverrides);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a local material parameter override.
|
||||||
|
*
|
||||||
|
* @param override The override to add.
|
||||||
|
* @see #getLocalOverrides()
|
||||||
|
*/
|
||||||
|
public void addMatParamOverride(MatParamOverride override) {
|
||||||
|
localOverrides.add(override);
|
||||||
|
setMatParamOverrideRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMatParamOverride(MatParamOverride override) {
|
||||||
|
if (worldOverrides.remove(override)) {
|
||||||
|
setMatParamOverrideRefresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearMatParamOverrides() {
|
||||||
|
if (!worldOverrides.isEmpty()) {
|
||||||
|
setMatParamOverrideRefresh();
|
||||||
|
}
|
||||||
|
worldOverrides.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should only be called from updateGeometricState().
|
* Should only be called from updateGeometricState().
|
||||||
* In most cases should not be subclassed.
|
* In most cases should not be subclassed.
|
||||||
@ -859,6 +901,9 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
if ((refreshFlags & RF_BOUND) != 0) {
|
if ((refreshFlags & RF_BOUND) != 0) {
|
||||||
updateWorldBound();
|
updateWorldBound();
|
||||||
}
|
}
|
||||||
|
if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
||||||
|
updateMatParamOverrides();
|
||||||
|
}
|
||||||
|
|
||||||
assert refreshFlags == 0;
|
assert refreshFlags == 0;
|
||||||
}
|
}
|
||||||
@ -1303,6 +1348,9 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
clone.localLights.setOwner(clone);
|
clone.localLights.setOwner(clone);
|
||||||
clone.worldLights.setOwner(clone);
|
clone.worldLights.setOwner(clone);
|
||||||
|
|
||||||
|
clone.worldOverrides = new ArrayList<MatParamOverride>(worldOverrides);
|
||||||
|
clone.localOverrides = new ArrayList<MatParamOverride>(localOverrides);
|
||||||
|
|
||||||
// No need to force cloned to update.
|
// No need to force cloned to update.
|
||||||
// This node already has the refresh flags
|
// This node already has the refresh flags
|
||||||
// set below so it will have to update anyway.
|
// set below so it will have to update anyway.
|
||||||
@ -1443,6 +1491,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
capsule.write(shadowMode, "shadow_mode", ShadowMode.Inherit);
|
capsule.write(shadowMode, "shadow_mode", ShadowMode.Inherit);
|
||||||
capsule.write(localTransform, "transform", Transform.IDENTITY);
|
capsule.write(localTransform, "transform", Transform.IDENTITY);
|
||||||
capsule.write(localLights, "lights", null);
|
capsule.write(localLights, "lights", null);
|
||||||
|
capsule.writeSavableArrayList(localOverrides, "overrides", null);
|
||||||
|
|
||||||
// Shallow clone the controls array to convert its type.
|
// Shallow clone the controls array to convert its type.
|
||||||
capsule.writeSavableArrayList(new ArrayList(controls), "controlsList", null);
|
capsule.writeSavableArrayList(new ArrayList(controls), "controlsList", null);
|
||||||
@ -1466,6 +1515,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|||||||
localLights = (LightList) ic.readSavable("lights", null);
|
localLights = (LightList) ic.readSavable("lights", null);
|
||||||
localLights.setOwner(this);
|
localLights.setOwner(this);
|
||||||
|
|
||||||
|
localOverrides = ic.readSavableArrayList("overrides", null);
|
||||||
|
if (localOverrides == null) {
|
||||||
|
localOverrides = new ArrayList<MatParamOverride>();
|
||||||
|
}
|
||||||
|
worldOverrides = new ArrayList<MatParamOverride>();
|
||||||
|
|
||||||
//changed for backward compatibility with j3o files generated before the AnimControl/SkeletonControl split
|
//changed for backward compatibility with j3o files generated before the AnimControl/SkeletonControl split
|
||||||
//the AnimControl creates the SkeletonControl for old files and add it to the spatial.
|
//the AnimControl creates the SkeletonControl for old files and add it to the spatial.
|
||||||
//The SkeletonControl must be the last in the stack so we add the list of all other control before it.
|
//The SkeletonControl must be the last in the stack so we add the list of all other control before it.
|
||||||
|
174
jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java
Normal file
174
jme3-core/src/test/java/com/jme3/scene/MPOTestUtils.java
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2016 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.scene;
|
||||||
|
|
||||||
|
import com.jme3.material.MatParamOverride;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.shader.VarType;
|
||||||
|
import static com.jme3.shader.VarType.Texture2D;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class MPOTestUtils {
|
||||||
|
|
||||||
|
private static final Camera DUMMY_CAM = new Camera(640, 480);
|
||||||
|
|
||||||
|
private static final SceneGraphVisitor VISITOR = new SceneGraphVisitor() {
|
||||||
|
@Override
|
||||||
|
public void visit(Spatial spatial) {
|
||||||
|
validateSubScene(spatial);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void validateSubScene(Spatial scene) {
|
||||||
|
scene.checkCulling(DUMMY_CAM);
|
||||||
|
|
||||||
|
Set<MatParamOverride> actualOverrides = new HashSet<MatParamOverride>();
|
||||||
|
for (MatParamOverride override : scene.getWorldOverrides()) {
|
||||||
|
actualOverrides.add(override);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<MatParamOverride> expectedOverrides = new HashSet<MatParamOverride>();
|
||||||
|
Spatial current = scene;
|
||||||
|
while (current != null) {
|
||||||
|
for (MatParamOverride override : current.getLocalOverrides()) {
|
||||||
|
expectedOverrides.add(override);
|
||||||
|
}
|
||||||
|
current = current.getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("For " + scene, expectedOverrides, actualOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateScene(Spatial scene) {
|
||||||
|
scene.updateGeometricState();
|
||||||
|
scene.depthFirstTraversal(VISITOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MatParamOverride mpoInt(String name, int value) {
|
||||||
|
return new MatParamOverride(VarType.Int, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MatParamOverride mpoBool(String name, boolean value) {
|
||||||
|
return new MatParamOverride(VarType.Boolean, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MatParamOverride mpoFloat(String name, float value) {
|
||||||
|
return new MatParamOverride(VarType.Float, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MatParamOverride mpoMatrix4Array(String name, Matrix4f[] value) {
|
||||||
|
return new MatParamOverride(VarType.Matrix4Array, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MatParamOverride mpoTexture2D(String name, Texture2D texture) {
|
||||||
|
return new MatParamOverride(VarType.Texture2D, name, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getRefreshFlags(Spatial scene) {
|
||||||
|
try {
|
||||||
|
Field refreshFlagsField = Spatial.class.getDeclaredField("refreshFlags");
|
||||||
|
refreshFlagsField.setAccessible(true);
|
||||||
|
return (Integer) refreshFlagsField.get(scene);
|
||||||
|
} catch (NoSuchFieldException ex) {
|
||||||
|
throw new AssertionError(ex);
|
||||||
|
} catch (SecurityException ex) {
|
||||||
|
throw new AssertionError(ex);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
throw new AssertionError(ex);
|
||||||
|
} catch (IllegalAccessException ex) {
|
||||||
|
throw new AssertionError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpSceneRF(Spatial scene, String indent, boolean last, int refreshFlagsMask) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
sb.append(indent);
|
||||||
|
if (last) {
|
||||||
|
if (!indent.isEmpty()) {
|
||||||
|
sb.append("└─");
|
||||||
|
} else {
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
indent += " ";
|
||||||
|
} else {
|
||||||
|
sb.append("├─");
|
||||||
|
indent += "│ ";
|
||||||
|
}
|
||||||
|
sb.append(scene.getName());
|
||||||
|
int rf = getRefreshFlags(scene) & refreshFlagsMask;
|
||||||
|
if (rf != 0) {
|
||||||
|
sb.append("(");
|
||||||
|
if ((rf & 0x1) != 0) {
|
||||||
|
sb.append("T");
|
||||||
|
}
|
||||||
|
if ((rf & 0x2) != 0) {
|
||||||
|
sb.append("B");
|
||||||
|
}
|
||||||
|
if ((rf & 0x4) != 0) {
|
||||||
|
sb.append("L");
|
||||||
|
}
|
||||||
|
if ((rf & 0x8) != 0) {
|
||||||
|
sb.append("l");
|
||||||
|
}
|
||||||
|
if ((rf & 0x10) != 0) {
|
||||||
|
sb.append("O");
|
||||||
|
}
|
||||||
|
sb.append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scene.getLocalOverrides().isEmpty()) {
|
||||||
|
sb.append(" [MPO]");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(sb);
|
||||||
|
|
||||||
|
if (scene instanceof Node) {
|
||||||
|
Node node = (Node) scene;
|
||||||
|
int childIndex = 0;
|
||||||
|
for (Spatial child : node.getChildren()) {
|
||||||
|
boolean childLast = childIndex == node.getQuantity() - 1;
|
||||||
|
dumpSceneRF(child, indent, childLast, refreshFlagsMask);
|
||||||
|
childIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void dumpSceneRF(Spatial scene, int refreshFlagsMask) {
|
||||||
|
dumpSceneRF(scene, "", true, refreshFlagsMask);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2016 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.scene;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.binary.BinaryExporter;
|
||||||
|
import com.jme3.material.MatParamOverride;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static com.jme3.scene.MPOTestUtils.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import com.jme3.system.TestUtil;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
||||||
|
public class SceneMatParamOverrideTest {
|
||||||
|
|
||||||
|
|
||||||
|
private static Node createDummyScene() {
|
||||||
|
Node scene = new Node("Scene Node");
|
||||||
|
|
||||||
|
Node a = new Node("A");
|
||||||
|
Node b = new Node("B");
|
||||||
|
|
||||||
|
Node c = new Node("C");
|
||||||
|
Node d = new Node("D");
|
||||||
|
|
||||||
|
Node e = new Node("E");
|
||||||
|
Node f = new Node("F");
|
||||||
|
|
||||||
|
Node g = new Node("G");
|
||||||
|
Node h = new Node("H");
|
||||||
|
Node j = new Node("J");
|
||||||
|
|
||||||
|
scene.attachChild(a);
|
||||||
|
scene.attachChild(b);
|
||||||
|
|
||||||
|
a.attachChild(c);
|
||||||
|
a.attachChild(d);
|
||||||
|
|
||||||
|
b.attachChild(e);
|
||||||
|
b.attachChild(f);
|
||||||
|
|
||||||
|
c.attachChild(g);
|
||||||
|
c.attachChild(h);
|
||||||
|
c.attachChild(j);
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_AddAfterAttach() {
|
||||||
|
Node scene = createDummyScene();
|
||||||
|
scene.updateGeometricState();
|
||||||
|
|
||||||
|
Node root = new Node("Root Node");
|
||||||
|
root.updateGeometricState();
|
||||||
|
|
||||||
|
root.attachChild(scene);
|
||||||
|
scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
|
||||||
|
|
||||||
|
validateScene(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_AddBeforeAttach() {
|
||||||
|
Node scene = createDummyScene();
|
||||||
|
scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
|
||||||
|
scene.updateGeometricState();
|
||||||
|
|
||||||
|
Node root = new Node("Root Node");
|
||||||
|
root.updateGeometricState();
|
||||||
|
|
||||||
|
root.attachChild(scene);
|
||||||
|
|
||||||
|
validateScene(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_RemoveBeforeAttach() {
|
||||||
|
Node scene = createDummyScene();
|
||||||
|
scene.updateGeometricState();
|
||||||
|
|
||||||
|
Node root = new Node("Root Node");
|
||||||
|
root.updateGeometricState();
|
||||||
|
|
||||||
|
scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
|
||||||
|
validateScene(scene);
|
||||||
|
|
||||||
|
scene.getChild("A").clearMatParamOverrides();
|
||||||
|
validateScene(scene);
|
||||||
|
|
||||||
|
root.attachChild(scene);
|
||||||
|
validateScene(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_RemoveAfterAttach() {
|
||||||
|
Node scene = createDummyScene();
|
||||||
|
scene.updateGeometricState();
|
||||||
|
|
||||||
|
Node root = new Node("Root Node");
|
||||||
|
root.updateGeometricState();
|
||||||
|
|
||||||
|
scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
|
||||||
|
|
||||||
|
root.attachChild(scene);
|
||||||
|
validateScene(root);
|
||||||
|
|
||||||
|
scene.getChild("A").clearMatParamOverrides();
|
||||||
|
validateScene(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_IdenticalNames() {
|
||||||
|
Node scene = createDummyScene();
|
||||||
|
|
||||||
|
scene.getChild("A").addMatParamOverride(mpoInt("val", 5));
|
||||||
|
scene.getChild("C").addMatParamOverride(mpoInt("val", 7));
|
||||||
|
|
||||||
|
validateScene(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_CloningScene_DoesntCloneMPO() {
|
||||||
|
Node originalScene = createDummyScene();
|
||||||
|
|
||||||
|
originalScene.getChild("A").addMatParamOverride(mpoInt("int", 5));
|
||||||
|
originalScene.getChild("A").addMatParamOverride(mpoBool("bool", true));
|
||||||
|
originalScene.getChild("A").addMatParamOverride(mpoFloat("float", 3.12f));
|
||||||
|
|
||||||
|
Node clonedScene = originalScene.clone(false);
|
||||||
|
|
||||||
|
validateScene(clonedScene);
|
||||||
|
validateScene(originalScene);
|
||||||
|
|
||||||
|
ArrayList<MatParamOverride> clonedOverrides = clonedScene.getChild("A").getLocalOverrides();
|
||||||
|
ArrayList<MatParamOverride> originalOverrides = originalScene.getChild("A").getLocalOverrides();
|
||||||
|
|
||||||
|
assertNotSame(clonedOverrides, originalOverrides);
|
||||||
|
assertEquals(clonedOverrides, originalOverrides);
|
||||||
|
|
||||||
|
for (int i = 0; i < clonedOverrides.size(); i++) {
|
||||||
|
assertSame(clonedOverrides.get(i), originalOverrides.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverrides_SaveAndLoad_KeepsMPOs() {
|
||||||
|
MatParamOverride override = mpoInt("val", 5);
|
||||||
|
Node scene = createDummyScene();
|
||||||
|
scene.getChild("A").addMatParamOverride(override);
|
||||||
|
|
||||||
|
AssetManager assetManager = TestUtil.createAssetManager();
|
||||||
|
Node loadedScene = BinaryExporter.saveAndLoad(assetManager, scene);
|
||||||
|
|
||||||
|
Node root = new Node("Root Node");
|
||||||
|
root.attachChild(loadedScene);
|
||||||
|
validateScene(root);
|
||||||
|
validateScene(scene);
|
||||||
|
|
||||||
|
assertNotSame(override, loadedScene.getChild("A").getLocalOverrides().get(0));
|
||||||
|
assertEquals(override, loadedScene.getChild("A").getLocalOverrides().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
assertEquals(mpoInt("val", 5), mpoInt("val", 5));
|
||||||
|
assertEquals(mpoBool("val", true), mpoBool("val", true));
|
||||||
|
assertNotEquals(mpoInt("val", 5), mpoInt("val", 6));
|
||||||
|
assertNotEquals(mpoInt("val1", 5), mpoInt("val2", 5));
|
||||||
|
assertNotEquals(mpoBool("val", true), mpoInt("val", 1));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user