|
@@ -122,9 +122,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
*/
|
|
|
protected static final int RF_TRANSFORM = 0x01, // need light resort + combine transforms
|
|
|
RF_BOUND = 0x02,
|
|
|
- RF_LIGHTLIST = 0x04, // changes in light lists
|
|
|
- RF_CHILD_LIGHTLIST = 0x08; // some child need geometry update
|
|
|
-
|
|
|
+ RF_LIGHTLIST = 0x04, // changes in light lists
|
|
|
+ RF_CHILD_LIGHTLIST = 0x08, // some child need geometry update
|
|
|
+ RF_MATPARAM_OVERRIDE = 0x10;
|
|
|
+
|
|
|
protected CullHint cullHint = CullHint.Inherit;
|
|
|
protected BatchHint batchHint = BatchHint.Inherit;
|
|
|
/**
|
|
@@ -136,7 +137,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
*/
|
|
|
protected LightList localLights;
|
|
|
protected transient LightList worldLights;
|
|
|
- /**
|
|
|
+ protected ArrayList<MatParamOverride> localOverrides;
|
|
|
+ protected ArrayList<MatParamOverride> worldOverrides;
|
|
|
+
|
|
|
+ /**
|
|
|
* This spatial's name.
|
|
|
*/
|
|
|
protected String name;
|
|
@@ -196,13 +200,14 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
*/
|
|
|
protected Spatial(String name) {
|
|
|
this.name = name;
|
|
|
-
|
|
|
localTransform = new Transform();
|
|
|
worldTransform = new Transform();
|
|
|
|
|
|
localLights = new LightList(this);
|
|
|
worldLights = new LightList(this);
|
|
|
|
|
|
+ localOverrides = new ArrayList<MatParamOverride>();
|
|
|
+ worldOverrides = new ArrayList<MatParamOverride>();
|
|
|
refreshFlags |= RF_BOUND;
|
|
|
}
|
|
|
|
|
@@ -223,7 +228,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
boolean requiresUpdates() {
|
|
|
return requiresUpdates | !controls.isEmpty();
|
|
|
}
|
|
|
-
|
|
|
/**
|
|
|
* Subclasses can call this with true to denote that they require
|
|
|
* updateLogicalState() to be called even if they contain no controls.
|
|
@@ -273,35 +277,32 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
|
|
|
protected void setLightListRefresh() {
|
|
|
refreshFlags |= RF_LIGHTLIST;
|
|
|
-
|
|
|
// Make sure next updateGeometricState() visits this branch
|
|
|
// to update lights.
|
|
|
Spatial p = parent;
|
|
|
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) {
|
|
|
// The parent already has this flag,
|
|
|
// so must all ancestors.
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
p.refreshFlags |= RF_CHILD_LIGHTLIST;
|
|
|
p = p.parent;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ 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
|
|
|
* a refresh is required.
|
|
@@ -319,7 +320,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
p = p.parent;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
/**
|
|
|
* (Internal use only) Forces a refresh of the given types of data.
|
|
|
*
|
|
@@ -431,7 +431,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
* @return The list of local material parameter overrides.
|
|
|
*/
|
|
|
public ArrayList<MatParamOverride> getLocalOverrides() {
|
|
|
- return null;
|
|
|
+ return localOverrides;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -445,7 +445,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
* @return The list of world material parameter overrides.
|
|
|
*/
|
|
|
public ArrayList<MatParamOverride> getWorldOverrides() {
|
|
|
- return null;
|
|
|
+ return worldOverrides;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -549,10 +549,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
TempVars vars = TempVars.get();
|
|
|
|
|
|
Vector3f compVecA = vars.vect4;
|
|
|
-
|
|
|
compVecA.set(position).subtractLocal(worldTranslation);
|
|
|
getLocalRotation().lookAt(compVecA, upVector);
|
|
|
-
|
|
|
if ( getParent() != null ) {
|
|
|
Quaternion rot=vars.quat1;
|
|
|
rot = rot.set(parent.getWorldRotation()).inverseLocal().multLocal(getLocalRotation());
|
|
@@ -579,15 +577,49 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
worldLights.update(localLights, null);
|
|
|
refreshFlags &= ~RF_LIGHTLIST;
|
|
|
} else {
|
|
|
- if ((parent.refreshFlags & RF_LIGHTLIST) == 0) {
|
|
|
- worldLights.update(localLights, parent.worldLights);
|
|
|
- refreshFlags &= ~RF_LIGHTLIST;
|
|
|
- } else {
|
|
|
- assert false;
|
|
|
- }
|
|
|
+ assert (parent.refreshFlags & RF_LIGHTLIST) == 0;
|
|
|
+ worldLights.update(localLights, parent.worldLights);
|
|
|
+ refreshFlags &= ~RF_LIGHTLIST;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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().
|
|
|
* In most cases should not be subclassed.
|
|
@@ -720,7 +752,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
controls.add(control);
|
|
|
control.setSpatial(this);
|
|
|
boolean after = requiresUpdates();
|
|
|
-
|
|
|
// If the requirement to be updated has changed
|
|
|
// then we need to let the parent node know so it
|
|
|
// can rebuild its update list.
|
|
@@ -744,7 +775,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
}
|
|
|
}
|
|
|
boolean after = requiresUpdates();
|
|
|
-
|
|
|
// If the requirement to be updated has changed
|
|
|
// then we need to let the parent node know so it
|
|
|
// can rebuild its update list.
|
|
@@ -770,14 +800,12 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
}
|
|
|
|
|
|
boolean after = requiresUpdates();
|
|
|
-
|
|
|
// If the requirement to be updated has changed
|
|
|
// then we need to let the parent node know so it
|
|
|
// can rebuild its update list.
|
|
|
if( parent != null && before != after ) {
|
|
|
parent.invalidateUpdateList();
|
|
|
}
|
|
|
-
|
|
|
return result;
|
|
|
}
|
|
|
|
|
@@ -862,7 +890,10 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
if ((refreshFlags & RF_BOUND) != 0) {
|
|
|
updateWorldBound();
|
|
|
}
|
|
|
-
|
|
|
+ if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
|
|
+ updateMatParamOverrides();
|
|
|
+ }
|
|
|
+
|
|
|
assert refreshFlags == 0;
|
|
|
}
|
|
|
|
|
@@ -1336,6 +1367,8 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
clone.localLights.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.
|
|
|
// This node already has the refresh flags
|
|
|
// set below so it will have to update anyway.
|
|
@@ -1539,6 +1572,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
capsule.write(shadowMode, "shadow_mode", ShadowMode.Inherit);
|
|
|
capsule.write(localTransform, "transform", Transform.IDENTITY);
|
|
|
capsule.write(localLights, "lights", null);
|
|
|
+ capsule.writeSavableArrayList(localOverrides, "overrides", null);
|
|
|
|
|
|
// Shallow clone the controls array to convert its type.
|
|
|
capsule.writeSavableArrayList(new ArrayList(controls), "controlsList", null);
|
|
@@ -1562,6 +1596,11 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
|
|
localLights = (LightList) ic.readSavable("lights", null);
|
|
|
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
|
|
|
//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.
|