Merge branch 'master' of https://github.com/jMonkeyEngine/jmonkeyengine.git
This commit is contained in:
commit
fa3ea41a8d
@ -8,7 +8,7 @@ apply plugin: 'maven'
|
|||||||
group = 'org.jmonkeyengine'
|
group = 'org.jmonkeyengine'
|
||||||
version = jmePomVersion
|
version = jmePomVersion
|
||||||
|
|
||||||
sourceCompatibility = '1.6'
|
sourceCompatibility = '1.7'
|
||||||
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -11,7 +11,6 @@ jmeVersionTagID = 0
|
|||||||
buildJavaDoc = true
|
buildJavaDoc = true
|
||||||
|
|
||||||
# specify if SDK and Native libraries get built
|
# specify if SDK and Native libraries get built
|
||||||
buildSdkProject = true
|
|
||||||
buildNativeProjects = false
|
buildNativeProjects = false
|
||||||
buildAndroidExamples = false
|
buildAndroidExamples = false
|
||||||
|
|
||||||
|
@ -430,7 +430,7 @@ public class AndroidTouchInput implements TouchInput {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(Level.INFO, "event: {0}", event);
|
//logger.log(Level.INFO, "event: {0}", event);
|
||||||
|
|
||||||
inputEventQueue.add(event);
|
inputEventQueue.add(event);
|
||||||
if (event instanceof TouchEvent) {
|
if (event instanceof TouchEvent) {
|
||||||
|
@ -146,7 +146,6 @@ public class Face implements Comparator<Integer> {
|
|||||||
/**
|
/**
|
||||||
* @return current indexes of the face (if it is already triangulated then more than one index group will be in the result list)
|
* @return current indexes of the face (if it is already triangulated then more than one index group will be in the result list)
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public List<List<Integer>> getCurrentIndexes() {
|
public List<List<Integer>> getCurrentIndexes() {
|
||||||
if (triangulatedFaces == null) {
|
if (triangulatedFaces == null) {
|
||||||
return Arrays.asList(indexes.getAll());
|
return Arrays.asList(indexes.getAll());
|
||||||
|
@ -286,30 +286,33 @@ public class MeshHelper extends AbstractBlenderHelper {
|
|||||||
List<Map<String, Float>> result = new ArrayList<Map<String, Float>>();
|
List<Map<String, Float>> result = new ArrayList<Map<String, Float>>();
|
||||||
|
|
||||||
Structure parent = blenderContext.peekParent();
|
Structure parent = blenderContext.peekParent();
|
||||||
Structure defbase = (Structure) parent.getFieldValue("defbase");
|
if(parent != null) {
|
||||||
List<String> groupNames = new ArrayList<String>();
|
// the mesh might be saved without its parent (it is then unused)
|
||||||
List<Structure> defs = defbase.evaluateListBase();
|
Structure defbase = (Structure) parent.getFieldValue("defbase");
|
||||||
for (Structure def : defs) {
|
List<String> groupNames = new ArrayList<String>();
|
||||||
groupNames.add(def.getFieldValue("name").toString());
|
List<Structure> defs = defbase.evaluateListBase();
|
||||||
}
|
for (Structure def : defs) {
|
||||||
|
groupNames.add(def.getFieldValue("name").toString());
|
||||||
|
}
|
||||||
|
|
||||||
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
|
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
|
||||||
if (pDvert.isNotNull()) {// assigning weights and bone indices
|
if (pDvert.isNotNull()) {// assigning weights and bone indices
|
||||||
List<Structure> dverts = pDvert.fetchData();
|
List<Structure> dverts = pDvert.fetchData();
|
||||||
for (Structure dvert : dverts) {
|
for (Structure dvert : dverts) {
|
||||||
Map<String, Float> weightsForVertex = new HashMap<String, Float>();
|
Map<String, Float> weightsForVertex = new HashMap<String, Float>();
|
||||||
Pointer pDW = (Pointer) dvert.getFieldValue("dw");
|
Pointer pDW = (Pointer) dvert.getFieldValue("dw");
|
||||||
if (pDW.isNotNull()) {
|
if (pDW.isNotNull()) {
|
||||||
List<Structure> dw = pDW.fetchData();
|
List<Structure> dw = pDW.fetchData();
|
||||||
for (Structure deformWeight : dw) {
|
for (Structure deformWeight : dw) {
|
||||||
int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue();
|
int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue();
|
||||||
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
|
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
|
||||||
String groupName = groupNames.get(groupIndex);
|
String groupName = groupNames.get(groupIndex);
|
||||||
|
|
||||||
weightsForVertex.put(groupName, weight);
|
weightsForVertex.put(groupName, weight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
result.add(weightsForVertex);
|
||||||
}
|
}
|
||||||
result.add(weightsForVertex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -41,6 +41,8 @@ import com.jme3.math.Vector3f;
|
|||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,7 +51,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractPhysicsControl implements PhysicsControl {
|
public abstract class AbstractPhysicsControl implements PhysicsControl, JmeCloneable {
|
||||||
|
|
||||||
private final Quaternion tmp_inverseWorldRotation = new Quaternion();
|
private final Quaternion tmp_inverseWorldRotation = new Quaternion();
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
@ -161,6 +163,12 @@ public abstract class AbstractPhysicsControl implements PhysicsControl {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
createSpatialData(this.spatial);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
if (this.spatial != null && this.spatial != spatial) {
|
if (this.spatial != null && this.spatial != spatial) {
|
||||||
removeSpatialData(this.spatial);
|
removeSpatialData(this.spatial);
|
||||||
|
@ -50,6 +50,8 @@ import com.jme3.renderer.ViewPort;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -68,7 +70,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public class BetterCharacterControl extends AbstractPhysicsControl implements PhysicsTickListener {
|
public class BetterCharacterControl extends AbstractPhysicsControl implements PhysicsTickListener, JmeCloneable {
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(BetterCharacterControl.class.getName());
|
protected static final Logger logger = Logger.getLogger(BetterCharacterControl.class.getName());
|
||||||
protected PhysicsRigidBody rigidBody;
|
protected PhysicsRigidBody rigidBody;
|
||||||
@ -663,12 +665,21 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
|
|||||||
rigidBody.setUserObject(null);
|
rigidBody.setUserObject(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);
|
BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);
|
||||||
control.setJumpForce(jumpForce);
|
control.setJumpForce(jumpForce);
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);
|
||||||
|
control.setJumpForce(jumpForce);
|
||||||
|
control.spatial = this.spatial;
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
super.write(ex);
|
super.write(ex);
|
||||||
|
@ -44,13 +44,15 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You might want to try <code>BetterCharacterControl</code> as well.
|
* You might want to try <code>BetterCharacterControl</code> as well.
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public class CharacterControl extends PhysicsCharacter implements PhysicsControl {
|
public class CharacterControl extends PhysicsCharacter implements PhysicsControl, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
@ -87,6 +89,7 @@ public class CharacterControl extends PhysicsCharacter implements PhysicsControl
|
|||||||
return spatial.getWorldTranslation();
|
return spatial.getWorldTranslation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
CharacterControl control = new CharacterControl(collisionShape, stepHeight);
|
CharacterControl control = new CharacterControl(collisionShape, stepHeight);
|
||||||
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
||||||
@ -103,6 +106,29 @@ public class CharacterControl extends PhysicsCharacter implements PhysicsControl
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
CharacterControl control = new CharacterControl(collisionShape, stepHeight);
|
||||||
|
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
||||||
|
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
|
||||||
|
control.setCollideWithGroups(getCollideWithGroups());
|
||||||
|
control.setCollisionGroup(getCollisionGroup());
|
||||||
|
control.setFallSpeed(getFallSpeed());
|
||||||
|
control.setGravity(getGravity());
|
||||||
|
control.setJumpSpeed(getJumpSpeed());
|
||||||
|
control.setMaxSlope(getMaxSlope());
|
||||||
|
control.setPhysicsLocation(getPhysicsLocation());
|
||||||
|
control.setUpAxis(getUpAxis());
|
||||||
|
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
|
||||||
|
control.spatial = this.spatial;
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
this.spatial = spatial;
|
this.spatial = spatial;
|
||||||
setUserObject(spatial);
|
setUserObject(spatial);
|
||||||
|
@ -44,6 +44,8 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,7 +53,7 @@ import java.io.IOException;
|
|||||||
* overlaps with other physics objects (e.g. aggro radius).
|
* overlaps with other physics objects (e.g. aggro radius).
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public class GhostControl extends PhysicsGhostObject implements PhysicsControl {
|
public class GhostControl extends PhysicsGhostObject implements PhysicsControl, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
@ -93,6 +95,7 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl {
|
|||||||
return spatial.getWorldRotation();
|
return spatial.getWorldRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
GhostControl control = new GhostControl(collisionShape);
|
GhostControl control = new GhostControl(collisionShape);
|
||||||
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
||||||
@ -105,6 +108,25 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl {
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
GhostControl control = new GhostControl(collisionShape);
|
||||||
|
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
||||||
|
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
|
||||||
|
control.setCollideWithGroups(getCollideWithGroups());
|
||||||
|
control.setCollisionGroup(getCollisionGroup());
|
||||||
|
control.setPhysicsLocation(getPhysicsLocation());
|
||||||
|
control.setPhysicsRotation(getPhysicsRotationMatrix());
|
||||||
|
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
|
||||||
|
control.spatial = this.spatial;
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
this.spatial = spatial;
|
this.spatial = spatial;
|
||||||
setUserObject(spatial);
|
setUserObject(spatial);
|
||||||
|
@ -61,6 +61,8 @@ import com.jme3.scene.Node;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -92,7 +94,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @author Normen Hansen and Rémy Bouquet (Nehon)
|
* @author Normen Hansen and Rémy Bouquet (Nehon)
|
||||||
*/
|
*/
|
||||||
public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener {
|
public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener, JmeCloneable {
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName());
|
protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName());
|
||||||
protected List<RagdollCollisionListener> listeners;
|
protected List<RagdollCollisionListener> listeners;
|
||||||
@ -910,6 +912,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
|
|||||||
public void render(RenderManager rm, ViewPort vp) {
|
public void render(RenderManager rm, ViewPort vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);
|
KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);
|
||||||
control.setMode(mode);
|
control.setMode(mode);
|
||||||
@ -919,6 +922,17 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);
|
||||||
|
control.setMode(mode);
|
||||||
|
control.setRootMass(rootMass);
|
||||||
|
control.setWeightThreshold(weightThreshold);
|
||||||
|
control.setApplyPhysicsLocal(applyLocal);
|
||||||
|
control.spatial = this.spatial;
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
public Vector3f setIKTarget(Bone bone, Vector3f worldPos, int chainLength) {
|
public Vector3f setIKTarget(Bone bone, Vector3f worldPos, int chainLength) {
|
||||||
Vector3f target = worldPos.subtract(targetModel.getWorldTranslation());
|
Vector3f target = worldPos.subtract(targetModel.getWorldTranslation());
|
||||||
ikTargets.put(bone.getName(), target);
|
ikTargets.put(bone.getName(), target);
|
||||||
|
@ -51,13 +51,15 @@ import com.jme3.scene.Spatial;
|
|||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.scene.shape.Box;
|
import com.jme3.scene.shape.Box;
|
||||||
import com.jme3.scene.shape.Sphere;
|
import com.jme3.scene.shape.Sphere;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl {
|
public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
@ -89,6 +91,7 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
|
|||||||
super(shape, mass);
|
super(shape, mass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
|
RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
|
||||||
control.setAngularFactor(getAngularFactor());
|
control.setAngularFactor(getAngularFactor());
|
||||||
@ -115,6 +118,39 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
|
||||||
|
control.setAngularFactor(getAngularFactor());
|
||||||
|
control.setAngularSleepingThreshold(getAngularSleepingThreshold());
|
||||||
|
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
||||||
|
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
|
||||||
|
control.setCollideWithGroups(getCollideWithGroups());
|
||||||
|
control.setCollisionGroup(getCollisionGroup());
|
||||||
|
control.setDamping(getLinearDamping(), getAngularDamping());
|
||||||
|
control.setFriction(getFriction());
|
||||||
|
control.setGravity(getGravity());
|
||||||
|
control.setKinematic(isKinematic());
|
||||||
|
control.setKinematicSpatial(isKinematicSpatial());
|
||||||
|
control.setLinearSleepingThreshold(getLinearSleepingThreshold());
|
||||||
|
control.setPhysicsLocation(getPhysicsLocation(null));
|
||||||
|
control.setPhysicsRotation(getPhysicsRotationMatrix(null));
|
||||||
|
control.setRestitution(getRestitution());
|
||||||
|
|
||||||
|
if (mass > 0) {
|
||||||
|
control.setAngularVelocity(getAngularVelocity());
|
||||||
|
control.setLinearVelocity(getLinearVelocity());
|
||||||
|
}
|
||||||
|
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
|
||||||
|
control.spatial = this.spatial;
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
this.spatial = spatial;
|
this.spatial = spatial;
|
||||||
setUserObject(spatial);
|
setUserObject(spatial);
|
||||||
|
@ -46,6 +46,8 @@ import com.jme3.renderer.ViewPort;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ import java.util.Iterator;
|
|||||||
*
|
*
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public class VehicleControl extends PhysicsVehicle implements PhysicsControl {
|
public class VehicleControl extends PhysicsVehicle implements PhysicsControl, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
@ -106,6 +108,7 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl {
|
|||||||
return spatial.getWorldRotation();
|
return spatial.getWorldRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
VehicleControl control = new VehicleControl(collisionShape, mass);
|
VehicleControl control = new VehicleControl(collisionShape, mass);
|
||||||
control.setAngularFactor(getAngularFactor());
|
control.setAngularFactor(getAngularFactor());
|
||||||
@ -155,6 +158,63 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl {
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
VehicleControl control = new VehicleControl(collisionShape, mass);
|
||||||
|
control.setAngularFactor(getAngularFactor());
|
||||||
|
control.setAngularSleepingThreshold(getAngularSleepingThreshold());
|
||||||
|
control.setAngularVelocity(getAngularVelocity());
|
||||||
|
control.setCcdMotionThreshold(getCcdMotionThreshold());
|
||||||
|
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
|
||||||
|
control.setCollideWithGroups(getCollideWithGroups());
|
||||||
|
control.setCollisionGroup(getCollisionGroup());
|
||||||
|
control.setDamping(getLinearDamping(), getAngularDamping());
|
||||||
|
control.setFriction(getFriction());
|
||||||
|
control.setGravity(getGravity());
|
||||||
|
control.setKinematic(isKinematic());
|
||||||
|
control.setLinearSleepingThreshold(getLinearSleepingThreshold());
|
||||||
|
control.setLinearVelocity(getLinearVelocity());
|
||||||
|
control.setPhysicsLocation(getPhysicsLocation());
|
||||||
|
control.setPhysicsRotation(getPhysicsRotationMatrix());
|
||||||
|
control.setRestitution(getRestitution());
|
||||||
|
|
||||||
|
control.setFrictionSlip(getFrictionSlip());
|
||||||
|
control.setMaxSuspensionTravelCm(getMaxSuspensionTravelCm());
|
||||||
|
control.setSuspensionStiffness(getSuspensionStiffness());
|
||||||
|
control.setSuspensionCompression(tuning.suspensionCompression);
|
||||||
|
control.setSuspensionDamping(tuning.suspensionDamping);
|
||||||
|
control.setMaxSuspensionForce(getMaxSuspensionForce());
|
||||||
|
|
||||||
|
for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) {
|
||||||
|
VehicleWheel wheel = it.next();
|
||||||
|
VehicleWheel newWheel = control.addWheel(wheel.getLocation(), wheel.getDirection(), wheel.getAxle(), wheel.getRestLength(), wheel.getRadius(), wheel.isFrontWheel());
|
||||||
|
newWheel.setFrictionSlip(wheel.getFrictionSlip());
|
||||||
|
newWheel.setMaxSuspensionTravelCm(wheel.getMaxSuspensionTravelCm());
|
||||||
|
newWheel.setSuspensionStiffness(wheel.getSuspensionStiffness());
|
||||||
|
newWheel.setWheelsDampingCompression(wheel.getWheelsDampingCompression());
|
||||||
|
newWheel.setWheelsDampingRelaxation(wheel.getWheelsDampingRelaxation());
|
||||||
|
newWheel.setMaxSuspensionForce(wheel.getMaxSuspensionForce());
|
||||||
|
|
||||||
|
// Copy the wheel spatial reference directly for now. They'll
|
||||||
|
// get fixed up in the cloneFields() method
|
||||||
|
newWheel.setWheelSpatial(wheel.getWheelSpatial());
|
||||||
|
}
|
||||||
|
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
|
||||||
|
|
||||||
|
control.spatial = spatial;
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
|
||||||
|
for( VehicleWheel wheel : wheels ) {
|
||||||
|
Spatial spatial = cloner.clone(wheel.getWheelSpatial());
|
||||||
|
wheel.setWheelSpatial(spatial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
this.spatial = spatial;
|
this.spatial = spatial;
|
||||||
setUserObject(spatial);
|
setUserObject(spatial);
|
||||||
|
@ -70,6 +70,10 @@ public class ConeCollisionShape extends CollisionShape {
|
|||||||
public float getRadius() {
|
public float getRadius() {
|
||||||
return radius;
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
public void write(JmeExporter ex) throws IOException {
|
public void write(JmeExporter ex) throws IOException {
|
||||||
super.write(ex);
|
super.write(ex);
|
||||||
|
@ -38,11 +38,14 @@ import com.jme3.scene.Mesh;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.AbstractControl;
|
import com.jme3.scene.control.AbstractControl;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +68,7 @@ import java.util.Map.Entry;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
public final class AnimControl extends AbstractControl implements Cloneable {
|
public final class AnimControl extends AbstractControl implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skeleton object must contain corresponding data for the targets' weight buffers.
|
* Skeleton object must contain corresponding data for the targets' weight buffers.
|
||||||
@ -108,6 +111,7 @@ public final class AnimControl extends AbstractControl implements Cloneable {
|
|||||||
/**
|
/**
|
||||||
* Internal use only.
|
* Internal use only.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
try {
|
try {
|
||||||
AnimControl clone = (AnimControl) super.clone();
|
AnimControl clone = (AnimControl) super.clone();
|
||||||
@ -130,6 +134,32 @@ public final class AnimControl extends AbstractControl implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
AnimControl clone = (AnimControl) super.jmeClone();
|
||||||
|
clone.channels = new ArrayList<AnimChannel>();
|
||||||
|
clone.listeners = new ArrayList<AnimEventListener>();
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
super.cloneFields(cloner, original);
|
||||||
|
|
||||||
|
this.skeleton = cloner.clone(skeleton);
|
||||||
|
|
||||||
|
// Note cloneForSpatial() never actually cloned the animation map... just its reference
|
||||||
|
HashMap<String, Animation> newMap = new HashMap<>();
|
||||||
|
|
||||||
|
// animationMap is cloned, but only ClonableTracks will be cloned as they need a reference to a cloned spatial
|
||||||
|
for( Map.Entry<String, Animation> e : animationMap.entrySet() ) {
|
||||||
|
newMap.put(e.getKey(), cloner.clone(e.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.animationMap = newMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param animations Set the animations that this <code>AnimControl</code>
|
* @param animations Set the animations that this <code>AnimControl</code>
|
||||||
* will be capable of playing. The animations should be compatible
|
* will be capable of playing. The animations should be compatible
|
||||||
|
@ -35,6 +35,8 @@ import com.jme3.export.*;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.util.SafeArrayList;
|
import com.jme3.util.SafeArrayList;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,7 +44,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
|
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
|
||||||
*/
|
*/
|
||||||
public class Animation implements Savable, Cloneable {
|
public class Animation implements Savable, Cloneable, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the animation.
|
* The name of the animation.
|
||||||
@ -190,6 +192,33 @@ public class Animation implements Savable, Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
|
||||||
|
// There is some logic here that I'm copying but I'm not sure if
|
||||||
|
// it's a mistake or not. If a track is not a CloneableTrack then it
|
||||||
|
// isn't cloned at all... even though they all implement clone() methods. -pspeed
|
||||||
|
SafeArrayList<Track> newTracks = new SafeArrayList<>(Track.class);
|
||||||
|
for( Track track : tracks ) {
|
||||||
|
if( track instanceof ClonableTrack ) {
|
||||||
|
newTracks.add(cloner.clone(track));
|
||||||
|
} else {
|
||||||
|
// this is the part that seems fishy
|
||||||
|
newTracks.add(track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tracks = newTracks;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']';
|
return getClass().getSimpleName() + "[name=" + name + ", length=" + length + ']';
|
||||||
|
@ -39,6 +39,8 @@ import com.jme3.export.OutputCapsule;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -174,6 +176,7 @@ public class AudioTrack implements ClonableTrack {
|
|||||||
* @param spatial the Spatial holding the AnimControl
|
* @param spatial the Spatial holding the AnimControl
|
||||||
* @return the cloned Track with proper reference
|
* @return the cloned Track with proper reference
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Track cloneForSpatial(Spatial spatial) {
|
public Track cloneForSpatial(Spatial spatial) {
|
||||||
AudioTrack audioTrack = new AudioTrack();
|
AudioTrack audioTrack = new AudioTrack();
|
||||||
audioTrack.length = this.length;
|
audioTrack.length = this.length;
|
||||||
@ -192,7 +195,27 @@ public class AudioTrack implements ClonableTrack {
|
|||||||
return audioTrack;
|
return audioTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
// Duplicating the old cloned state from cloneForSpatial()
|
||||||
|
this.initialized = false;
|
||||||
|
this.started = false;
|
||||||
|
this.played = false;
|
||||||
|
this.audio = cloner.clone(audio);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
* recursive function responsible for finding the newly cloned AudioNode
|
* recursive function responsible for finding the newly cloned AudioNode
|
||||||
*
|
*
|
||||||
* @param spat
|
* @param spat
|
||||||
|
@ -139,11 +139,7 @@ public final class Bone implements Savable {
|
|||||||
/**
|
/**
|
||||||
* Special-purpose copy constructor.
|
* Special-purpose copy constructor.
|
||||||
* <p>
|
* <p>
|
||||||
* Only copies the name and bind pose from the original.
|
* Only copies the name, user control state and bind pose transforms from the original.
|
||||||
* <p>
|
|
||||||
* WARNING: Local bind pose and world inverse bind pose transforms shallow
|
|
||||||
* copied. Modifying that data on the original bone will cause it to
|
|
||||||
* be recomputed on any cloned bones.
|
|
||||||
* <p>
|
* <p>
|
||||||
* The rest of the data is <em>NOT</em> copied, as it will be
|
* The rest of the data is <em>NOT</em> copied, as it will be
|
||||||
* generated automatically when the bone is animated.
|
* generated automatically when the bone is animated.
|
||||||
@ -155,13 +151,13 @@ public final class Bone implements Savable {
|
|||||||
|
|
||||||
userControl = source.userControl;
|
userControl = source.userControl;
|
||||||
|
|
||||||
bindPos = source.bindPos;
|
bindPos = source.bindPos.clone();
|
||||||
bindRot = source.bindRot;
|
bindRot = source.bindRot.clone();
|
||||||
bindScale = source.bindScale;
|
bindScale = source.bindScale.clone();
|
||||||
|
|
||||||
modelBindInversePos = source.modelBindInversePos;
|
modelBindInversePos = source.modelBindInversePos.clone();
|
||||||
modelBindInverseRot = source.modelBindInverseRot;
|
modelBindInverseRot = source.modelBindInverseRot.clone();
|
||||||
modelBindInverseScale = source.modelBindInverseScale;
|
modelBindInverseScale = source.modelBindInverseScale.clone();
|
||||||
|
|
||||||
// parent and children will be assigned manually..
|
// parent and children will be assigned manually..
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
package com.jme3.animation;
|
package com.jme3.animation;
|
||||||
|
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface that allow to clone a Track for a given Spatial.
|
* An interface that allow to clone a Track for a given Spatial.
|
||||||
@ -43,7 +44,7 @@ import com.jme3.scene.Spatial;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
public interface ClonableTrack extends Track {
|
public interface ClonableTrack extends Track, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows to clone the track for a given Spatial.
|
* Allows to clone the track for a given Spatial.
|
||||||
|
@ -44,6 +44,8 @@ import com.jme3.scene.Spatial.CullHint;
|
|||||||
import com.jme3.scene.control.AbstractControl;
|
import com.jme3.scene.control.AbstractControl;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -116,6 +118,22 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
KillParticleControl c = new KillParticleControl();
|
||||||
|
//this control should be removed as it shouldn't have been persisted in the first place
|
||||||
|
//In the quest to find the less hackish solution to achieve this,
|
||||||
|
//making it remove itself from the spatial in the first update loop when loaded was the less bad.
|
||||||
|
c.remove = true;
|
||||||
|
c.spatial = spatial;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
}
|
}
|
||||||
@ -263,6 +281,7 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
* @param spatial the Spatial holding the AnimControl
|
* @param spatial the Spatial holding the AnimControl
|
||||||
* @return the cloned Track with proper reference
|
* @return the cloned Track with proper reference
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Track cloneForSpatial(Spatial spatial) {
|
public Track cloneForSpatial(Spatial spatial) {
|
||||||
EffectTrack effectTrack = new EffectTrack();
|
EffectTrack effectTrack = new EffectTrack();
|
||||||
effectTrack.particlesPerSeconds = this.particlesPerSeconds;
|
effectTrack.particlesPerSeconds = this.particlesPerSeconds;
|
||||||
@ -283,6 +302,21 @@ public class EffectTrack implements ClonableTrack {
|
|||||||
return effectTrack;
|
return effectTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.emitter = cloner.clone(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* recursive function responsible for finding the newly cloned Emitter
|
* recursive function responsible for finding the newly cloned Emitter
|
||||||
*
|
*
|
||||||
|
@ -34,6 +34,8 @@ package com.jme3.animation;
|
|||||||
import com.jme3.export.*;
|
import com.jme3.export.*;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -45,7 +47,7 @@ import java.util.List;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
public final class Skeleton implements Savable {
|
public final class Skeleton implements Savable, JmeCloneable {
|
||||||
|
|
||||||
private Bone[] rootBones;
|
private Bone[] rootBones;
|
||||||
private Bone[] boneList;
|
private Bone[] boneList;
|
||||||
@ -118,6 +120,15 @@ public final class Skeleton implements Savable {
|
|||||||
public Skeleton() {
|
public Skeleton() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
return new Skeleton(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
}
|
||||||
|
|
||||||
private void createSkinningMatrices() {
|
private void createSkinningMatrices() {
|
||||||
skinningMatrixes = new Matrix4f[boneList.length];
|
skinningMatrixes = new Matrix4f[boneList.length];
|
||||||
for (int i = 0; i < skinningMatrixes.length; i++) {
|
for (int i = 0; i < skinningMatrixes.length; i++) {
|
||||||
|
@ -46,6 +46,8 @@ import com.jme3.scene.control.Control;
|
|||||||
import com.jme3.shader.VarType;
|
import com.jme3.shader.VarType;
|
||||||
import com.jme3.util.SafeArrayList;
|
import com.jme3.util.SafeArrayList;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.Buffer;
|
import java.nio.Buffer;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -63,7 +65,7 @@ import java.util.logging.Logger;
|
|||||||
*
|
*
|
||||||
* @author Rémy Bouquet Based on AnimControl by Kirill Vainer
|
* @author Rémy Bouquet Based on AnimControl by Kirill Vainer
|
||||||
*/
|
*/
|
||||||
public class SkeletonControl extends AbstractControl implements Cloneable {
|
public class SkeletonControl extends AbstractControl implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The skeleton of the model.
|
* The skeleton of the model.
|
||||||
@ -345,6 +347,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
Node clonedNode = (Node) spatial;
|
Node clonedNode = (Node) spatial;
|
||||||
SkeletonControl clone = new SkeletonControl();
|
SkeletonControl clone = new SkeletonControl();
|
||||||
@ -385,6 +388,29 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
return super.jmeClone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
super.cloneFields(cloner, original);
|
||||||
|
|
||||||
|
this.skeleton = cloner.clone(skeleton);
|
||||||
|
|
||||||
|
// If the targets were cloned then this will clone them. If the targets
|
||||||
|
// were shared then this will share them.
|
||||||
|
this.targets = cloner.clone(targets);
|
||||||
|
|
||||||
|
// Not automatic set cloning yet
|
||||||
|
Set<Material> newMaterials = new HashSet<Material>();
|
||||||
|
for( Material m : this.materials ) {
|
||||||
|
newMaterials.add(cloner.clone(m));
|
||||||
|
}
|
||||||
|
this.materials = newMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param boneName the name of the bone
|
* @param boneName the name of the bone
|
||||||
|
@ -36,6 +36,8 @@ import com.jme3.export.JmeExporter;
|
|||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
import com.jme3.export.Savable;
|
import com.jme3.export.Savable;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@ -48,7 +50,7 @@ import java.util.ArrayList;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
public class TrackInfo implements Savable {
|
public class TrackInfo implements Savable, JmeCloneable {
|
||||||
|
|
||||||
ArrayList<Track> tracks = new ArrayList<Track>();
|
ArrayList<Track> tracks = new ArrayList<Track>();
|
||||||
|
|
||||||
@ -72,4 +74,18 @@ public class TrackInfo implements Savable {
|
|||||||
public void addTrack(Track track) {
|
public void addTrack(Track track) {
|
||||||
tracks.add(track);
|
tracks.add(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.tracks = cloner.clone(tracks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,8 @@ import com.jme3.renderer.queue.RenderQueue.Bucket;
|
|||||||
import com.jme3.scene.Node;
|
import com.jme3.scene.Node;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <code>StatsView</code> provides a heads-up display (HUD) of various
|
* The <code>StatsView</code> provides a heads-up display (HUD) of various
|
||||||
@ -58,7 +60,7 @@ import com.jme3.scene.control.Control;
|
|||||||
* rootNode.attachChild(statsView);<br/>
|
* rootNode.attachChild(statsView);<br/>
|
||||||
* </code>
|
* </code>
|
||||||
*/
|
*/
|
||||||
public class StatsView extends Node implements Control {
|
public class StatsView extends Node implements Control, JmeCloneable {
|
||||||
|
|
||||||
private BitmapText statText;
|
private BitmapText statText;
|
||||||
private Statistics statistics;
|
private Statistics statistics;
|
||||||
@ -115,10 +117,21 @@ public class StatsView extends Node implements Control {
|
|||||||
//statistics.clearFrame();
|
//statistics.clearFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
return (Control) spatial;
|
return (Control) spatial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,21 +249,23 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
|
|||||||
}
|
}
|
||||||
logger.log(Level.FINE, "Saving ScreenShot to: {0}", file.getAbsolutePath());
|
logger.log(Level.FINE, "Saving ScreenShot to: {0}", file.getAbsolutePath());
|
||||||
|
|
||||||
OutputStream outStream = null;
|
|
||||||
try {
|
try {
|
||||||
outStream = new FileOutputStream(file);
|
writeImageFile(file);
|
||||||
JmeSystem.writeImageFile(outStream, "png", outBuf, width, height);
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.SEVERE, "Error while saving screenshot", ex);
|
logger.log(Level.SEVERE, "Error while saving screenshot", ex);
|
||||||
} finally {
|
}
|
||||||
if (outStream != null){
|
|
||||||
try {
|
|
||||||
outStream.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error while saving screenshot", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by postFrame() once the screen has been captured to outBuf.
|
||||||
|
*/
|
||||||
|
protected void writeImageFile( File file ) throws IOException {
|
||||||
|
OutputStream outStream = new FileOutputStream(file);
|
||||||
|
try {
|
||||||
|
JmeSystem.writeImageFile(outStream, "png", outBuf, width, height);
|
||||||
|
} finally {
|
||||||
|
outStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,7 @@ public class AssetKey<T> implements Savable, Cloneable {
|
|||||||
list.removeLast();
|
list.removeLast();
|
||||||
} else {
|
} else {
|
||||||
list.add("..");
|
list.add("..");
|
||||||
Logger.getLogger(AssetKey.class.getName()).log(Level.SEVERE, "Asset path is outside assetmanager root");
|
Logger.getLogger(AssetKey.class.getName()).log(Level.SEVERE, "Asset path \"{0}\" is outside assetmanager root", path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
list.add(string);
|
list.add(string);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
* Copyright (c) 2009-2012, 2016 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
|
||||||
@ -33,6 +33,7 @@ package com.jme3.audio;
|
|||||||
|
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.asset.AssetNotFoundException;
|
import com.jme3.asset.AssetNotFoundException;
|
||||||
|
import com.jme3.audio.AudioData.DataType;
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.InputCapsule;
|
||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
@ -127,6 +128,17 @@ public class AudioNode extends Node implements AudioSource {
|
|||||||
public AudioNode(AudioData audioData, AudioKey audioKey) {
|
public AudioNode(AudioData audioData, AudioKey audioKey) {
|
||||||
setAudioData(audioData, audioKey);
|
setAudioData(audioData, audioKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>AudioNode</code> with the given audio file.
|
||||||
|
* @param assetManager The asset manager to use to load the audio file
|
||||||
|
* @param name The filename of the audio file
|
||||||
|
* @param type The type. If <code>{@link com.jme3.audio.AudioData.DataType}.Stream</code>, the audio will be streamed gradually from disk,
|
||||||
|
* otherwise it will be buffered (<code>{@link com.jme3.audio.AudioData.DataType}.Buffer</code>)
|
||||||
|
*/
|
||||||
|
public AudioNode(AssetManager assetManager, String name, DataType type) {
|
||||||
|
this(assetManager, name, type == DataType.Stream, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>AudioNode</code> with the given audio file.
|
* Creates a new <code>AudioNode</code> with the given audio file.
|
||||||
@ -139,6 +151,8 @@ public class AudioNode extends Node implements AudioSource {
|
|||||||
* the stream cache is used. When enabled, the audio stream will
|
* the stream cache is used. When enabled, the audio stream will
|
||||||
* be read entirely but not decoded, allowing features such as
|
* be read entirely but not decoded, allowing features such as
|
||||||
* seeking, looping and determining duration.
|
* seeking, looping and determining duration.
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link AudioNode#AudioNode(com.jme3.asset.AssetManager, java.lang.String, com.jme3.audio.AudioData.DataType)} instead
|
||||||
*/
|
*/
|
||||||
public AudioNode(AssetManager assetManager, String name, boolean stream, boolean streamCache) {
|
public AudioNode(AssetManager assetManager, String name, boolean stream, boolean streamCache) {
|
||||||
this.audioKey = new AudioKey(name, stream, streamCache);
|
this.audioKey = new AudioKey(name, stream, streamCache);
|
||||||
@ -152,9 +166,11 @@ public class AudioNode extends Node implements AudioSource {
|
|||||||
* @param name The filename of the audio file
|
* @param name The filename of the audio file
|
||||||
* @param stream If true, the audio will be streamed gradually from disk,
|
* @param stream If true, the audio will be streamed gradually from disk,
|
||||||
* otherwise, it will be buffered.
|
* otherwise, it will be buffered.
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link AudioNode#AudioNode(com.jme3.asset.AssetManager, java.lang.String, com.jme3.audio.AudioData.DataType)} instead
|
||||||
*/
|
*/
|
||||||
public AudioNode(AssetManager assetManager, String name, boolean stream) {
|
public AudioNode(AssetManager assetManager, String name, boolean stream) {
|
||||||
this(assetManager, name, stream, false);
|
this(assetManager, name, stream, true); // Always streamCached
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,7 +183,7 @@ public class AudioNode extends Node implements AudioSource {
|
|||||||
* @deprecated AudioRenderer parameter is ignored.
|
* @deprecated AudioRenderer parameter is ignored.
|
||||||
*/
|
*/
|
||||||
public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name) {
|
public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name) {
|
||||||
this(assetManager, name, false);
|
this(assetManager, name, DataType.Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -175,9 +191,10 @@ public class AudioNode extends Node implements AudioSource {
|
|||||||
*
|
*
|
||||||
* @param assetManager The asset manager to use to load the audio file
|
* @param assetManager The asset manager to use to load the audio file
|
||||||
* @param name The filename of the audio file
|
* @param name The filename of the audio file
|
||||||
|
* @deprecated Use {@link AudioNode#AudioNode(com.jme3.asset.AssetManager, java.lang.String, com.jme3.audio.AudioData.DataType) } instead
|
||||||
*/
|
*/
|
||||||
public AudioNode(AssetManager assetManager, String name) {
|
public AudioNode(AssetManager assetManager, String name) {
|
||||||
this(assetManager, name, false);
|
this(assetManager, name, DataType.Buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AudioRenderer getRenderer() {
|
protected AudioRenderer getRenderer() {
|
||||||
@ -310,6 +327,19 @@ public class AudioNode extends Node implements AudioSource {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Type of the underlying AudioData to see if it's streamed or buffered.
|
||||||
|
* This is a shortcut to getAudioData().getType()
|
||||||
|
* <b>Warning</b>: Can return null!
|
||||||
|
* @return The {@link com.jme3.audio.AudioData.DataType} of the audio node.
|
||||||
|
*/
|
||||||
|
public DataType getType() {
|
||||||
|
if (data == null)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return data.getDataType();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if the audio will keep looping after it is done playing,
|
* @return True if the audio will keep looping after it is done playing,
|
||||||
* otherwise, false.
|
* otherwise, false.
|
||||||
|
@ -47,6 +47,8 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +58,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Nehon
|
* @author Nehon
|
||||||
*/
|
*/
|
||||||
public class MotionEvent extends AbstractCinematicEvent implements Control {
|
public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
protected int currentWayPoint;
|
protected int currentWayPoint;
|
||||||
@ -274,6 +276,7 @@ public class MotionEvent extends AbstractCinematicEvent implements Control {
|
|||||||
* @param spatial
|
* @param spatial
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
MotionEvent control = new MotionEvent(spatial, path);
|
MotionEvent control = new MotionEvent(spatial, path);
|
||||||
control.playState = playState;
|
control.playState = playState;
|
||||||
@ -291,6 +294,31 @@ public class MotionEvent extends AbstractCinematicEvent implements Control {
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
MotionEvent control = new MotionEvent();
|
||||||
|
control.path = path;
|
||||||
|
control.playState = playState;
|
||||||
|
control.currentWayPoint = currentWayPoint;
|
||||||
|
control.currentValue = currentValue;
|
||||||
|
control.direction = direction.clone();
|
||||||
|
control.lookAt = lookAt.clone();
|
||||||
|
control.upVector = upVector.clone();
|
||||||
|
control.rotation = rotation.clone();
|
||||||
|
control.initialDuration = initialDuration;
|
||||||
|
control.speed = speed;
|
||||||
|
control.loopMode = loopMode;
|
||||||
|
control.directionType = directionType;
|
||||||
|
control.spatial = spatial;
|
||||||
|
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPlay() {
|
public void onPlay() {
|
||||||
traveledDistance = 0;
|
traveledDistance = 0;
|
||||||
|
@ -54,6 +54,8 @@ import com.jme3.scene.Geometry;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
import com.jme3.util.TempVars;
|
import com.jme3.util.TempVars;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,7 +110,7 @@ public class ParticleEmitter extends Geometry {
|
|||||||
private transient Vector3f temp = new Vector3f();
|
private transient Vector3f temp = new Vector3f();
|
||||||
private transient Vector3f lastPos;
|
private transient Vector3f lastPos;
|
||||||
|
|
||||||
public static class ParticleEmitterControl implements Control {
|
public static class ParticleEmitterControl implements Control, JmeCloneable {
|
||||||
|
|
||||||
ParticleEmitter parentEmitter;
|
ParticleEmitter parentEmitter;
|
||||||
|
|
||||||
@ -119,11 +121,26 @@ public class ParticleEmitter extends Geometry {
|
|||||||
this.parentEmitter = parentEmitter;
|
this.parentEmitter = parentEmitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
return this; // WARNING: Sets wrong control on spatial. Will be
|
return this; // WARNING: Sets wrong control on spatial. Will be
|
||||||
// fixed automatically by ParticleEmitter.clone() method.
|
// fixed automatically by ParticleEmitter.clone() method.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.parentEmitter = cloner.clone(parentEmitter);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,13 +43,15 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A camera that follows a spatial and can turn around it by dragging the mouse
|
* A camera that follows a spatial and can turn around it by dragging the mouse
|
||||||
* @author nehon
|
* @author nehon
|
||||||
*/
|
*/
|
||||||
public class ChaseCamera implements ActionListener, AnalogListener, Control {
|
public class ChaseCamera implements ActionListener, AnalogListener, Control, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial target = null;
|
protected Spatial target = null;
|
||||||
protected float minVerticalRotation = 0.00f;
|
protected float minVerticalRotation = 0.00f;
|
||||||
@ -567,6 +569,7 @@ public class ChaseCamera implements ActionListener, AnalogListener, Control {
|
|||||||
* @param spatial
|
* @param spatial
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
ChaseCamera cc = new ChaseCamera(cam, spatial, inputManager);
|
ChaseCamera cc = new ChaseCamera(cam, spatial, inputManager);
|
||||||
cc.setMaxDistance(getMaxDistance());
|
cc.setMaxDistance(getMaxDistance());
|
||||||
@ -574,6 +577,23 @@ public class ChaseCamera implements ActionListener, AnalogListener, Control {
|
|||||||
return cc;
|
return cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
ChaseCamera cc = new ChaseCamera(cam, inputManager);
|
||||||
|
cc.target = target;
|
||||||
|
cc.setMaxDistance(getMaxDistance());
|
||||||
|
cc.setMinDistance(getMinDistance());
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.target = cloner.clone(target);
|
||||||
|
computePosition();
|
||||||
|
prevPos = new Vector3f(target.getWorldTranslation());
|
||||||
|
cam.setLocation(pos);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the spacial for the camera control, should only be used internally
|
* Sets the spacial for the camera control, should only be used internally
|
||||||
* @param spatial
|
* @param spatial
|
||||||
|
@ -248,16 +248,45 @@ When arrays can be inserted in J3M files
|
|||||||
if (texKey.isFlipY()) {
|
if (texKey.isFlipY()) {
|
||||||
ret += "Flip ";
|
ret += "Flip ";
|
||||||
}
|
}
|
||||||
if (texVal.getWrap(Texture.WrapAxis.S) == WrapMode.Repeat) {
|
|
||||||
ret += "Repeat ";
|
//Wrap mode
|
||||||
|
ret += getWrapMode(texVal, Texture.WrapAxis.S);
|
||||||
|
ret += getWrapMode(texVal, Texture.WrapAxis.T);
|
||||||
|
ret += getWrapMode(texVal, Texture.WrapAxis.R);
|
||||||
|
|
||||||
|
//Min and Mag filter
|
||||||
|
Texture.MinFilter def = Texture.MinFilter.BilinearNoMipMaps;
|
||||||
|
if(texVal.getImage().hasMipmaps() || texKey.isGenerateMips()){
|
||||||
|
def = Texture.MinFilter.Trilinear;
|
||||||
|
}
|
||||||
|
if(texVal.getMinFilter() != def){
|
||||||
|
ret += "Min" + texVal.getMinFilter().name()+ " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret + texKey.getName();
|
if(texVal.getMagFilter() != Texture.MagFilter.Bilinear){
|
||||||
|
ret += "Mag" + texVal.getMagFilter().name()+ " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret + "\"" + texKey.getName() + "\"";
|
||||||
default:
|
default:
|
||||||
return null; // parameter type not supported in J3M
|
return null; // parameter type not supported in J3M
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getWrapMode(Texture texVal, Texture.WrapAxis axis) {
|
||||||
|
WrapMode mode = WrapMode.EdgeClamp;
|
||||||
|
try{
|
||||||
|
mode = texVal.getWrap(axis);
|
||||||
|
}catch (IllegalArgumentException e){
|
||||||
|
//this axis doesn't exist on the texture
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if(mode != WrapMode.EdgeClamp){
|
||||||
|
return"Wrap"+ mode.name() + "_" + axis.name() + " ";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MatParam clone() {
|
public MatParam clone() {
|
||||||
try {
|
try {
|
||||||
|
@ -401,8 +401,10 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
|
|||||||
viewPort.getCamera().setViewPort(left, right, bottom, top);
|
viewPort.getCamera().setViewPort(left, right, bottom, top);
|
||||||
viewPort.setOutputFrameBuffer(outputBuffer);
|
viewPort.setOutputFrameBuffer(outputBuffer);
|
||||||
viewPort = null;
|
viewPort = null;
|
||||||
|
|
||||||
renderFrameBuffer.dispose();
|
if(renderFrameBuffer != null){
|
||||||
|
renderFrameBuffer.dispose();
|
||||||
|
}
|
||||||
if(depthTexture!=null){
|
if(depthTexture!=null){
|
||||||
depthTexture.getImage().dispose();
|
depthTexture.getImage().dispose();
|
||||||
}
|
}
|
||||||
|
@ -31,14 +31,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.scene;
|
package com.jme3.scene;
|
||||||
|
|
||||||
import com.jme3.export.*;
|
|
||||||
import com.jme3.material.Material;
|
|
||||||
import com.jme3.math.Matrix4f;
|
|
||||||
import com.jme3.math.Vector3f;
|
|
||||||
import com.jme3.scene.mesh.IndexBuffer;
|
|
||||||
import com.jme3.util.SafeArrayList;
|
|
||||||
import com.jme3.util.TempVars;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.Buffer;
|
import java.nio.Buffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -48,13 +40,22 @@ import java.util.Map;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import com.jme3.collision.Collidable;
|
||||||
|
import com.jme3.collision.CollisionResults;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.scene.mesh.IndexBuffer;
|
||||||
|
import com.jme3.util.SafeArrayList;
|
||||||
|
import com.jme3.util.TempVars;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BatchNode holds geometries that are a batched version of all the geometries that are in its sub scenegraph.
|
* BatchNode holds geometries that are a batched version of all the geometries that are in its sub scenegraph.
|
||||||
* There is one geometry per different material in the sub tree.
|
* There is one geometry per different material in the sub tree.
|
||||||
* The geometries are directly attached to the node in the scene graph.
|
* The geometries are directly attached to the node in the scene graph.
|
||||||
* Usage is like any other node except you have to call the {@link #batch()} method once all the geometries have been attached to the sub scene graph and their material set
|
* Usage is like any other node except you have to call the {@link #batch()} method once all the geometries have been attached to the sub scene graph and their material set
|
||||||
* (see todo more automagic for further enhancements)
|
* (see todo more automagic for further enhancements)
|
||||||
* All the geometries that have been batched are set to {@link CullHint#Always} to not render them.
|
* All the geometries that have been batched are set to not be rendered - {@link CullHint} is left intact.
|
||||||
* The sub geometries can be transformed as usual, their transforms are used to update the mesh of the geometryBatch.
|
* The sub geometries can be transformed as usual, their transforms are used to update the mesh of the geometryBatch.
|
||||||
* Sub geoms can be removed but it may be slower than the normal spatial removing
|
* Sub geoms can be removed but it may be slower than the normal spatial removing
|
||||||
* Sub geoms can be added after the batch() method has been called but won't be batched and will just be rendered as normal geometries.
|
* Sub geoms can be added after the batch() method has been called but won't be batched and will just be rendered as normal geometries.
|
||||||
@ -72,7 +73,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
*/
|
*/
|
||||||
protected SafeArrayList<Batch> batches = new SafeArrayList<Batch>(Batch.class);
|
protected SafeArrayList<Batch> batches = new SafeArrayList<Batch>(Batch.class);
|
||||||
/**
|
/**
|
||||||
* a map storing he batches by geometry to quickly acces the batch when updating
|
* a map for storing the batches by geometry to quickly access the batch when updating
|
||||||
*/
|
*/
|
||||||
protected Map<Geometry, Batch> batchesByGeom = new HashMap<Geometry, Batch>();
|
protected Map<Geometry, Batch> batchesByGeom = new HashMap<Geometry, Batch>();
|
||||||
/**
|
/**
|
||||||
@ -115,10 +116,9 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGeoemtryUnassociated(Geometry geom) {
|
public void onGeometryUnassociated(Geometry geom) {
|
||||||
setNeedsFullRebatch(true);
|
setNeedsFullRebatch(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected Matrix4f getTransformMatrix(Geometry g){
|
protected Matrix4f getTransformMatrix(Geometry g){
|
||||||
return g.cachedWorldMat;
|
return g.cachedWorldMat;
|
||||||
@ -166,7 +166,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
*/
|
*/
|
||||||
public void batch() {
|
public void batch() {
|
||||||
doBatch();
|
doBatch();
|
||||||
//we set the batch geometries to ignore transforms to avoid transforms of parent nodes to be applied twice
|
//we set the batch geometries to ignore transforms to avoid transforms of parent nodes to be applied twice
|
||||||
for (Batch batch : batches.getArray()) {
|
for (Batch batch : batches.getArray()) {
|
||||||
batch.geometry.setIgnoreTransform(true);
|
batch.geometry.setIgnoreTransform(true);
|
||||||
batch.geometry.setUserData(UserData.JME_PHYSICSIGNORE, true);
|
batch.geometry.setUserData(UserData.JME_PHYSICSIGNORE, true);
|
||||||
@ -174,10 +174,10 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void doBatch() {
|
protected void doBatch() {
|
||||||
Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();
|
Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();
|
||||||
int nbGeoms = 0;
|
int nbGeoms = 0;
|
||||||
|
|
||||||
gatherGeomerties(matMap, this, needsFullRebatch);
|
gatherGeometries(matMap, this, needsFullRebatch);
|
||||||
if (needsFullRebatch) {
|
if (needsFullRebatch) {
|
||||||
for (Batch batch : batches.getArray()) {
|
for (Batch batch : batches.getArray()) {
|
||||||
batch.geometry.removeFromParent();
|
batch.geometry.removeFromParent();
|
||||||
@ -221,7 +221,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
|
|
||||||
batch.geometry.setMesh(m);
|
batch.geometry.setMesh(m);
|
||||||
batch.geometry.getMesh().updateCounts();
|
batch.geometry.getMesh().updateCounts();
|
||||||
batch.geometry.updateModelBound();
|
batch.geometry.updateModelBound();
|
||||||
batches.add(batch);
|
batches.add(batch);
|
||||||
}
|
}
|
||||||
if (batches.size() > 0) {
|
if (batches.size() > 0) {
|
||||||
@ -271,7 +271,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) {
|
private void gatherGeometries(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) {
|
||||||
|
|
||||||
if (n instanceof Geometry) {
|
if (n instanceof Geometry) {
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
if (child instanceof BatchNode) {
|
if (child instanceof BatchNode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gatherGeomerties(map, child, rebatch);
|
gatherGeometries(map, child, rebatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,7 +319,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isBatch(Spatial s) {
|
public final boolean isBatch(Spatial s) {
|
||||||
for (Batch batch : batches.getArray()) {
|
for (Batch batch : batches.getArray()) {
|
||||||
if (batch.geometry == s) {
|
if (batch.geometry == s) {
|
||||||
return true;
|
return true;
|
||||||
@ -336,9 +336,6 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setMaterial(Material material) {
|
public void setMaterial(Material material) {
|
||||||
// for (Batch batch : batches.values()) {
|
|
||||||
// batch.geometry.setMaterial(material);
|
|
||||||
// }
|
|
||||||
throw new UnsupportedOperationException("Unsupported for now, please set the material on the geoms before batching");
|
throw new UnsupportedOperationException("Unsupported for now, please set the material on the geoms before batching");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,74 +353,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
Batch b = batches.iterator().next();
|
Batch b = batches.iterator().next();
|
||||||
return b.geometry.getMaterial();
|
return b.geometry.getMaterial();
|
||||||
}
|
}
|
||||||
return null;//material;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Sets the material to the a specific batch of this BatchNode
|
|
||||||
// *
|
|
||||||
// *
|
|
||||||
// * @param material the material to use for this geometry
|
|
||||||
// */
|
|
||||||
// public void setMaterial(Material material,int batchIndex) {
|
|
||||||
// if (!batches.isEmpty()) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * Returns the material that is used for the first batch of this BatchNode
|
|
||||||
// *
|
|
||||||
// * use getMaterial(Material material,int batchIndex) to get a material from a specific batch
|
|
||||||
// *
|
|
||||||
// * @return the material that is used for the first batch of this BatchNode
|
|
||||||
// *
|
|
||||||
// * @see #setMaterial(com.jme3.material.Material)
|
|
||||||
// */
|
|
||||||
// public Material getMaterial(int batchIndex) {
|
|
||||||
// if (!batches.isEmpty()) {
|
|
||||||
// Batch b = batches.get(batches.keySet().iterator().next());
|
|
||||||
// return b.geometry.getMaterial();
|
|
||||||
// }
|
|
||||||
// return null;//material;
|
|
||||||
// }
|
|
||||||
@Override
|
|
||||||
public void write(JmeExporter ex) throws IOException {
|
|
||||||
super.write(ex);
|
|
||||||
OutputCapsule oc = ex.getCapsule(this);
|
|
||||||
//
|
|
||||||
// if (material != null) {
|
|
||||||
// oc.write(material.getAssetName(), "materialName", null);
|
|
||||||
// }
|
|
||||||
// oc.write(material, "material", null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(JmeImporter im) throws IOException {
|
|
||||||
super.read(im);
|
|
||||||
InputCapsule ic = im.getCapsule(this);
|
|
||||||
|
|
||||||
|
|
||||||
// material = null;
|
|
||||||
// String matName = ic.readString("materialName", null);
|
|
||||||
// if (matName != null) {
|
|
||||||
// // Material name is set,
|
|
||||||
// // Attempt to load material via J3M
|
|
||||||
// try {
|
|
||||||
// material = im.getAssetManager().loadMaterial(matName);
|
|
||||||
// } catch (AssetNotFoundException ex) {
|
|
||||||
// // Cannot find J3M file.
|
|
||||||
// logger.log(Level.FINE, "Could not load J3M file {0} for Geometry.",
|
|
||||||
// matName);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // If material is NULL, try to load it from the geometry
|
|
||||||
// if (material == null) {
|
|
||||||
// material = (Material) ic.readSavable("material", null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -494,7 +424,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
if (mode != null && mode != listMode) {
|
if (mode != null && mode != listMode) {
|
||||||
throw new UnsupportedOperationException("Cannot combine different"
|
throw new UnsupportedOperationException("Cannot combine different"
|
||||||
+ " primitive types: " + mode + " != " + listMode);
|
+ " primitive types: " + mode + " != " + listMode);
|
||||||
}
|
}
|
||||||
mode = listMode;
|
mode = listMode;
|
||||||
if (mode == Mesh.Mode.Lines) {
|
if (mode == Mesh.Mode.Lines) {
|
||||||
if (lineWidth != 1f && listLineWidth != lineWidth) {
|
if (lineWidth != 1f && listLineWidth != lineWidth) {
|
||||||
@ -510,8 +440,7 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
outMesh.setMode(mode);
|
outMesh.setMode(mode);
|
||||||
outMesh.setLineWidth(lineWidth);
|
outMesh.setLineWidth(lineWidth);
|
||||||
if (totalVerts >= 65536) {
|
if (totalVerts >= 65536) {
|
||||||
// make sure we create an UnsignedInt buffer so
|
// make sure we create an UnsignedInt buffer so we can fit all of the meshes
|
||||||
// we can fit all of the meshes
|
|
||||||
formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedInt;
|
formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedInt;
|
||||||
} else {
|
} else {
|
||||||
formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedShort;
|
formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedShort;
|
||||||
@ -733,7 +662,6 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected class Batch {
|
protected class Batch {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update the batchesByGeom map for this batch with the given List of geometries
|
* update the batchesByGeom map for this batch with the given List of geometries
|
||||||
* @param list
|
* @param list
|
||||||
@ -745,7 +673,11 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Geometry geometry;
|
Geometry geometry;
|
||||||
|
|
||||||
|
public final Geometry getGeometry() {
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setNeedsFullRebatch(boolean needsFullRebatch) {
|
protected void setNeedsFullRebatch(boolean needsFullRebatch) {
|
||||||
@ -771,4 +703,15 @@ public class BatchNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int collideWith(Collidable other, CollisionResults results) {
|
||||||
|
int total = 0;
|
||||||
|
for (Spatial child : children.getArray()){
|
||||||
|
if (!isBatch(child)) {
|
||||||
|
total += child.collideWith(other, results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ public class Geometry extends Spatial {
|
|||||||
if (groupNode != null) {
|
if (groupNode != null) {
|
||||||
// Once the geometry is removed
|
// Once the geometry is removed
|
||||||
// from the parent, the group node needs to be updated.
|
// from the parent, the group node needs to be updated.
|
||||||
groupNode.onGeoemtryUnassociated(this);
|
groupNode.onGeometryUnassociated(this);
|
||||||
groupNode = null;
|
groupNode = null;
|
||||||
|
|
||||||
// change the default to -1 to make error detection easier
|
// change the default to -1 to make error detection easier
|
||||||
|
@ -83,5 +83,5 @@ public abstract class GeometryGroupNode extends Node {
|
|||||||
*
|
*
|
||||||
* @param geom The Geometry which is being unassociated.
|
* @param geom The Geometry which is being unassociated.
|
||||||
*/
|
*/
|
||||||
public abstract void onGeoemtryUnassociated(Geometry geom);
|
public abstract void onGeometryUnassociated(Geometry geom);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ import com.jme3.export.OutputCapsule;
|
|||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +47,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @author Kirill Vainer
|
* @author Kirill Vainer
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractControl implements Control {
|
public abstract class AbstractControl implements Control, JmeCloneable {
|
||||||
|
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
@ -105,6 +107,20 @@ public abstract class AbstractControl implements Control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException( "Can't clone control for spatial", e );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.spatial = cloner.clone(spatial);
|
||||||
|
}
|
||||||
|
|
||||||
public void update(float tpf) {
|
public void update(float tpf) {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
|
@ -86,12 +86,13 @@ public class BillboardControl extends AbstractControl {
|
|||||||
alignment = Alignment.Screen;
|
alignment = Alignment.Screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
// default implementation from AbstractControl is equivalent
|
||||||
BillboardControl control = new BillboardControl();
|
//public Control cloneForSpatial(Spatial spatial) {
|
||||||
control.alignment = this.alignment;
|
// BillboardControl control = new BillboardControl();
|
||||||
control.setSpatial(spatial);
|
// control.alignment = this.alignment;
|
||||||
return control;
|
// control.setSpatial(spatial);
|
||||||
}
|
// return control;
|
||||||
|
//}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
|
@ -136,13 +136,14 @@ public class CameraControl extends AbstractControl {
|
|||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// default implementation from AbstractControl is equivalent
|
||||||
public Control cloneForSpatial(Spatial newSpatial) {
|
//@Override
|
||||||
CameraControl control = new CameraControl(camera, controlDir);
|
//public Control cloneForSpatial(Spatial newSpatial) {
|
||||||
control.setSpatial(newSpatial);
|
// CameraControl control = new CameraControl(camera, controlDir);
|
||||||
control.setEnabled(isEnabled());
|
// control.setSpatial(newSpatial);
|
||||||
return control;
|
// control.setEnabled(isEnabled());
|
||||||
}
|
// return control;
|
||||||
|
//}
|
||||||
private static final String CONTROL_DIR_NAME = "controlDir";
|
private static final String CONTROL_DIR_NAME = "controlDir";
|
||||||
private static final String CAMERA_NAME = "camera";
|
private static final String CAMERA_NAME = "camera";
|
||||||
|
|
||||||
|
@ -167,13 +167,14 @@ public class LightControl extends AbstractControl {
|
|||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// default implementation from AbstractControl is equivalent
|
||||||
public Control cloneForSpatial(Spatial newSpatial) {
|
//@Override
|
||||||
LightControl control = new LightControl(light, controlDir);
|
//public Control cloneForSpatial(Spatial newSpatial) {
|
||||||
control.setSpatial(newSpatial);
|
// LightControl control = new LightControl(light, controlDir);
|
||||||
control.setEnabled(isEnabled());
|
// control.setSpatial(newSpatial);
|
||||||
return control;
|
// control.setEnabled(isEnabled());
|
||||||
}
|
// return control;
|
||||||
|
//}
|
||||||
private static final String CONTROL_DIR_NAME = "controlDir";
|
private static final String CONTROL_DIR_NAME = "controlDir";
|
||||||
private static final String LIGHT_NAME = "light";
|
private static final String LIGHT_NAME = "light";
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ import com.jme3.renderer.ViewPort;
|
|||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Mesh;
|
import com.jme3.scene.Mesh;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +58,7 @@ import java.io.IOException;
|
|||||||
* and will update the spatial's LOD if the camera has moved by a specified
|
* and will update the spatial's LOD if the camera has moved by a specified
|
||||||
* amount.
|
* amount.
|
||||||
*/
|
*/
|
||||||
public class LodControl extends AbstractControl implements Cloneable {
|
public class LodControl extends AbstractControl implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
private float trisPerPixel = 1f;
|
private float trisPerPixel = 1f;
|
||||||
private float distTolerance = 1f;
|
private float distTolerance = 1f;
|
||||||
@ -140,7 +142,16 @@ public class LodControl extends AbstractControl implements Cloneable {
|
|||||||
clone.lastLevel = 0;
|
clone.lastLevel = 0;
|
||||||
clone.numTris = numTris != null ? numTris.clone() : null;
|
clone.numTris = numTris != null ? numTris.clone() : null;
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
LodControl clone = (LodControl)super.jmeClone();
|
||||||
|
clone.lastDistance = 0;
|
||||||
|
clone.lastLevel = 0;
|
||||||
|
clone.numTris = numTris != null ? numTris.clone() : null;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlUpdate(float tpf) {
|
protected void controlUpdate(float tpf) {
|
||||||
|
@ -35,6 +35,8 @@ import com.jme3.app.AppTask;
|
|||||||
import com.jme3.renderer.RenderManager;
|
import com.jme3.renderer.RenderManager;
|
||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -85,6 +87,7 @@ public class UpdateControl extends AbstractControl {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial newSpatial) {
|
public Control cloneForSpatial(Spatial newSpatial) {
|
||||||
UpdateControl control = new UpdateControl();
|
UpdateControl control = new UpdateControl();
|
||||||
control.setSpatial(newSpatial);
|
control.setSpatial(newSpatial);
|
||||||
@ -93,4 +96,15 @@ public class UpdateControl extends AbstractControl {
|
|||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
UpdateControl clone = (UpdateControl)super.jmeClone();
|
||||||
|
|
||||||
|
// This is kind of questionable since the tasks aren't cloned and have
|
||||||
|
// no reference to the new spatial or anything. They'll get run again
|
||||||
|
// but it's not clear to me why that would be desired. I'm doing it
|
||||||
|
// because the old cloneForSpatial() code does. FIXME? -pspeed
|
||||||
|
clone.taskQueue.addAll(taskQueue);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ import com.jme3.scene.control.Control;
|
|||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
import com.jme3.material.MatParam;
|
import com.jme3.material.MatParam;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
@ -106,7 +108,7 @@ public class InstancedNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class InstancedNodeControl implements Control {
|
private static class InstancedNodeControl implements Control, JmeCloneable {
|
||||||
|
|
||||||
private InstancedNode node;
|
private InstancedNode node;
|
||||||
|
|
||||||
@ -124,6 +126,20 @@ public class InstancedNode extends GeometryGroupNode {
|
|||||||
// fixed automatically by InstancedNode.clone() method.
|
// fixed automatically by InstancedNode.clone() method.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
try {
|
||||||
|
return super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning control", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.node = cloner.clone(node);
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial){
|
public void setSpatial(Spatial spatial){
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +345,7 @@ public class InstancedNode extends GeometryGroupNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGeoemtryUnassociated(Geometry geom) {
|
public void onGeometryUnassociated(Geometry geom) {
|
||||||
removeFromInstancedGeometry(geom);
|
removeFromInstancedGeometry(geom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ public class Cylinder extends Mesh {
|
|||||||
*/
|
*/
|
||||||
public void updateGeometry(int axisSamples, int radialSamples,
|
public void updateGeometry(int axisSamples, int radialSamples,
|
||||||
float radius, float radius2, float height, boolean closed, boolean inverted) {
|
float radius, float radius2, float height, boolean closed, boolean inverted) {
|
||||||
this.axisSamples = axisSamples + (closed ? 2 : 0);
|
this.axisSamples = axisSamples;
|
||||||
this.radialSamples = radialSamples;
|
this.radialSamples = radialSamples;
|
||||||
this.radius = radius;
|
this.radius = radius;
|
||||||
this.radius2 = radius2;
|
this.radius2 = radius2;
|
||||||
@ -222,6 +222,7 @@ public class Cylinder extends Mesh {
|
|||||||
// VertexBuffer pvb = getBuffer(Type.Position);
|
// VertexBuffer pvb = getBuffer(Type.Position);
|
||||||
// VertexBuffer nvb = getBuffer(Type.Normal);
|
// VertexBuffer nvb = getBuffer(Type.Normal);
|
||||||
// VertexBuffer tvb = getBuffer(Type.TexCoord);
|
// VertexBuffer tvb = getBuffer(Type.TexCoord);
|
||||||
|
axisSamples += (closed ? 2 : 0);
|
||||||
|
|
||||||
// Vertices
|
// Vertices
|
||||||
int vertCount = axisSamples * (radialSamples + 1) + (closed ? 2 : 0);
|
int vertCount = axisSamples * (radialSamples + 1) + (closed ? 2 : 0);
|
||||||
|
@ -37,6 +37,7 @@ import com.jme3.export.JmeExporter;
|
|||||||
import com.jme3.export.JmeImporter;
|
import com.jme3.export.JmeImporter;
|
||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.material.RenderState;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Vector4f;
|
import com.jme3.math.Vector4f;
|
||||||
import com.jme3.post.Filter;
|
import com.jme3.post.Filter;
|
||||||
@ -44,6 +45,7 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.renderer.queue.RenderQueue;
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
import com.jme3.texture.FrameBuffer;
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +76,9 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
|
|||||||
material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md");
|
material = new Material(manager, "Common/MatDefs/Shadow/PostShadowFilter.j3md");
|
||||||
this.shadowRenderer = shadowRenderer;
|
this.shadowRenderer = shadowRenderer;
|
||||||
this.shadowRenderer.setPostShadowMaterial(material);
|
this.shadowRenderer.setPostShadowMaterial(material);
|
||||||
|
|
||||||
|
//this is legacy setting for shadows with backface shadows
|
||||||
|
this.shadowRenderer.setRenderBackFacesShadows(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -126,7 +131,7 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
|
|||||||
/**
|
/**
|
||||||
* How far the shadows are rendered in the view
|
* How far the shadows are rendered in the view
|
||||||
*
|
*
|
||||||
* @see setShadowZExtend(float zFar)
|
* @see #setShadowZExtend(float zFar)
|
||||||
* @return shadowZExtend
|
* @return shadowZExtend
|
||||||
*/
|
*/
|
||||||
public float getShadowZExtend() {
|
public float getShadowZExtend() {
|
||||||
@ -248,6 +253,46 @@ public abstract class AbstractShadowFilter<T extends AbstractShadowRenderer> ext
|
|||||||
shadowRenderer.setEdgeFilteringMode(filterMode);
|
shadowRenderer.setEdgeFilteringMode(filterMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* !! WARNING !! this parameter is defaulted to true for the ShadowFilter.
|
||||||
|
* Setting it to true, may produce edges artifacts on shadows. *
|
||||||
|
*
|
||||||
|
* Set to true if you want back faces shadows on geometries.
|
||||||
|
* Note that back faces shadows will be blended over dark lighten areas and may produce overly dark lighting.
|
||||||
|
*
|
||||||
|
* Setting this parameter will override this parameter for ALL materials in the scene.
|
||||||
|
* This also will automatically adjust the faceCullMode and the PolyOffset of the pre shadow pass.
|
||||||
|
* You can modify them by using {@link #getPreShadowForcedRenderState()}
|
||||||
|
*
|
||||||
|
* If you want to set it differently for each material in the scene you have to use the ShadowRenderer instead
|
||||||
|
* of the shadow filter.
|
||||||
|
*
|
||||||
|
* @param renderBackFacesShadows true or false.
|
||||||
|
*/
|
||||||
|
public void setRenderBackFacesShadows(Boolean renderBackFacesShadows) {
|
||||||
|
shadowRenderer.setRenderBackFacesShadows(renderBackFacesShadows);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if this filter renders back faces shadows
|
||||||
|
* @return true if this filter renders back faces shadows
|
||||||
|
*/
|
||||||
|
public boolean isRenderBackFacesShadows() {
|
||||||
|
return shadowRenderer.isRenderBackFacesShadows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the pre shadows pass render state.
|
||||||
|
* use it to adjust the RenderState parameters of the pre shadow pass.
|
||||||
|
* Note that this will be overriden if the preShadow technique in the material has a ForcedRenderState
|
||||||
|
* @return the pre shadow render state.
|
||||||
|
*/
|
||||||
|
public RenderState getPreShadowForcedRenderState() {
|
||||||
|
return shadowRenderer.getPreShadowForcedRenderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the the edge filtering mode
|
* returns the the edge filtering mode
|
||||||
*
|
*
|
||||||
|
@ -31,10 +31,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.jme3.shadow;
|
package com.jme3.shadow;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.jme3.asset.AssetManager;
|
import com.jme3.asset.AssetManager;
|
||||||
import com.jme3.export.InputCapsule;
|
import com.jme3.export.InputCapsule;
|
||||||
import com.jme3.export.JmeExporter;
|
import com.jme3.export.JmeExporter;
|
||||||
@ -42,6 +38,7 @@ import com.jme3.export.JmeImporter;
|
|||||||
import com.jme3.export.OutputCapsule;
|
import com.jme3.export.OutputCapsule;
|
||||||
import com.jme3.export.Savable;
|
import com.jme3.export.Savable;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.material.RenderState;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.math.Matrix4f;
|
import com.jme3.math.Matrix4f;
|
||||||
import com.jme3.math.Vector2f;
|
import com.jme3.math.Vector2f;
|
||||||
@ -67,6 +64,10 @@ import com.jme3.texture.Texture.ShadowCompareMode;
|
|||||||
import com.jme3.texture.Texture2D;
|
import com.jme3.texture.Texture2D;
|
||||||
import com.jme3.ui.Picture;
|
import com.jme3.ui.Picture;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* abstract shadow renderer that holds commons feature to have for a shadow
|
* abstract shadow renderer that holds commons feature to have for a shadow
|
||||||
* renderer
|
* renderer
|
||||||
@ -92,6 +93,9 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
|
protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
|
||||||
protected CompareMode shadowCompareMode = CompareMode.Hardware;
|
protected CompareMode shadowCompareMode = CompareMode.Hardware;
|
||||||
protected Picture[] dispPic;
|
protected Picture[] dispPic;
|
||||||
|
protected RenderState forcedRenderState = new RenderState();
|
||||||
|
protected Boolean renderBackFacesShadows;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* true if the fallback material should be used, otherwise false
|
* true if the fallback material should be used, otherwise false
|
||||||
*/
|
*/
|
||||||
@ -181,6 +185,14 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
setShadowCompareMode(shadowCompareMode);
|
setShadowCompareMode(shadowCompareMode);
|
||||||
setEdgeFilteringMode(edgeFilteringMode);
|
setEdgeFilteringMode(edgeFilteringMode);
|
||||||
setShadowIntensity(shadowIntensity);
|
setShadowIntensity(shadowIntensity);
|
||||||
|
initForcedRenderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initForcedRenderState() {
|
||||||
|
forcedRenderState.setFaceCullMode(RenderState.FaceCullMode.Front);
|
||||||
|
forcedRenderState.setColorWrite(false);
|
||||||
|
forcedRenderState.setDepthWrite(true);
|
||||||
|
forcedRenderState.setDepthTest(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -356,9 +368,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
* rendered in the shadow map
|
* rendered in the shadow map
|
||||||
*
|
*
|
||||||
* @param shadowMapIndex the index of the shadow map being rendered
|
* @param shadowMapIndex the index of the shadow map being rendered
|
||||||
* @param sceneOccluders the occluders of the whole scene
|
* @param shadowMapOccluders the list of occluders
|
||||||
* @param sceneReceivers the receivers of the whole scene
|
|
||||||
* @param shadowMapOcculders
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders);
|
protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders);
|
||||||
@ -425,9 +435,11 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
|
|
||||||
renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]);
|
renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]);
|
||||||
renderManager.getRenderer().clearBuffers(true, true, true);
|
renderManager.getRenderer().clearBuffers(true, true, true);
|
||||||
|
renderManager.setForcedRenderState(forcedRenderState);
|
||||||
|
|
||||||
// render shadow casters to shadow map
|
// render shadow casters to shadow map
|
||||||
viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true);
|
viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true);
|
||||||
|
renderManager.setForcedRenderState(null);
|
||||||
}
|
}
|
||||||
boolean debugfrustums = false;
|
boolean debugfrustums = false;
|
||||||
|
|
||||||
@ -535,18 +547,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
private void setMatParams(GeometryList l) {
|
private void setMatParams(GeometryList l) {
|
||||||
//iteration throught all the geometries of the list to gather the materials
|
//iteration throught all the geometries of the list to gather the materials
|
||||||
|
|
||||||
matCache.clear();
|
buildMatCache(l);
|
||||||
for (int i = 0; i < l.size(); i++) {
|
|
||||||
Material mat = l.get(i).getMaterial();
|
|
||||||
//checking if the material has the post technique and adding it to the material cache
|
|
||||||
if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
|
|
||||||
if (!matCache.contains(mat)) {
|
|
||||||
matCache.add(mat);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
needsfallBackMaterial = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//iterating through the mat cache and setting the parameters
|
//iterating through the mat cache and setting the parameters
|
||||||
for (Material mat : matCache) {
|
for (Material mat : matCache) {
|
||||||
@ -566,6 +567,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
if (fadeInfo != null) {
|
if (fadeInfo != null) {
|
||||||
mat.setVector2("FadeInfo", fadeInfo);
|
mat.setVector2("FadeInfo", fadeInfo);
|
||||||
}
|
}
|
||||||
|
if(renderBackFacesShadows != null){
|
||||||
|
mat.setBoolean("BackfaceShadows", renderBackFacesShadows);
|
||||||
|
}
|
||||||
|
|
||||||
setMaterialParameters(mat);
|
setMaterialParameters(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,6 +582,21 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buildMatCache(GeometryList l) {
|
||||||
|
matCache.clear();
|
||||||
|
for (int i = 0; i < l.size(); i++) {
|
||||||
|
Material mat = l.get(i).getMaterial();
|
||||||
|
//checking if the material has the post technique and adding it to the material cache
|
||||||
|
if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
|
||||||
|
if (!matCache.contains(mat)) {
|
||||||
|
matCache.add(mat);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
needsfallBackMaterial = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for internal use only
|
* for internal use only
|
||||||
*/
|
*/
|
||||||
@ -587,7 +607,10 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
|
postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
|
||||||
}
|
}
|
||||||
if (fadeInfo != null) {
|
if (fadeInfo != null) {
|
||||||
postshadowMat.setVector2("FadeInfo", fadeInfo);
|
postshadowMat.setVector2("FadeInfo", fadeInfo);
|
||||||
|
}
|
||||||
|
if(renderBackFacesShadows != null){
|
||||||
|
postshadowMat.setBoolean("BackfaceShadows", renderBackFacesShadows);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -730,6 +753,48 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public void setFlushQueues(boolean flushQueues) {}
|
public void setFlushQueues(boolean flushQueues) {}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the pre shadows pass render state.
|
||||||
|
* use it to adjust the RenderState parameters of the pre shadow pass.
|
||||||
|
* Note that this will be overriden if the preShadow technique in the material has a ForcedRenderState
|
||||||
|
* @return the pre shadow render state.
|
||||||
|
*/
|
||||||
|
public RenderState getPreShadowForcedRenderState() {
|
||||||
|
return forcedRenderState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to true if you want back faces shadows on geometries.
|
||||||
|
* Note that back faces shadows will be blended over dark lighten areas and may produce overly dark lighting.
|
||||||
|
*
|
||||||
|
* Also note that setting this parameter will override this parameter for ALL materials in the scene.
|
||||||
|
* You can alternatively change this parameter on a single material using {@link Material#setBoolean(String, boolean)}
|
||||||
|
*
|
||||||
|
* This also will automatically adjust the faceCullMode and the PolyOffset of the pre shadow pass.
|
||||||
|
* You can modify them by using {@link #getPreShadowForcedRenderState()}
|
||||||
|
*
|
||||||
|
* @param renderBackFacesShadows true or false.
|
||||||
|
*/
|
||||||
|
public void setRenderBackFacesShadows(Boolean renderBackFacesShadows) {
|
||||||
|
this.renderBackFacesShadows = renderBackFacesShadows;
|
||||||
|
if(renderBackFacesShadows) {
|
||||||
|
getPreShadowForcedRenderState().setPolyOffset(5, 3);
|
||||||
|
getPreShadowForcedRenderState().setFaceCullMode(RenderState.FaceCullMode.Back);
|
||||||
|
}else{
|
||||||
|
getPreShadowForcedRenderState().setPolyOffset(0, 0);
|
||||||
|
getPreShadowForcedRenderState().setFaceCullMode(RenderState.FaceCullMode.Front);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if this processor renders back faces shadows
|
||||||
|
* @return true if this processor renders back faces shadows
|
||||||
|
*/
|
||||||
|
public boolean isRenderBackFacesShadows() {
|
||||||
|
return renderBackFacesShadows != null?renderBackFacesShadows:false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* De-serialize this instance, for example when loading from a J3O file.
|
* De-serialize this instance, for example when loading from a J3O file.
|
||||||
*
|
*
|
||||||
|
@ -215,6 +215,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
|
|||||||
@Override
|
@Override
|
||||||
protected void setMaterialParameters(Material material) {
|
protected void setMaterialParameters(Material material) {
|
||||||
material.setColor("Splits", splits);
|
material.setColor("Splits", splits);
|
||||||
|
material.setVector3("LightDir", light.getDirection());
|
||||||
if (fadeInfo != null) {
|
if (fadeInfo != null) {
|
||||||
material.setVector2("FadeInfo", fadeInfo);
|
material.setVector2("FadeInfo", fadeInfo);
|
||||||
}
|
}
|
||||||
@ -224,6 +225,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
|
|||||||
protected void clearMaterialParameters(Material material) {
|
protected void clearMaterialParameters(Material material) {
|
||||||
material.clearParam("Splits");
|
material.clearParam("Splits");
|
||||||
material.clearParam("FadeInfo");
|
material.clearParam("FadeInfo");
|
||||||
|
material.clearParam("LightDir");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,6 +157,8 @@ public abstract class JmeSystemDelegate {
|
|||||||
return false;
|
return false;
|
||||||
} else if (arch.equals("aarch64")) {
|
} else if (arch.equals("aarch64")) {
|
||||||
return true;
|
return true;
|
||||||
|
} else if (arch.equals("armv7") || arch.equals("armv7l")) {
|
||||||
|
return false;
|
||||||
} else if (arch.equals("arm")) {
|
} else if (arch.equals("arm")) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -51,7 +51,6 @@ import java.nio.IntBuffer;
|
|||||||
import java.nio.LongBuffer;
|
import java.nio.LongBuffer;
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -1268,7 +1267,6 @@ public final class BufferUtils {
|
|||||||
System.out.println(store.toString());
|
System.out.println(store.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static final AtomicBoolean loadedMethods = new AtomicBoolean(false);
|
|
||||||
private static Method cleanerMethod = null;
|
private static Method cleanerMethod = null;
|
||||||
private static Method cleanMethod = null;
|
private static Method cleanMethod = null;
|
||||||
private static Method viewedBufferMethod = null;
|
private static Method viewedBufferMethod = null;
|
||||||
@ -1288,31 +1286,23 @@ public final class BufferUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadCleanerMethods() {
|
static {
|
||||||
// If its already true, exit, if not, set it to true.
|
// Oracle JRE / OpenJDK
|
||||||
if (BufferUtils.loadedMethods.getAndSet(true)) {
|
cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
|
||||||
return;
|
cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
|
||||||
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
|
||||||
|
if (viewedBufferMethod == null) {
|
||||||
|
// They changed the name in Java 7 (???)
|
||||||
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
|
||||||
}
|
}
|
||||||
// This could potentially be called many times if used from multiple
|
|
||||||
// threads
|
|
||||||
synchronized (BufferUtils.loadedMethods) {
|
|
||||||
// Oracle JRE / OpenJDK
|
|
||||||
cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
|
|
||||||
cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
|
|
||||||
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
|
|
||||||
if (viewedBufferMethod == null) {
|
|
||||||
// They changed the name in Java 7 (???)
|
|
||||||
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apache Harmony
|
// Apache Harmony
|
||||||
ByteBuffer bb = BufferUtils.createByteBuffer(1);
|
ByteBuffer bb = BufferUtils.createByteBuffer(1);
|
||||||
Class<?> clazz = bb.getClass();
|
Class<?> clazz = bb.getClass();
|
||||||
try {
|
try {
|
||||||
freeMethod = clazz.getMethod("free");
|
freeMethod = clazz.getMethod("free");
|
||||||
} catch (NoSuchMethodException ex) {
|
} catch (NoSuchMethodException ex) {
|
||||||
} catch (SecurityException ex) {
|
} catch (SecurityException ex) {
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1333,8 +1323,6 @@ public final class BufferUtils {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferUtils.loadCleanerMethods();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (freeMethod != null) {
|
if (freeMethod != null) {
|
||||||
freeMethod.invoke(toBeDestroyed);
|
freeMethod.invoke(toBeDestroyed);
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.util.clone;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides custom cloning for a particular object type. Once
|
||||||
|
* registered with the Cloner, this function object will be called twice
|
||||||
|
* for any cloned object that matches the class for which it was registered.
|
||||||
|
* It will first call cloneObject() to shallow clone the object and then call
|
||||||
|
* cloneFields() to deep clone the object's values.
|
||||||
|
*
|
||||||
|
* <p>This two step process is important because this is what allows
|
||||||
|
* circular references in the cloned object graph.</p>
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface CloneFunction<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a shallow clone of the specified object. This is similar
|
||||||
|
* to the JmeCloneable.clone() method in semantics and is the first part
|
||||||
|
* of a two part cloning process. Once the shallow clone is created, it
|
||||||
|
* is cached and CloneFunction.cloneFields() is called. In this way,
|
||||||
|
* the CloneFunction interface can completely take over the JmeCloneable
|
||||||
|
* style cloning for an object that doesn't otherwise implement that interface.
|
||||||
|
*
|
||||||
|
* @param cloner The cloner performing the cloning operation.
|
||||||
|
* @param original The original object that needs to be cloned.
|
||||||
|
*/
|
||||||
|
public T cloneObject( Cloner cloner, T original );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a deep clone of the specified clone's fields. This is similar
|
||||||
|
* to the JmeCloneable.cloneFields() method in semantics and is the second part
|
||||||
|
* of a two part cloning process. Once the shallow clone is created, it
|
||||||
|
* is cached and CloneFunction.cloneFields() is called. In this way,
|
||||||
|
* the CloneFunction interface can completely take over the JmeCloneable
|
||||||
|
* style cloning for an object that doesn't otherwise implement that interface.
|
||||||
|
*
|
||||||
|
* @param cloner The cloner performing the cloning operation.
|
||||||
|
* @param clone The clone previously returned from cloneObject().
|
||||||
|
* @param original The original object that was cloned. This is provided for
|
||||||
|
* the very special case where field cloning needs to refer to
|
||||||
|
* the original object. Mostly the necessary fields should already
|
||||||
|
* be on the clone.
|
||||||
|
*/
|
||||||
|
public void cloneFields( Cloner cloner, T clone, T original );
|
||||||
|
|
||||||
|
}
|
348
jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
Normal file
348
jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.util.clone;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A deep clone utility that provides similar object-graph-preserving
|
||||||
|
* qualities to typical serialization schemes. An internal registry
|
||||||
|
* of cloned objects is kept to be used by other objects in the deep
|
||||||
|
* clone process that implement JmeCloneable.
|
||||||
|
*
|
||||||
|
* <p>By default, objects that do not implement JmeCloneable will
|
||||||
|
* be treated like normal Java Cloneable objects. If the object does
|
||||||
|
* not implement the JmeCloneable or the regular JDK Cloneable interfaces
|
||||||
|
* AND has no special handling defined then an IllegalArgumentException
|
||||||
|
* will be thrown.</p>
|
||||||
|
*
|
||||||
|
* <p>Enhanced object cloning is done in a two step process. First,
|
||||||
|
* the object is cloned using the normal Java clone() method and stored
|
||||||
|
* in the clone registry. After that, if it implements JmeCloneable then
|
||||||
|
* its cloneFields() method is called to deep clone any of the fields.
|
||||||
|
* This two step process has a few benefits. First, it means that objects
|
||||||
|
* can easily have a regular shallow clone implementation just like any
|
||||||
|
* normal Java objects. Second, the deep cloning of fields happens after
|
||||||
|
* creation wich means that the clone is available to future field cloning
|
||||||
|
* to resolve circular references.</p>
|
||||||
|
*
|
||||||
|
* <p>Similar to Java serialization, the handling of specific object
|
||||||
|
* types can be customized. This allows certain objects to be cloned gracefully
|
||||||
|
* even if they aren't normally Cloneable. This can also be used as a
|
||||||
|
* sort of filter to keep certain types of objects from being cloned.
|
||||||
|
* (For example, adding the IdentityCloneFunction for Mesh.class would cause
|
||||||
|
* all mesh instances to be shared with the original object graph.)</p>
|
||||||
|
*
|
||||||
|
* <p>By default, the Cloner registers serveral default clone functions
|
||||||
|
* as follows:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>java.util.ArrayList: ListCloneFunction
|
||||||
|
* <li>java.util.LinkedList: ListCloneFunction
|
||||||
|
* <li>java.util.concurrent.CopyOnWriteArrayList: ListCloneFunction
|
||||||
|
* <li>java.util.Vector: ListCloneFunction
|
||||||
|
* <li>java.util.Stack: ListCloneFunction
|
||||||
|
* <li>com.jme3.util.SafeArrayList: ListCloneFunction
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Usage:</p>
|
||||||
|
* <pre>
|
||||||
|
* // Example 1: using an instantiated, reusable cloner.
|
||||||
|
* Cloner cloner = new Cloner();
|
||||||
|
* Foo fooClone = cloner.clone(foo);
|
||||||
|
* cloner.clearIndex(); // prepare it for reuse
|
||||||
|
* Foo fooClone2 = cloner.clone(foo);
|
||||||
|
*
|
||||||
|
* // Example 2: using the utility method that self-instantiates a temporary cloner.
|
||||||
|
* Foo fooClone = Cloner.deepClone(foo);
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class Cloner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps track of the objects that have been cloned so far.
|
||||||
|
*/
|
||||||
|
private IdentityHashMap<Object, Object> index = new IdentityHashMap<Object, Object>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom functions for cloning objects.
|
||||||
|
*/
|
||||||
|
private Map<Class, CloneFunction> functions = new HashMap<Class, CloneFunction>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache the clone methods once for all cloners.
|
||||||
|
*/
|
||||||
|
private static final Map<Class, Method> methodCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new cloner with only default clone functions and an empty
|
||||||
|
* object index.
|
||||||
|
*/
|
||||||
|
public Cloner() {
|
||||||
|
// Register some standard types
|
||||||
|
ListCloneFunction listFunction = new ListCloneFunction();
|
||||||
|
functions.put(java.util.ArrayList.class, listFunction);
|
||||||
|
functions.put(java.util.LinkedList.class, listFunction);
|
||||||
|
functions.put(java.util.concurrent.CopyOnWriteArrayList.class, listFunction);
|
||||||
|
functions.put(java.util.Vector.class, listFunction);
|
||||||
|
functions.put(java.util.Stack.class, listFunction);
|
||||||
|
functions.put(com.jme3.util.SafeArrayList.class, listFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience utility function that creates a new Cloner, uses it to
|
||||||
|
* deep clone the object, and then returns the result.
|
||||||
|
*/
|
||||||
|
public static <T> T deepClone( T object ) {
|
||||||
|
return new Cloner().clone(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deeps clones the specified object, reusing previous clones when possible.
|
||||||
|
*
|
||||||
|
* <p>Object cloning priority works as follows:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>If the object has already been cloned then its clone is returned.
|
||||||
|
* <li>If there is a custom CloneFunction then it is called to clone the object.
|
||||||
|
* <li>If the object implements Cloneable then its clone() method is called, arrays are
|
||||||
|
* deep cloned with entries passing through clone().
|
||||||
|
* <li>If the object implements JmeCloneable then its cloneFields() method is called on the
|
||||||
|
* clone.
|
||||||
|
* <li>Else an IllegalArgumentException is thrown.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* Note: objects returned by this method may not have yet had their cloneField()
|
||||||
|
* method called.
|
||||||
|
*/
|
||||||
|
public <T> T clone( T object ) {
|
||||||
|
return clone(object, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to work around a Java generics typing issue by
|
||||||
|
* isolating the 'bad' case into a method with suppressed warnings.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> Class<T> objectClass( T object ) {
|
||||||
|
// This should be 100% allowed without a cast but Java generics
|
||||||
|
// is not that smart sometimes.
|
||||||
|
// Wrapping it in a method at least isolates the warning suppression
|
||||||
|
return (Class<T>)object.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deeps clones the specified object, reusing previous clones when possible.
|
||||||
|
*
|
||||||
|
* <p>Object cloning priority works as follows:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>If the object has already been cloned then its clone is returned.
|
||||||
|
* <li>If useFunctions is true and there is a custom CloneFunction then it is
|
||||||
|
* called to clone the object.
|
||||||
|
* <li>If the object implements Cloneable then its clone() method is called, arrays are
|
||||||
|
* deep cloned with entries passing through clone().
|
||||||
|
* <li>If the object implements JmeCloneable then its cloneFields() method is called on the
|
||||||
|
* clone.
|
||||||
|
* <li>Else an IllegalArgumentException is thrown.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>The abililty to selectively use clone functions is useful when
|
||||||
|
* being called from a clone function.</p>
|
||||||
|
*
|
||||||
|
* Note: objects returned by this method may not have yet had their cloneField()
|
||||||
|
* method called.
|
||||||
|
*/
|
||||||
|
public <T> T clone( T object, boolean useFunctions ) {
|
||||||
|
if( object == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Class<T> type = objectClass(object);
|
||||||
|
|
||||||
|
// Check the index to see if we already have it
|
||||||
|
Object clone = index.get(object);
|
||||||
|
if( clone != null ) {
|
||||||
|
return type.cast(clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if there is a custom function... that trumps everything.
|
||||||
|
CloneFunction<T> f = getCloneFunction(type);
|
||||||
|
if( f != null ) {
|
||||||
|
T result = f.cloneObject(this, object);
|
||||||
|
|
||||||
|
// Store the object in the identity map so that any circular references
|
||||||
|
// are resolvable.
|
||||||
|
index.put(object, result);
|
||||||
|
|
||||||
|
// Now call the function again to deep clone the fields
|
||||||
|
f.cloneFields(this, result, object);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( object.getClass().isArray() ) {
|
||||||
|
// Perform an array clone
|
||||||
|
clone = arrayClone(object);
|
||||||
|
|
||||||
|
// Array clone already indexes the clone
|
||||||
|
} else if( object instanceof JmeCloneable ) {
|
||||||
|
// Use the two-step cloning semantics
|
||||||
|
clone = ((JmeCloneable)object).jmeClone();
|
||||||
|
|
||||||
|
// Store the object in the identity map so that any circular references
|
||||||
|
// are resolvable
|
||||||
|
index.put(object, clone);
|
||||||
|
|
||||||
|
((JmeCloneable)clone).cloneFields(this, object);
|
||||||
|
} else if( object instanceof Cloneable ) {
|
||||||
|
|
||||||
|
// Perform a regular Java shallow clone
|
||||||
|
try {
|
||||||
|
clone = javaClone(object);
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new IllegalArgumentException("Object is not cloneable, type:" + type, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the object in the identity map so that any circular references
|
||||||
|
// are resolvable
|
||||||
|
index.put(object, clone);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Object is not cloneable, type:" + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.cast(clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a custom CloneFunction for the exact Java type. Note: no inheritence
|
||||||
|
* checks are performed so a function must be registered for each specific type
|
||||||
|
* that it handles. By default ListCloneFunction is registered for
|
||||||
|
* ArrayList, LinkedList, CopyOnWriteArrayList, Vector, Stack, and JME's SafeArrayList.
|
||||||
|
*/
|
||||||
|
public <T> void setCloneFunction( Class<T> type, CloneFunction<T> function ) {
|
||||||
|
if( function == null ) {
|
||||||
|
functions.remove(type);
|
||||||
|
} else {
|
||||||
|
functions.put(type, function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a previously registered clone function for the specified type or null
|
||||||
|
* if there is no custom clone function for the type.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> CloneFunction<T> getCloneFunction( Class<T> type ) {
|
||||||
|
return (CloneFunction<T>)functions.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the object index allowing the cloner to be reused for a brand new
|
||||||
|
* cloning operation.
|
||||||
|
*/
|
||||||
|
public void clearIndex() {
|
||||||
|
index.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a raw shallow Java clone using reflection. This call does NOT
|
||||||
|
* check against the clone index and so will return new objects every time
|
||||||
|
* it is called. That's because these are shallow clones and have not (and may
|
||||||
|
* not ever, depending on the caller) get resolved.
|
||||||
|
*
|
||||||
|
* <p>This method is provided as a convenient way for CloneFunctions to call
|
||||||
|
* clone() and objects without necessarily knowing their real type.</p>
|
||||||
|
*/
|
||||||
|
public <T> T javaClone( T object ) throws CloneNotSupportedException {
|
||||||
|
Method m = methodCache.get(object.getClass());
|
||||||
|
if( m == null ) {
|
||||||
|
try {
|
||||||
|
// Lookup the method and cache it
|
||||||
|
m = object.getClass().getMethod("clone");
|
||||||
|
} catch( NoSuchMethodException e ) {
|
||||||
|
throw new CloneNotSupportedException("No public clone method found for:" + object.getClass());
|
||||||
|
}
|
||||||
|
methodCache.put(object.getClass(), m);
|
||||||
|
|
||||||
|
// Note: yes we might cache the method twice... but so what?
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<? extends T> type = objectClass(object);
|
||||||
|
return type.cast(m.invoke(object));
|
||||||
|
} catch( IllegalAccessException | InvocationTargetException e ) {
|
||||||
|
throw new RuntimeException("Error cloning object of type:" + object.getClass(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones a primitive array by coping it and clones an object
|
||||||
|
* array by coping it and then running each of its values through
|
||||||
|
* Cloner.clone().
|
||||||
|
*/
|
||||||
|
protected <T> T arrayClone( T object ) {
|
||||||
|
|
||||||
|
// Java doesn't support the cloning of arrays through reflection unless
|
||||||
|
// you open access to Object's protected clone array... which requires
|
||||||
|
// elevated privileges. So we will do a work-around that is slightly less
|
||||||
|
// elegant.
|
||||||
|
// This should be 100% allowed without a case but Java generics
|
||||||
|
// is not that smart
|
||||||
|
Class<T> type = objectClass(object);
|
||||||
|
Class elementType = type.getComponentType();
|
||||||
|
int size = Array.getLength(object);
|
||||||
|
Object clone = Array.newInstance(elementType, size);
|
||||||
|
|
||||||
|
// Store the clone for later lookups
|
||||||
|
index.put(object, clone);
|
||||||
|
|
||||||
|
if( elementType.isPrimitive() ) {
|
||||||
|
// Then our job is a bit easier
|
||||||
|
System.arraycopy(object, 0, clone, 0, size);
|
||||||
|
} else {
|
||||||
|
// Else it's an object array so we'll clone it and its children
|
||||||
|
for( int i = 0; i < size; i++ ) {
|
||||||
|
Object element = clone(Array.get(object, i));
|
||||||
|
Array.set(clone, i, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return type.cast(clone);
|
||||||
|
}
|
||||||
|
}
|
@ -1,63 +1,58 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2010 jMonkeyEngine
|
* Copyright (c) 2016 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.gde.terraineditor;
|
package com.jme3.util.clone;
|
||||||
|
|
||||||
import com.jme3.terrain.heightmap.AbstractHeightMap;
|
|
||||||
|
/**
|
||||||
/**
|
* A CloneFunction implementation that simply returns the
|
||||||
* Very simple heightmap class that is a heightmap of floats that is size*size
|
* the passed object without cloning it. This is useful for
|
||||||
* in size, and has height values of zero.
|
* forcing some object types (like Meshes) to be shared between
|
||||||
*
|
* the original and cloned object graph.
|
||||||
* @author bowens
|
*
|
||||||
*/
|
* @author Paul Speed
|
||||||
public class FlatHeightmap extends AbstractHeightMap {
|
*/
|
||||||
|
public class IdentityCloneFunction<T> implements CloneFunction<T> {
|
||||||
private int size;
|
|
||||||
private float[] heightmapData;
|
/**
|
||||||
|
* Returns the object directly.
|
||||||
public FlatHeightmap(int size) {
|
*/
|
||||||
this.size = size;
|
public T cloneObject( Cloner cloner, T object ) {
|
||||||
}
|
return object;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public boolean load() {
|
/**
|
||||||
heightmapData = new float[size*size];
|
* Does nothing.
|
||||||
return true;
|
*/
|
||||||
}
|
public void cloneFields( Cloner cloner, T clone, T object ) {
|
||||||
|
}
|
||||||
@Override
|
}
|
||||||
public float[] getHeightMap() {
|
|
||||||
return heightmapData;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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.util.clone;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates an object that wishes to more actively participate in the
|
||||||
|
* two-part deep copying process provided by the Cloner. Objects implementing
|
||||||
|
* this interface can access the already cloned object graph to resolve
|
||||||
|
* their local dependencies in a way that will be equivalent to the
|
||||||
|
* original object graph. In other words, if two objects in the graph
|
||||||
|
* share the same target reference then the cloned version will share
|
||||||
|
* the cloned reference.
|
||||||
|
*
|
||||||
|
* <p>For example, if an object wishes to deep clone one of its fields
|
||||||
|
* then it will call cloner.clone(object) instead of object.clone().
|
||||||
|
* The cloner will keep track of any clones already created for 'object'
|
||||||
|
* and return that instead of a new clone.</p>
|
||||||
|
*
|
||||||
|
* <p>Cloning of a JmeCloneable object is done in two parts. First,
|
||||||
|
* the standard Java clone() method is called to create a shallow clone
|
||||||
|
* of the object. Second, the cloner wil lcall the cloneFields() method
|
||||||
|
* to let the object deep clone any of its fields that should be cloned.</p>
|
||||||
|
*
|
||||||
|
* <p>This two part process is necessary to facilitate circular references.
|
||||||
|
* When an object calls cloner.clone() during its cloneFields() method, it
|
||||||
|
* may get only a shallow copy that will be filled in later.</p>
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public interface JmeCloneable extends Cloneable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a regular shallow clone of the object. Some fields
|
||||||
|
* may also be cloned but generally only if they will never be
|
||||||
|
* shared with other objects. (For example, local Vector3fs and so on.)
|
||||||
|
*
|
||||||
|
* <p>This method is separate from the regular clone() method
|
||||||
|
* so that objects might still maintain their own regular java clone()
|
||||||
|
* semantics (perhaps even using Cloner for those methods). However,
|
||||||
|
* because Java's clone() has specific features in the sense of Object's
|
||||||
|
* clone() implementation, it's usually best to have some path for
|
||||||
|
* subclasses to bypass the public clone() method that might be cloning
|
||||||
|
* fields and instead get at the superclass protected clone() methods.
|
||||||
|
* For example, through super.jmeClone() or another protected clone
|
||||||
|
* method that some base class eventually calls super.clone() in.</p>
|
||||||
|
*/
|
||||||
|
public Object jmeClone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented to perform deep cloning for this object, resolving
|
||||||
|
* local cloned references using the specified cloner. The object
|
||||||
|
* can call cloner.clone(fieldValue) to deep clone any of its fields.
|
||||||
|
*
|
||||||
|
* <p>Note: during normal clone operations the original object
|
||||||
|
* will not be needed as the clone has already had all of the fields
|
||||||
|
* shallow copied.</p>
|
||||||
|
*
|
||||||
|
* @param cloner The cloner that is performing the cloning operation. The
|
||||||
|
* cloneFields method can call back into the cloner to make
|
||||||
|
* clones if its subordinate fields.
|
||||||
|
* @param original The original object from which this object was cloned.
|
||||||
|
* This is provided for the very rare case that this object needs
|
||||||
|
* to refer to its original for some reason. In general, all of
|
||||||
|
* the relevant values should have been transferred during the
|
||||||
|
* shallow clone and this object need merely clone what it wants.
|
||||||
|
*/
|
||||||
|
public void cloneFields( Cloner cloner, Object original );
|
||||||
|
}
|
@ -1,55 +1,70 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003-2012 jMonkeyEngine
|
* Copyright (c) 2016 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.gde.core.util;
|
|
||||||
|
package com.jme3.util.clone;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import org.apache.commons.beanutils.BeanUtils;
|
import java.util.List;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
|
/**
|
||||||
/**
|
* A CloneFunction implementation that deep clones a list by
|
||||||
*
|
* creating a new list and cloning its values using the cloner.
|
||||||
* @author normenhansen
|
*
|
||||||
*/
|
* @author Paul Speed
|
||||||
public class Beans {
|
*/
|
||||||
|
public class ListCloneFunction<T extends List> implements CloneFunction<T> {
|
||||||
public static boolean copyProperties(Object dest, Object src) {
|
|
||||||
try {
|
public T cloneObject( Cloner cloner, T object ) {
|
||||||
BeanUtils.copyProperties(dest, src);
|
try {
|
||||||
return true;
|
T clone = cloner.javaClone(object);
|
||||||
} catch (IllegalAccessException ex) {
|
return clone;
|
||||||
Exceptions.printStackTrace(ex);
|
} catch( CloneNotSupportedException e ) {
|
||||||
} catch (InvocationTargetException ex) {
|
throw new IllegalArgumentException("Clone not supported for type:" + object.getClass(), e);
|
||||||
Exceptions.printStackTrace(ex);
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
/**
|
||||||
}
|
* Clones the elements of the list.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void cloneFields( Cloner cloner, T clone, T object ) {
|
||||||
|
for( int i = 0; i < clone.size(); i++ ) {
|
||||||
|
// Need to clone the clones... because T might
|
||||||
|
// have done something special in its clone method that
|
||||||
|
// we will have to adhere to. For example, clone may have nulled
|
||||||
|
// out some things or whatever that might be implementation specific.
|
||||||
|
// At any rate, if it's a proper clone then the clone will already
|
||||||
|
// have shallow versions of the elements that we can clone.
|
||||||
|
clone.set(i, cloner.clone(clone.get(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.util.mikktspace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public interface MikkTSpaceContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of faces (triangles/quads) on the mesh to be
|
||||||
|
* processed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getNumFaces();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of vertices on face number iFace iFace is a number in
|
||||||
|
* the range {0, 1, ..., getNumFaces()-1}
|
||||||
|
*
|
||||||
|
* @param face
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getNumVerticesOfFace(int face);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the position/normal/texcoord of the referenced face of vertex
|
||||||
|
* number iVert. iVert is in the range {0,1,2} for triangles and {0,1,2,3}
|
||||||
|
* for quads.
|
||||||
|
*
|
||||||
|
* @param posOut
|
||||||
|
* @param face
|
||||||
|
* @param vert
|
||||||
|
*/
|
||||||
|
public void getPosition(float posOut[], int face, int vert);
|
||||||
|
|
||||||
|
public void getNormal(float normOut[], int face, int vert);
|
||||||
|
|
||||||
|
public void getTexCoord(float texOut[], int face, int vert);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The call-backsetTSpaceBasic() is sufficient for basic normal mapping.
|
||||||
|
* This function is used to return the tangent and sign to the application.
|
||||||
|
* tangent is a unit length vector. For normal maps it is sufficient to use
|
||||||
|
* the following simplified version of the bitangent which is generated at
|
||||||
|
* pixel/vertex level.
|
||||||
|
*
|
||||||
|
* bitangent = fSign * cross(vN, tangent);
|
||||||
|
*
|
||||||
|
* Note that the results are returned unindexed. It is possible to generate
|
||||||
|
* a new index list But averaging/overwriting tangent spaces by using an
|
||||||
|
* already existing index list WILL produce INCRORRECT results. DO NOT! use
|
||||||
|
* an already existing index list.
|
||||||
|
*
|
||||||
|
* @param tangent
|
||||||
|
* @param sign
|
||||||
|
* @param face
|
||||||
|
* @param vert
|
||||||
|
*/
|
||||||
|
public void setTSpaceBasic(float tangent[], float sign, int face, int vert);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is used to return tangent space results to the application.
|
||||||
|
* tangent and biTangent are unit length vectors and fMagS and fMagT are
|
||||||
|
* their true magnitudes which can be used for relief mapping effects.
|
||||||
|
*
|
||||||
|
* biTangent is the "real" bitangent and thus may not be perpendicular to
|
||||||
|
* tangent. However, both are perpendicular to the vertex normal. For normal
|
||||||
|
* maps it is sufficient to use the following simplified version of the
|
||||||
|
* bitangent which is generated at pixel/vertex level.
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* fSign = bIsOrientationPreserving ? 1.0f : (-1.0f);
|
||||||
|
* bitangent = fSign * cross(vN, tangent);
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* Note that the results are returned unindexed. It is possible to generate
|
||||||
|
* a new index list. But averaging/overwriting tangent spaces by using an
|
||||||
|
* already existing index list WILL produce INCRORRECT results. DO NOT! use
|
||||||
|
* an already existing index list.
|
||||||
|
*
|
||||||
|
* @param tangent
|
||||||
|
* @param biTangent
|
||||||
|
* @param magS
|
||||||
|
* @param magT
|
||||||
|
* @param isOrientationPreserving
|
||||||
|
* @param face
|
||||||
|
* @param vert
|
||||||
|
*/
|
||||||
|
void setTSpace(float tangent[], float biTangent[], float magS, float magT,
|
||||||
|
boolean isOrientationPreserving, int face, int vert);
|
||||||
|
}
|
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.util.mikktspace;
|
||||||
|
|
||||||
|
import com.jme3.scene.Mesh;
|
||||||
|
import com.jme3.scene.VertexBuffer;
|
||||||
|
import com.jme3.scene.mesh.IndexBuffer;
|
||||||
|
import com.jme3.util.BufferUtils;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public class MikkTSpaceImpl implements MikkTSpaceContext {
|
||||||
|
|
||||||
|
Mesh mesh;
|
||||||
|
|
||||||
|
public MikkTSpaceImpl(Mesh mesh) {
|
||||||
|
this.mesh = mesh;
|
||||||
|
VertexBuffer tangentBuffer = mesh.getBuffer(VertexBuffer.Type.Tangent);
|
||||||
|
if(tangentBuffer == null){
|
||||||
|
FloatBuffer fb = BufferUtils.createFloatBuffer(mesh.getVertexCount() * 4);
|
||||||
|
mesh.setBuffer(VertexBuffer.Type.Tangent, 4, fb);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO ensure the Tangent buffer exists, else create one.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumFaces() {
|
||||||
|
return mesh.getTriangleCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNumVerticesOfFace(int face) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getPosition(float[] posOut, int face, int vert) {
|
||||||
|
int vertIndex = getIndex(face, vert);
|
||||||
|
VertexBuffer position = mesh.getBuffer(VertexBuffer.Type.Position);
|
||||||
|
FloatBuffer pos = (FloatBuffer) position.getData();
|
||||||
|
pos.position(vertIndex * 3);
|
||||||
|
posOut[0] = pos.get();
|
||||||
|
posOut[1] = pos.get();
|
||||||
|
posOut[2] = pos.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getNormal(float[] normOut, int face, int vert) {
|
||||||
|
int vertIndex = getIndex(face, vert);
|
||||||
|
VertexBuffer normal = mesh.getBuffer(VertexBuffer.Type.Normal);
|
||||||
|
FloatBuffer norm = (FloatBuffer) normal.getData();
|
||||||
|
norm.position(vertIndex * 3);
|
||||||
|
normOut[0] = norm.get();
|
||||||
|
normOut[1] = norm.get();
|
||||||
|
normOut[2] = norm.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getTexCoord(float[] texOut, int face, int vert) {
|
||||||
|
int vertIndex = getIndex(face, vert);
|
||||||
|
VertexBuffer texCoord = mesh.getBuffer(VertexBuffer.Type.TexCoord);
|
||||||
|
FloatBuffer tex = (FloatBuffer) texCoord.getData();
|
||||||
|
tex.position(vertIndex * 2);
|
||||||
|
texOut[0] = tex.get();
|
||||||
|
texOut[1] = tex.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTSpaceBasic(float[] tangent, float sign, int face, int vert) {
|
||||||
|
int vertIndex = getIndex(face, vert);
|
||||||
|
VertexBuffer tangentBuffer = mesh.getBuffer(VertexBuffer.Type.Tangent);
|
||||||
|
FloatBuffer tan = (FloatBuffer) tangentBuffer.getData();
|
||||||
|
|
||||||
|
tan.position(vertIndex * 4);
|
||||||
|
tan.put(tangent);
|
||||||
|
tan.put(sign);
|
||||||
|
|
||||||
|
tan.rewind();
|
||||||
|
tangentBuffer.setUpdateNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTSpace(float[] tangent, float[] biTangent, float magS, float magT, boolean isOrientationPreserving, int face, int vert) {
|
||||||
|
//Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndex(int face, int vert) {
|
||||||
|
IndexBuffer index = mesh.getIndexBuffer();
|
||||||
|
int vertIndex = index.get(face * 3 + vert);
|
||||||
|
return vertIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -113,6 +113,8 @@ MaterialDef Phong Lighting {
|
|||||||
|
|
||||||
//For instancing
|
//For instancing
|
||||||
Boolean UseInstancing
|
Boolean UseInstancing
|
||||||
|
|
||||||
|
Boolean BackfaceShadows: false
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique {
|
Technique {
|
||||||
@ -213,26 +215,19 @@ MaterialDef Phong Lighting {
|
|||||||
INSTANCING : UseInstancing
|
INSTANCING : UseInstancing
|
||||||
}
|
}
|
||||||
|
|
||||||
ForcedRenderState {
|
|
||||||
FaceCull Off
|
|
||||||
DepthTest On
|
|
||||||
DepthWrite On
|
|
||||||
PolyOffset 5 3
|
|
||||||
ColorWrite Off
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Technique PostShadow15{
|
Technique PostShadow15{
|
||||||
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow15.vert
|
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert
|
||||||
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow15.frag
|
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag
|
||||||
|
|
||||||
WorldParameters {
|
WorldParameters {
|
||||||
WorldViewProjectionMatrix
|
WorldViewProjectionMatrix
|
||||||
WorldMatrix
|
WorldMatrix
|
||||||
ViewProjectionMatrix
|
ViewProjectionMatrix
|
||||||
ViewMatrix
|
ViewMatrix
|
||||||
|
NormalMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
Defines {
|
Defines {
|
||||||
@ -247,6 +242,7 @@ MaterialDef Phong Lighting {
|
|||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
NUM_BONES : NumberOfBones
|
NUM_BONES : NumberOfBones
|
||||||
INSTANCING : UseInstancing
|
INSTANCING : UseInstancing
|
||||||
|
BACKFACE_SHADOWS: BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
ForcedRenderState {
|
ForcedRenderState {
|
||||||
@ -265,6 +261,7 @@ MaterialDef Phong Lighting {
|
|||||||
WorldMatrix
|
WorldMatrix
|
||||||
ViewProjectionMatrix
|
ViewProjectionMatrix
|
||||||
ViewMatrix
|
ViewMatrix
|
||||||
|
NormalMatrix
|
||||||
}
|
}
|
||||||
|
|
||||||
Defines {
|
Defines {
|
||||||
|
@ -51,6 +51,8 @@ MaterialDef Unshaded {
|
|||||||
Float PCFEdge
|
Float PCFEdge
|
||||||
|
|
||||||
Float ShadowMapSize
|
Float ShadowMapSize
|
||||||
|
|
||||||
|
Boolean BackfaceShadows: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique {
|
Technique {
|
||||||
@ -147,8 +149,8 @@ MaterialDef Unshaded {
|
|||||||
|
|
||||||
|
|
||||||
Technique PostShadow15{
|
Technique PostShadow15{
|
||||||
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow15.vert
|
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert
|
||||||
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow15.frag
|
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag
|
||||||
|
|
||||||
WorldParameters {
|
WorldParameters {
|
||||||
WorldViewProjectionMatrix
|
WorldViewProjectionMatrix
|
||||||
@ -169,6 +171,7 @@ MaterialDef Unshaded {
|
|||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
NUM_BONES : NumberOfBones
|
NUM_BONES : NumberOfBones
|
||||||
INSTANCING : UseInstancing
|
INSTANCING : UseInstancing
|
||||||
|
BACKFACE_SHADOWS: BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
ForcedRenderState {
|
ForcedRenderState {
|
||||||
@ -201,6 +204,7 @@ MaterialDef Unshaded {
|
|||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
NUM_BONES : NumberOfBones
|
NUM_BONES : NumberOfBones
|
||||||
INSTANCING : UseInstancing
|
INSTANCING : UseInstancing
|
||||||
|
BACKFACE_SHADOWS: BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
ForcedRenderState {
|
ForcedRenderState {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#import "Common/ShaderLib/Shadows.glsllib"
|
#import "Common/ShaderLib/Shadows.glsllib"
|
||||||
|
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||||
|
|
||||||
#if defined(PSSM) || defined(FADE)
|
#if defined(PSSM) || defined(FADE)
|
||||||
varying float shadowPosition;
|
varying float shadowPosition;
|
||||||
@ -8,6 +9,9 @@ varying vec4 projCoord0;
|
|||||||
varying vec4 projCoord1;
|
varying vec4 projCoord1;
|
||||||
varying vec4 projCoord2;
|
varying vec4 projCoord2;
|
||||||
varying vec4 projCoord3;
|
varying vec4 projCoord3;
|
||||||
|
#ifndef BACKFACE_SHADOWS
|
||||||
|
varying float nDotL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
#ifdef POINTLIGHT
|
||||||
varying vec4 projCoord4;
|
varying vec4 projCoord4;
|
||||||
@ -45,9 +49,15 @@ void main(){
|
|||||||
if(alpha<=m_AlphaDiscardThreshold){
|
if(alpha<=m_AlphaDiscardThreshold){
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BACKFACE_SHADOWS
|
||||||
|
if(nDotL > 0.0){
|
||||||
|
discard;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
float shadow = 1.0;
|
float shadow = 1.0;
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
#ifdef POINTLIGHT
|
||||||
@ -70,11 +80,11 @@ void main(){
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FADE
|
#ifdef FADE
|
||||||
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y));
|
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y));
|
||||||
#endif
|
#endif
|
||||||
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
|
|
||||||
|
|
||||||
gl_FragColor = vec4(shadow, shadow, shadow, 1.0);
|
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
|
||||||
|
gl_FragColor = vec4(shadow, shadow, shadow, 1.0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,12 +29,14 @@ MaterialDef Post Shadow {
|
|||||||
Float PCFEdge
|
Float PCFEdge
|
||||||
|
|
||||||
Float ShadowMapSize
|
Float ShadowMapSize
|
||||||
|
|
||||||
|
Boolean BackfaceShadows: false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique {
|
Technique {
|
||||||
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow15.vert
|
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadow.vert
|
||||||
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow15.frag
|
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadow.frag
|
||||||
|
|
||||||
WorldParameters {
|
WorldParameters {
|
||||||
WorldViewProjectionMatrix
|
WorldViewProjectionMatrix
|
||||||
@ -49,6 +51,7 @@ MaterialDef Post Shadow {
|
|||||||
FADE : FadeInfo
|
FADE : FadeInfo
|
||||||
PSSM : Splits
|
PSSM : Splits
|
||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
|
BACKFACE_SHADOWS: BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderState {
|
RenderState {
|
||||||
@ -75,6 +78,7 @@ MaterialDef Post Shadow {
|
|||||||
FADE : FadeInfo
|
FADE : FadeInfo
|
||||||
PSSM : Splits
|
PSSM : Splits
|
||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
|
BACKFACE_SHADOWS: BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderState {
|
RenderState {
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
#import "Common/ShaderLib/Instancing.glsllib"
|
#import "Common/ShaderLib/Instancing.glsllib"
|
||||||
#import "Common/ShaderLib/Skinning.glsllib"
|
#import "Common/ShaderLib/Skinning.glsllib"
|
||||||
|
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||||
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix0;
|
uniform mat4 m_LightViewProjectionMatrix0;
|
||||||
uniform mat4 m_LightViewProjectionMatrix1;
|
uniform mat4 m_LightViewProjectionMatrix1;
|
||||||
uniform mat4 m_LightViewProjectionMatrix2;
|
uniform mat4 m_LightViewProjectionMatrix2;
|
||||||
uniform mat4 m_LightViewProjectionMatrix3;
|
uniform mat4 m_LightViewProjectionMatrix3;
|
||||||
|
|
||||||
uniform vec3 m_LightPos;
|
|
||||||
|
|
||||||
varying vec4 projCoord0;
|
varying vec4 projCoord0;
|
||||||
varying vec4 projCoord1;
|
varying vec4 projCoord1;
|
||||||
@ -15,12 +16,14 @@ varying vec4 projCoord3;
|
|||||||
#ifdef POINTLIGHT
|
#ifdef POINTLIGHT
|
||||||
uniform mat4 m_LightViewProjectionMatrix4;
|
uniform mat4 m_LightViewProjectionMatrix4;
|
||||||
uniform mat4 m_LightViewProjectionMatrix5;
|
uniform mat4 m_LightViewProjectionMatrix5;
|
||||||
|
uniform vec3 m_LightPos;
|
||||||
varying vec4 projCoord4;
|
varying vec4 projCoord4;
|
||||||
varying vec4 projCoord5;
|
varying vec4 projCoord5;
|
||||||
varying vec4 worldPos;
|
varying vec4 worldPos;
|
||||||
#else
|
#else
|
||||||
|
uniform vec3 m_LightDir;
|
||||||
#ifndef PSSM
|
#ifndef PSSM
|
||||||
uniform vec3 m_LightDir;
|
uniform vec3 m_LightPos;
|
||||||
varying float lightDot;
|
varying float lightDot;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -28,12 +31,15 @@ varying vec4 projCoord3;
|
|||||||
#if defined(PSSM) || defined(FADE)
|
#if defined(PSSM) || defined(FADE)
|
||||||
varying float shadowPosition;
|
varying float shadowPosition;
|
||||||
#endif
|
#endif
|
||||||
varying vec3 lightVec;
|
|
||||||
|
|
||||||
varying vec2 texCoord;
|
varying vec2 texCoord;
|
||||||
|
|
||||||
attribute vec3 inPosition;
|
attribute vec3 inPosition;
|
||||||
|
|
||||||
|
#ifndef BACKFACE_SHADOWS
|
||||||
|
attribute vec3 inNormal;
|
||||||
|
varying float nDotL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA
|
#ifdef DISCARD_ALPHA
|
||||||
attribute vec2 inTexCoord;
|
attribute vec2 inTexCoord;
|
||||||
#endif
|
#endif
|
||||||
@ -51,16 +57,17 @@ void main(){
|
|||||||
Skinning_Compute(modelSpacePos);
|
Skinning_Compute(modelSpacePos);
|
||||||
#endif
|
#endif
|
||||||
gl_Position = TransformWorldViewProjection(modelSpacePos);
|
gl_Position = TransformWorldViewProjection(modelSpacePos);
|
||||||
|
vec3 lightDir;
|
||||||
|
|
||||||
#if defined(PSSM) || defined(FADE)
|
#if defined(PSSM) || defined(FADE)
|
||||||
shadowPosition = gl_Position.z;
|
shadowPosition = gl_Position.z;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef POINTLIGHT
|
#ifndef POINTLIGHT
|
||||||
vec4 worldPos=vec4(0.0);
|
vec4 worldPos=vec4(0.0);
|
||||||
#endif
|
#endif
|
||||||
// get the vertex in world space
|
// get the vertex in world space
|
||||||
worldPos = g_WorldMatrix * modelSpacePos;
|
worldPos = TransformWorld(modelSpacePos);
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA
|
#ifdef DISCARD_ALPHA
|
||||||
texCoord = inTexCoord;
|
texCoord = inTexCoord;
|
||||||
@ -75,8 +82,21 @@ void main(){
|
|||||||
projCoord5 = biasMat * m_LightViewProjectionMatrix5 * worldPos;
|
projCoord5 = biasMat * m_LightViewProjectionMatrix5 * worldPos;
|
||||||
#else
|
#else
|
||||||
#ifndef PSSM
|
#ifndef PSSM
|
||||||
vec3 lightDir = worldPos.xyz - m_LightPos;
|
//Spot light
|
||||||
|
lightDir = worldPos.xyz - m_LightPos;
|
||||||
lightDot = dot(m_LightDir,lightDir);
|
lightDot = dot(m_LightDir,lightDir);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BACKFACE_SHADOWS
|
||||||
|
vec3 normal = normalize(TransformWorld(vec4(inNormal,0.0))).xyz;
|
||||||
|
#ifdef POINTLIGHT
|
||||||
|
lightDir = worldPos.xyz - m_LightPos;
|
||||||
|
#else
|
||||||
|
#ifdef PSSM
|
||||||
|
lightDir = m_LightDir;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
nDotL = dot(normal, lightDir);
|
||||||
|
#endif
|
||||||
}
|
}
|
@ -1,80 +0,0 @@
|
|||||||
#import "Common/ShaderLib/Shadows15.glsllib"
|
|
||||||
|
|
||||||
out vec4 outFragColor;
|
|
||||||
|
|
||||||
#if defined(PSSM) || defined(FADE)
|
|
||||||
in float shadowPosition;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
in vec4 projCoord0;
|
|
||||||
in vec4 projCoord1;
|
|
||||||
in vec4 projCoord2;
|
|
||||||
in vec4 projCoord3;
|
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
|
||||||
in vec4 projCoord4;
|
|
||||||
in vec4 projCoord5;
|
|
||||||
in vec4 worldPos;
|
|
||||||
uniform vec3 m_LightPos;
|
|
||||||
#else
|
|
||||||
#ifndef PSSM
|
|
||||||
in float lightDot;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA
|
|
||||||
#ifdef COLOR_MAP
|
|
||||||
uniform sampler2D m_ColorMap;
|
|
||||||
#else
|
|
||||||
uniform sampler2D m_DiffuseMap;
|
|
||||||
#endif
|
|
||||||
uniform float m_AlphaDiscardThreshold;
|
|
||||||
varying vec2 texCoord;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FADE
|
|
||||||
uniform vec2 m_FadeInfo;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA
|
|
||||||
#ifdef COLOR_MAP
|
|
||||||
float alpha = texture2D(m_ColorMap,texCoord).a;
|
|
||||||
#else
|
|
||||||
float alpha = texture2D(m_DiffuseMap,texCoord).a;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(alpha < m_AlphaDiscardThreshold){
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float shadow = 1.0;
|
|
||||||
#ifdef POINTLIGHT
|
|
||||||
shadow = getPointLightShadows(worldPos, m_LightPos,
|
|
||||||
m_ShadowMap0,m_ShadowMap1,m_ShadowMap2,m_ShadowMap3,m_ShadowMap4,m_ShadowMap5,
|
|
||||||
projCoord0, projCoord1, projCoord2, projCoord3, projCoord4, projCoord5);
|
|
||||||
#else
|
|
||||||
#ifdef PSSM
|
|
||||||
shadow = getDirectionalLightShadows(m_Splits, shadowPosition,
|
|
||||||
m_ShadowMap0,m_ShadowMap1,m_ShadowMap2,m_ShadowMap3,
|
|
||||||
projCoord0, projCoord1, projCoord2, projCoord3);
|
|
||||||
#else
|
|
||||||
//spotlight
|
|
||||||
if(lightDot < 0){
|
|
||||||
outFragColor = vec4(1.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
shadow = getSpotLightShadows(m_ShadowMap0,projCoord0);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FADE
|
|
||||||
shadow = max(0.0,mix(shadow,1.0,(shadowPosition - m_FadeInfo.x) * m_FadeInfo.y));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
shadow = shadow * m_ShadowIntensity + (1.0 - m_ShadowIntensity);
|
|
||||||
outFragColor = vec4(shadow, shadow, shadow, 1.0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
|||||||
#import "Common/ShaderLib/Instancing.glsllib"
|
|
||||||
#import "Common/ShaderLib/Skinning.glsllib"
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix0;
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix1;
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix2;
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix3;
|
|
||||||
|
|
||||||
|
|
||||||
out vec4 projCoord0;
|
|
||||||
out vec4 projCoord1;
|
|
||||||
out vec4 projCoord2;
|
|
||||||
out vec4 projCoord3;
|
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix4;
|
|
||||||
uniform mat4 m_LightViewProjectionMatrix5;
|
|
||||||
out vec4 projCoord4;
|
|
||||||
out vec4 projCoord5;
|
|
||||||
out vec4 worldPos;
|
|
||||||
#else
|
|
||||||
#ifndef PSSM
|
|
||||||
uniform vec3 m_LightPos;
|
|
||||||
uniform vec3 m_LightDir;
|
|
||||||
out float lightDot;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PSSM) || defined(FADE)
|
|
||||||
out float shadowPosition;
|
|
||||||
#endif
|
|
||||||
out vec3 lightVec;
|
|
||||||
|
|
||||||
out vec2 texCoord;
|
|
||||||
|
|
||||||
in vec3 inPosition;
|
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA
|
|
||||||
in vec2 inTexCoord;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const mat4 biasMat = mat4(0.5, 0.0, 0.0, 0.0,
|
|
||||||
0.0, 0.5, 0.0, 0.0,
|
|
||||||
0.0, 0.0, 0.5, 0.0,
|
|
||||||
0.5, 0.5, 0.5, 1.0);
|
|
||||||
|
|
||||||
|
|
||||||
void main(){
|
|
||||||
vec4 modelSpacePos = vec4(inPosition, 1.0);
|
|
||||||
|
|
||||||
#ifdef NUM_BONES
|
|
||||||
Skinning_Compute(modelSpacePos);
|
|
||||||
#endif
|
|
||||||
gl_Position = TransformWorldViewProjection(modelSpacePos);
|
|
||||||
|
|
||||||
#if defined(PSSM) || defined(FADE)
|
|
||||||
shadowPosition = gl_Position.z;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef POINTLIGHT
|
|
||||||
vec4 worldPos=vec4(0.0);
|
|
||||||
#endif
|
|
||||||
// get the vertex in world space
|
|
||||||
worldPos = TransformWorld(modelSpacePos);
|
|
||||||
|
|
||||||
#ifdef DISCARD_ALPHA
|
|
||||||
texCoord = inTexCoord;
|
|
||||||
#endif
|
|
||||||
// populate the light view matrices array and convert vertex to light viewProj space
|
|
||||||
projCoord0 = biasMat * m_LightViewProjectionMatrix0 * worldPos;
|
|
||||||
projCoord1 = biasMat * m_LightViewProjectionMatrix1 * worldPos;
|
|
||||||
projCoord2 = biasMat * m_LightViewProjectionMatrix2 * worldPos;
|
|
||||||
projCoord3 = biasMat * m_LightViewProjectionMatrix3 * worldPos;
|
|
||||||
#ifdef POINTLIGHT
|
|
||||||
projCoord4 = biasMat * m_LightViewProjectionMatrix4 * worldPos;
|
|
||||||
projCoord5 = biasMat * m_LightViewProjectionMatrix5 * worldPos;
|
|
||||||
#else
|
|
||||||
#ifndef PSSM
|
|
||||||
vec3 lightDir = worldPos.xyz - m_LightPos;
|
|
||||||
lightDot = dot(m_LightDir,lightDir);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -18,6 +18,8 @@ uniform mat4 m_LightViewProjectionMatrix1;
|
|||||||
uniform mat4 m_LightViewProjectionMatrix2;
|
uniform mat4 m_LightViewProjectionMatrix2;
|
||||||
uniform mat4 m_LightViewProjectionMatrix3;
|
uniform mat4 m_LightViewProjectionMatrix3;
|
||||||
|
|
||||||
|
uniform vec2 g_ResolutionInverse;
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
#ifdef POINTLIGHT
|
||||||
uniform vec3 m_LightPos;
|
uniform vec3 m_LightPos;
|
||||||
uniform mat4 m_LightViewProjectionMatrix4;
|
uniform mat4 m_LightViewProjectionMatrix4;
|
||||||
@ -39,6 +41,19 @@ vec3 getPosition(in float depth, in vec2 uv){
|
|||||||
return pos.xyz / pos.w;
|
return pos.xyz / pos.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 approximateNormal(in vec4 worldPos,in vec2 texCoord){
|
||||||
|
float step = g_ResolutionInverse.x ;
|
||||||
|
float stepy = g_ResolutionInverse.y ;
|
||||||
|
float depth2 = texture2D(m_DepthTexture,texCoord + vec2(step,-stepy)).r;
|
||||||
|
float depth3 = texture2D(m_DepthTexture,texCoord + vec2(-step,-stepy)).r;
|
||||||
|
vec4 worldPos2 = vec4(getPosition(depth2,texCoord + vec2(step,-stepy)),1.0);
|
||||||
|
vec4 worldPos3 = vec4(getPosition(depth3,texCoord + vec2(-step,-stepy)),1.0);
|
||||||
|
|
||||||
|
vec3 v1 = (worldPos - worldPos2).xyz;
|
||||||
|
vec3 v2 = (worldPos3 - worldPos2).xyz;
|
||||||
|
return normalize(cross(v1, v2));
|
||||||
|
}
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
#if !defined( RENDER_SHADOWS )
|
#if !defined( RENDER_SHADOWS )
|
||||||
gl_FragColor = texture2D(m_Texture,texCoord);
|
gl_FragColor = texture2D(m_Texture,texCoord);
|
||||||
@ -48,6 +63,7 @@ void main(){
|
|||||||
float depth = texture2D(m_DepthTexture,texCoord).r;
|
float depth = texture2D(m_DepthTexture,texCoord).r;
|
||||||
vec4 color = texture2D(m_Texture,texCoord);
|
vec4 color = texture2D(m_Texture,texCoord);
|
||||||
|
|
||||||
|
|
||||||
//Discard shadow computation on the sky
|
//Discard shadow computation on the sky
|
||||||
if(depth == 1.0){
|
if(depth == 1.0){
|
||||||
gl_FragColor = color;
|
gl_FragColor = color;
|
||||||
@ -56,6 +72,19 @@ void main(){
|
|||||||
|
|
||||||
// get the vertex in world space
|
// get the vertex in world space
|
||||||
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
|
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
|
||||||
|
vec3 normal = approximateNormal(worldPos, texCoord);
|
||||||
|
|
||||||
|
vec3 lightDir;
|
||||||
|
#ifdef PSSM
|
||||||
|
lightDir = m_LightDir;
|
||||||
|
#else
|
||||||
|
lightDir = worldPos.xyz - m_LightPos;
|
||||||
|
#endif
|
||||||
|
float ndotl = dot(normal, lightDir);
|
||||||
|
if(ndotl > -0.0){
|
||||||
|
gl_FragColor = color;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if (!defined(POINTLIGHT) && !defined(PSSM))
|
#if (!defined(POINTLIGHT) && !defined(PSSM))
|
||||||
vec3 lightDir = worldPos.xyz - m_LightPos;
|
vec3 lightDir = worldPos.xyz - m_LightPos;
|
||||||
|
@ -38,13 +38,15 @@ MaterialDef Post Shadow {
|
|||||||
Texture2D Texture
|
Texture2D Texture
|
||||||
Texture2D DepthTexture
|
Texture2D DepthTexture
|
||||||
|
|
||||||
|
Boolean BackfaceShadows: true
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique {
|
Technique {
|
||||||
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.vert
|
VertexShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.vert
|
||||||
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.frag
|
FragmentShader GLSL150: Common/MatDefs/Shadow/PostShadowFilter15.frag
|
||||||
|
|
||||||
WorldParameters {
|
WorldParameters {
|
||||||
|
ResolutionInverse
|
||||||
}
|
}
|
||||||
|
|
||||||
Defines {
|
Defines {
|
||||||
@ -59,7 +61,7 @@ MaterialDef Post Shadow {
|
|||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
//if no shadow map don't render shadows
|
//if no shadow map don't render shadows
|
||||||
RENDER_SHADOWS : ShadowMap0
|
RENDER_SHADOWS : ShadowMap0
|
||||||
|
BACKFACE_SHADOWS : BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -68,7 +70,8 @@ MaterialDef Post Shadow {
|
|||||||
VertexShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.vert
|
VertexShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.vert
|
||||||
FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.frag
|
FragmentShader GLSL100: Common/MatDefs/Shadow/PostShadowFilter.frag
|
||||||
|
|
||||||
WorldParameters {
|
WorldParameters {
|
||||||
|
ResolutionInverse
|
||||||
}
|
}
|
||||||
|
|
||||||
Defines {
|
Defines {
|
||||||
@ -79,6 +82,7 @@ MaterialDef Post Shadow {
|
|||||||
FADE : FadeInfo
|
FADE : FadeInfo
|
||||||
PSSM : Splits
|
PSSM : Splits
|
||||||
POINTLIGHT : LightViewProjectionMatrix5
|
POINTLIGHT : LightViewProjectionMatrix5
|
||||||
|
BACKFACE_SHADOWS : BackfaceShadows
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#import "Common/ShaderLib/MultiSample.glsllib"
|
#import "Common/ShaderLib/MultiSample.glsllib"
|
||||||
#import "Common/ShaderLib/Shadows15.glsllib"
|
#import "Common/ShaderLib/Shadows.glsllib"
|
||||||
|
|
||||||
|
|
||||||
uniform COLORTEXTURE m_Texture;
|
uniform COLORTEXTURE m_Texture;
|
||||||
@ -20,14 +20,16 @@ uniform mat4 m_LightViewProjectionMatrix1;
|
|||||||
uniform mat4 m_LightViewProjectionMatrix2;
|
uniform mat4 m_LightViewProjectionMatrix2;
|
||||||
uniform mat4 m_LightViewProjectionMatrix3;
|
uniform mat4 m_LightViewProjectionMatrix3;
|
||||||
|
|
||||||
|
uniform vec2 g_ResolutionInverse;
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
#ifdef POINTLIGHT
|
||||||
uniform vec3 m_LightPos;
|
uniform vec3 m_LightPos;
|
||||||
uniform mat4 m_LightViewProjectionMatrix4;
|
uniform mat4 m_LightViewProjectionMatrix4;
|
||||||
uniform mat4 m_LightViewProjectionMatrix5;
|
uniform mat4 m_LightViewProjectionMatrix5;
|
||||||
#else
|
#else
|
||||||
|
uniform vec3 m_LightDir;
|
||||||
#ifndef PSSM
|
#ifndef PSSM
|
||||||
uniform vec3 m_LightPos;
|
uniform vec3 m_LightPos;
|
||||||
uniform vec3 m_LightDir;
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -41,6 +43,23 @@ vec3 getPosition(in float depth, in vec2 uv){
|
|||||||
return pos.xyz / pos.w;
|
return pos.xyz / pos.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef BACKFACE_SHADOWS
|
||||||
|
vec3 approximateNormal(in float depth,in vec4 worldPos,in vec2 texCoord, in int numSample){
|
||||||
|
float step = g_ResolutionInverse.x ;
|
||||||
|
float stepy = g_ResolutionInverse.y ;
|
||||||
|
float depth1 = fetchTextureSample(m_DepthTexture,texCoord + vec2(-step,stepy),numSample).r;
|
||||||
|
float depth2 = fetchTextureSample(m_DepthTexture,texCoord + vec2(step,stepy),numSample).r;
|
||||||
|
vec3 v1, v2;
|
||||||
|
vec4 worldPos1 = vec4(getPosition(depth1,texCoord + vec2(-step,stepy)),1.0);
|
||||||
|
vec4 worldPos2 = vec4(getPosition(depth2,texCoord + vec2(step,stepy)),1.0);
|
||||||
|
|
||||||
|
v1 = normalize((worldPos1 - worldPos)).xyz;
|
||||||
|
v2 = normalize((worldPos2 - worldPos)).xyz;
|
||||||
|
return normalize(cross(v2, v1));
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
vec4 main_multiSample(in int numSample){
|
vec4 main_multiSample(in int numSample){
|
||||||
float depth = fetchTextureSample(m_DepthTexture,texCoord,numSample).r;//getDepth(m_DepthTexture,texCoord).r;
|
float depth = fetchTextureSample(m_DepthTexture,texCoord,numSample).r;//getDepth(m_DepthTexture,texCoord).r;
|
||||||
vec4 color = fetchTextureSample(m_Texture,texCoord,numSample);
|
vec4 color = fetchTextureSample(m_Texture,texCoord,numSample);
|
||||||
@ -52,12 +71,27 @@ vec4 main_multiSample(in int numSample){
|
|||||||
|
|
||||||
// get the vertex in world space
|
// get the vertex in world space
|
||||||
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
|
vec4 worldPos = vec4(getPosition(depth,texCoord),1.0);
|
||||||
|
|
||||||
|
|
||||||
|
vec3 lightDir;
|
||||||
|
#ifdef PSSM
|
||||||
|
lightDir = m_LightDir;
|
||||||
|
#else
|
||||||
|
lightDir = worldPos.xyz - m_LightPos;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BACKFACE_SHADOWS
|
||||||
|
vec3 normal = approximateNormal(depth, worldPos, texCoord, numSample);
|
||||||
|
float ndotl = dot(normal, lightDir);
|
||||||
|
if(ndotl > 0.0){
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (!defined(POINTLIGHT) && !defined(PSSM))
|
#if (!defined(POINTLIGHT) && !defined(PSSM))
|
||||||
vec3 lightDir = worldPos.xyz - m_LightPos;
|
if( dot(m_LightDir,lightDir)<0){
|
||||||
if( dot(m_LightDir,lightDir)<0){
|
return color;
|
||||||
return color;
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// populate the light view matrices array and convert vertex to light viewProj space
|
// populate the light view matrices array and convert vertex to light viewProj space
|
||||||
|
@ -1,22 +1,57 @@
|
|||||||
#ifdef HARDWARE_SHADOWS
|
#if __VERSION__ >= 130
|
||||||
#define SHADOWMAP sampler2DShadow
|
// Because gpu_shader5 is actually where those
|
||||||
#define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r
|
// gather functions are declared to work on shadowmaps
|
||||||
|
#extension GL_ARB_gpu_shader5 : enable
|
||||||
|
#define IVEC2 ivec2
|
||||||
|
#ifdef HARDWARE_SHADOWS
|
||||||
|
#define SHADOWMAP sampler2DShadow
|
||||||
|
#define SHADOWCOMPAREOFFSET(tex,coord,offset) textureProjOffset(tex, coord, offset)
|
||||||
|
#define SHADOWCOMPARE(tex,coord) textureProj(tex, coord)
|
||||||
|
#define SHADOWGATHER(tex,coord) textureGather(tex, coord.xy, coord.z)
|
||||||
|
#else
|
||||||
|
#define SHADOWMAP sampler2D
|
||||||
|
#define SHADOWCOMPAREOFFSET(tex,coord,offset) step(coord.z, textureProjOffset(tex, coord, offset).r)
|
||||||
|
#define SHADOWCOMPARE(tex,coord) step(coord.z, textureProj(tex, coord).r)
|
||||||
|
#define SHADOWGATHER(tex,coord) step(coord.z, textureGather(tex, coord.xy))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FILTER_MODE == 0
|
||||||
|
#define GETSHADOW Shadow_Nearest
|
||||||
|
#define KERNEL 1.0
|
||||||
|
#elif FILTER_MODE == 1
|
||||||
|
#ifdef HARDWARE_SHADOWS
|
||||||
|
#define GETSHADOW Shadow_Nearest
|
||||||
|
#else
|
||||||
|
#define GETSHADOW Shadow_DoBilinear_2x2
|
||||||
|
#endif
|
||||||
|
#define KERNEL 1.0
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define SHADOWMAP sampler2D
|
#define IVEC2 vec2
|
||||||
#define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r)
|
#ifdef HARDWARE_SHADOWS
|
||||||
|
#define SHADOWMAP sampler2DShadow
|
||||||
|
#define SHADOWCOMPARE(tex,coord) shadow2DProj(tex, coord).r
|
||||||
|
#else
|
||||||
|
#define SHADOWMAP sampler2D
|
||||||
|
#define SHADOWCOMPARE(tex,coord) step(coord.z, texture2DProj(tex, coord).r)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FILTER_MODE == 0
|
||||||
|
#define GETSHADOW Shadow_DoShadowCompare
|
||||||
|
#define KERNEL 1.0
|
||||||
|
#elif FILTER_MODE == 1
|
||||||
|
#ifdef HARDWARE_SHADOWS
|
||||||
|
#define GETSHADOW Shadow_DoShadowCompare
|
||||||
|
#else
|
||||||
|
#define GETSHADOW Shadow_DoBilinear_2x2
|
||||||
|
#endif
|
||||||
|
#define KERNEL 1.0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FILTER_MODE == 0
|
#if FILTER_MODE == 2
|
||||||
#define GETSHADOW Shadow_DoShadowCompare
|
|
||||||
#define KERNEL 1.0
|
|
||||||
#elif FILTER_MODE == 1
|
|
||||||
#ifdef HARDWARE_SHADOWS
|
|
||||||
#define GETSHADOW Shadow_DoShadowCompare
|
|
||||||
#else
|
|
||||||
#define GETSHADOW Shadow_DoBilinear_2x2
|
|
||||||
#endif
|
|
||||||
#define KERNEL 1.0
|
|
||||||
#elif FILTER_MODE == 2
|
|
||||||
#define GETSHADOW Shadow_DoDither_2x2
|
#define GETSHADOW Shadow_DoDither_2x2
|
||||||
#define KERNEL 1.0
|
#define KERNEL 1.0
|
||||||
#elif FILTER_MODE == 3
|
#elif FILTER_MODE == 3
|
||||||
@ -30,14 +65,13 @@
|
|||||||
#define KERNEL 8.0
|
#define KERNEL 8.0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
uniform SHADOWMAP m_ShadowMap0;
|
uniform SHADOWMAP m_ShadowMap0;
|
||||||
uniform SHADOWMAP m_ShadowMap1;
|
uniform SHADOWMAP m_ShadowMap1;
|
||||||
uniform SHADOWMAP m_ShadowMap2;
|
uniform SHADOWMAP m_ShadowMap2;
|
||||||
uniform SHADOWMAP m_ShadowMap3;
|
uniform SHADOWMAP m_ShadowMap3;
|
||||||
#ifdef POINTLIGHT
|
#ifdef POINTLIGHT
|
||||||
uniform SHADOWMAP m_ShadowMap4;
|
uniform SHADOWMAP m_ShadowMap4;
|
||||||
uniform SHADOWMAP m_ShadowMap5;
|
uniform SHADOWMAP m_ShadowMap5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PSSM
|
#ifdef PSSM
|
||||||
@ -49,73 +83,91 @@ uniform float m_ShadowIntensity;
|
|||||||
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
|
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
|
||||||
float shadowBorderScale = 1.0;
|
float shadowBorderScale = 1.0;
|
||||||
|
|
||||||
float Shadow_DoShadowCompareOffset(SHADOWMAP tex, vec4 projCoord, vec2 offset){
|
float Shadow_DoShadowCompare(in SHADOWMAP tex,in vec4 projCoord){
|
||||||
vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2 * shadowBorderScale, projCoord.zw);
|
|
||||||
return SHADOWCOMPARE(tex, coord);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Shadow_DoShadowCompare(SHADOWMAP tex, vec4 projCoord){
|
|
||||||
return SHADOWCOMPARE(tex, projCoord);
|
return SHADOWCOMPARE(tex, projCoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Shadow_BorderCheck(vec2 coord){
|
float Shadow_BorderCheck(in vec2 coord){
|
||||||
// Fastest, "hack" method (uses 4-5 instructions)
|
// Fastest, "hack" method (uses 4-5 instructions)
|
||||||
vec4 t = vec4(coord.xy, 0.0, 1.0);
|
vec4 t = vec4(coord.xy, 0.0, 1.0);
|
||||||
t = step(t.wwxy, t.xyzz);
|
t = step(t.wwxy, t.xyzz);
|
||||||
return dot(t,t);
|
return dot(t,t);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Shadow_Nearest(SHADOWMAP tex, vec4 projCoord){
|
float Shadow_Nearest(in SHADOWMAP tex,in vec4 projCoord){
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
float border = Shadow_BorderCheck(projCoord.xy);
|
||||||
if (border > 0.0){
|
if (border > 0.0){
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
return Shadow_DoShadowCompare(tex,projCoord);
|
return SHADOWCOMPARE(tex, projCoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Shadow_DoDither_2x2(SHADOWMAP tex, vec4 projCoord){
|
float Shadow_DoShadowCompareOffset(in SHADOWMAP tex,in vec4 projCoord,in vec2 offset){
|
||||||
|
vec4 coord = vec4(projCoord.xy + offset.xy * pixSize2 * shadowBorderScale, projCoord.zw);
|
||||||
|
return SHADOWCOMPARE(tex, coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
float border = Shadow_BorderCheck(projCoord.xy);
|
||||||
if (border > 0.0)
|
if (border > 0.0)
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
|
||||||
|
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
vec2 o = mod(floor(gl_FragCoord.xy), 2.0);
|
IVEC2 o = IVEC2(mod(floor(gl_FragCoord.xy), 2.0));
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, 1.5) + o);
|
shadow += Shadow_DoShadowCompareOffset(tex, projCoord, (vec2(-1.5, 1.5)+o));
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, 1.5) + o);
|
shadow += Shadow_DoShadowCompareOffset(tex, projCoord, (vec2( 0.5, 1.5)+o));
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2(-1.5, -0.5) + o);
|
shadow += Shadow_DoShadowCompareOffset(tex, projCoord, (vec2(-1.5, -0.5)+o));
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex,projCoord,vec2( 0.5, -0.5) + o);
|
shadow += Shadow_DoShadowCompareOffset(tex, projCoord, (vec2( 0.5, -0.5)+o));
|
||||||
shadow *= 0.25 ;
|
shadow *= 0.25;
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Shadow_DoBilinear_2x2(SHADOWMAP tex, vec4 projCoord){
|
float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
float border = Shadow_BorderCheck(projCoord.xy);
|
||||||
if (border > 0.0)
|
if (border > 0.0){
|
||||||
return 1.0;
|
return 1.0;
|
||||||
vec4 gather = vec4(0.0);
|
}
|
||||||
gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0));
|
|
||||||
gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0));
|
|
||||||
gather.z = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 1.0));
|
|
||||||
gather.w = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 1.0));
|
|
||||||
|
|
||||||
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE );
|
vec4 gather = vec4(0.0);
|
||||||
vec2 mx = mix( gather.xz, gather.yw, f.x );
|
#if __VERSION__ >= 130
|
||||||
return mix( mx.x, mx.y, f.y );
|
#ifdef GL_ARB_gpu_shader5
|
||||||
|
vec4 coord = vec4(projCoord.xyz / projCoord.www,0.0);
|
||||||
|
gather = SHADOWGATHER(tex, coord);
|
||||||
|
#else
|
||||||
|
gather.x = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 1));
|
||||||
|
gather.y = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 1));
|
||||||
|
gather.z = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 0));
|
||||||
|
gather.w = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 0));
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
gather.x = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 0.0));
|
||||||
|
gather.y = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 0.0));
|
||||||
|
gather.z = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(0.0, 1.0));
|
||||||
|
gather.w = Shadow_DoShadowCompareOffset(tex, projCoord, vec2(1.0, 1.0));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE );
|
||||||
|
vec2 mx = mix( gather.wx, gather.zy, f.x );
|
||||||
|
return mix( mx.x, mx.y, f.y );
|
||||||
}
|
}
|
||||||
|
|
||||||
float Shadow_DoPCF(SHADOWMAP tex, vec4 projCoord){
|
float Shadow_DoPCF(in SHADOWMAP tex,in vec4 projCoord){
|
||||||
|
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
float border = Shadow_BorderCheck(projCoord.xy);
|
||||||
if (border > 0.0)
|
if (border > 0.0)
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
|
||||||
float bound = KERNEL * 0.5 - 0.5;
|
float bound = KERNEL * 0.5 - 0.5;
|
||||||
bound *= PCFEDGE;
|
bound *= PCFEDGE;
|
||||||
for (float y = -bound; y <= bound; y += PCFEDGE){
|
for (float y = -bound; y <= bound; y += PCFEDGE){
|
||||||
for (float x = -bound; x <= bound; x += PCFEDGE){
|
for (float x = -bound; x <= bound; x += PCFEDGE){
|
||||||
shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) +
|
#if __VERSION__ < 130
|
||||||
border,
|
shadow += clamp(Shadow_DoShadowCompareOffset(tex,projCoord,vec2(x,y)) + border, 0.0, 1.0);
|
||||||
0.0, 1.0);
|
#else
|
||||||
|
shadow += Shadow_DoShadowCompareOffset(tex, projCoord, vec2(x,y));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,51 +175,51 @@ float Shadow_DoPCF(SHADOWMAP tex, vec4 projCoord){
|
|||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//12 tap poisson disk
|
//12 tap poisson disk
|
||||||
const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
|
const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
|
||||||
const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
|
const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
|
||||||
const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
|
const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
|
||||||
const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
|
const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
|
||||||
const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
|
const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
|
||||||
const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
|
const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
|
||||||
const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
|
const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
|
||||||
const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
|
const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
|
||||||
const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
|
const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
|
||||||
const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
|
const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
|
||||||
const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
|
const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
|
||||||
const vec2 poissonDisk11 = vec2(0.0123658, 0.8627419);
|
const vec2 poissonDisk11 = vec2(0.0123658, 0.8627419);
|
||||||
|
|
||||||
float Shadow_DoPCFPoisson(SHADOWMAP tex, vec4 projCoord){
|
|
||||||
|
float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){
|
||||||
float shadow = 0.0;
|
float shadow = 0.0;
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
float border = Shadow_BorderCheck(projCoord.xy);
|
||||||
if (border > 0.0)
|
if (border > 0.0){
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
vec2 texelSize = vec2( 4.0 * PCFEDGE * shadowBorderScale);
|
vec2 texelSize = pixSize2 * 4.0 * PCFEDGE * shadowBorderScale;
|
||||||
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk0 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk1 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk2 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk3 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk4 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk5 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk6 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk7 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk8 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk9 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk10 * texelSize);
|
|
||||||
shadow += Shadow_DoShadowCompareOffset(tex, projCoord , poissonDisk11 * texelSize);
|
|
||||||
|
|
||||||
shadow = shadow * 0.08333333333;//this is divided by 12
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk0 * texelSize, projCoord.zw));
|
||||||
return shadow;
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk1 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk2 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk3 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk4 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk5 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk6 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk7 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk8 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk9 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk10 * texelSize, projCoord.zw));
|
||||||
|
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk11 * texelSize, projCoord.zw));
|
||||||
|
|
||||||
|
//this is divided by 12
|
||||||
|
return shadow * 0.08333333333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef POINTLIGHT
|
||||||
#ifdef POINTLIGHT
|
float getPointLightShadows(in vec4 worldPos,in vec3 lightPos,
|
||||||
float getPointLightShadows(vec4 worldPos,vec3 lightPos,
|
in SHADOWMAP shadowMap0,in SHADOWMAP shadowMap1,in SHADOWMAP shadowMap2,in SHADOWMAP shadowMap3,in SHADOWMAP shadowMap4,in SHADOWMAP shadowMap5,
|
||||||
SHADOWMAP shadowMap0,SHADOWMAP shadowMap1,SHADOWMAP shadowMap2,SHADOWMAP shadowMap3,SHADOWMAP shadowMap4,SHADOWMAP shadowMap5,
|
in vec4 projCoord0,in vec4 projCoord1,in vec4 projCoord2,in vec4 projCoord3,in vec4 projCoord4,in vec4 projCoord5){
|
||||||
vec4 projCoord0,vec4 projCoord1,vec4 projCoord2,vec4 projCoord3,vec4 projCoord4,vec4 projCoord5){
|
|
||||||
float shadow = 1.0;
|
float shadow = 1.0;
|
||||||
vec3 vect = worldPos.xyz - lightPos;
|
vec3 vect = worldPos.xyz - lightPos;
|
||||||
vec3 absv= abs(vect);
|
vec3 absv= abs(vect);
|
||||||
@ -190,42 +242,41 @@ float Shadow_DoPCFPoisson(SHADOWMAP tex, vec4 projCoord){
|
|||||||
}else{
|
}else{
|
||||||
shadow = GETSHADOW(shadowMap5, projCoord5 / projCoord5.w);
|
shadow = GETSHADOW(shadowMap5, projCoord5 / projCoord5.w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifdef PSSM
|
#ifdef PSSM
|
||||||
float getDirectionalLightShadows(vec4 splits,float shadowPosition,
|
float getDirectionalLightShadows(in vec4 splits,in float shadowPosition,
|
||||||
SHADOWMAP shadowMap0,SHADOWMAP shadowMap1,SHADOWMAP shadowMap2,SHADOWMAP shadowMap3,
|
in SHADOWMAP shadowMap0,in SHADOWMAP shadowMap1,in SHADOWMAP shadowMap2,in SHADOWMAP shadowMap3,
|
||||||
vec4 projCoord0,vec4 projCoord1,vec4 projCoord2,vec4 projCoord3){
|
in vec4 projCoord0,in vec4 projCoord1,in vec4 projCoord2,in vec4 projCoord3){
|
||||||
float shadow = 1.0;
|
float shadow = 1.0;
|
||||||
if(shadowPosition < splits.x){
|
if(shadowPosition < splits.x){
|
||||||
shadow = GETSHADOW(shadowMap0, projCoord0 );
|
shadow = GETSHADOW(shadowMap0, projCoord0 );
|
||||||
}else if( shadowPosition < splits.y){
|
}else if( shadowPosition < splits.y){
|
||||||
shadowBorderScale = 0.5;
|
shadowBorderScale = 0.5;
|
||||||
shadow = GETSHADOW(shadowMap1, projCoord1);
|
shadow = GETSHADOW(shadowMap1, projCoord1);
|
||||||
}else if( shadowPosition < splits.z){
|
}else if( shadowPosition < splits.z){
|
||||||
shadowBorderScale = 0.25;
|
shadowBorderScale = 0.25;
|
||||||
shadow = GETSHADOW(shadowMap2, projCoord2);
|
shadow = GETSHADOW(shadowMap2, projCoord2);
|
||||||
}else if( shadowPosition < splits.w){
|
}else if( shadowPosition < splits.w){
|
||||||
shadowBorderScale = 0.125;
|
shadowBorderScale = 0.125;
|
||||||
shadow = GETSHADOW(shadowMap3, projCoord3);
|
shadow = GETSHADOW(shadowMap3, projCoord3);
|
||||||
}
|
}
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
float getSpotLightShadows(SHADOWMAP shadowMap, vec4 projCoord){
|
float getSpotLightShadows(in SHADOWMAP shadowMap,in vec4 projCoord){
|
||||||
float shadow = 1.0;
|
float shadow = 1.0;
|
||||||
projCoord /= projCoord.w;
|
projCoord /= projCoord.w;
|
||||||
shadow = GETSHADOW(shadowMap, projCoord);
|
shadow = GETSHADOW(shadowMap,projCoord);
|
||||||
|
|
||||||
//a small falloff to make the shadow blend nicely into the not lighten
|
//a small falloff to make the shadow blend nicely into the not lighten
|
||||||
//we translate the texture coordinate value to a -1,1 range so the length
|
//we translate the texture coordinate value to a -1,1 range so the length
|
||||||
//of the texture coordinate vector is actually the radius of the lighten area on the ground
|
//of the texture coordinate vector is actually the radius of the lighten area on the ground
|
||||||
projCoord = projCoord * 2.0 - 1.0;
|
projCoord = projCoord * 2.0 - 1.0;
|
||||||
float fallOff = ( length(projCoord.xy) - 0.9 ) / 0.1;
|
float fallOff = ( length(projCoord.xy) - 0.9 ) / 0.1;
|
||||||
return mix(shadow,1.0,clamp(fallOff,0.0,1.0));
|
return mix(shadow,1.0,clamp(fallOff,0.0,1.0));
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,242 +0,0 @@
|
|||||||
// Because gpu_shader5 is actually where those
|
|
||||||
// gather functions are declared to work on shadowmaps
|
|
||||||
#extension GL_ARB_gpu_shader5 : enable
|
|
||||||
|
|
||||||
#ifdef HARDWARE_SHADOWS
|
|
||||||
#define SHADOWMAP sampler2DShadow
|
|
||||||
#define SHADOWCOMPAREOFFSET(tex,coord,offset) textureProjOffset(tex, coord, offset)
|
|
||||||
#define SHADOWCOMPARE(tex,coord) textureProj(tex, coord)
|
|
||||||
#define SHADOWGATHER(tex,coord) textureGather(tex, coord.xy, coord.z)
|
|
||||||
#else
|
|
||||||
#define SHADOWMAP sampler2D
|
|
||||||
#define SHADOWCOMPAREOFFSET(tex,coord,offset) step(coord.z, textureProjOffset(tex, coord, offset).r)
|
|
||||||
#define SHADOWCOMPARE(tex,coord) step(coord.z, textureProj(tex, coord).r)
|
|
||||||
#define SHADOWGATHER(tex,coord) step(coord.z, textureGather(tex, coord.xy))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if FILTER_MODE == 0
|
|
||||||
#define GETSHADOW Shadow_Nearest
|
|
||||||
#define KERNEL 1.0
|
|
||||||
#elif FILTER_MODE == 1
|
|
||||||
#ifdef HARDWARE_SHADOWS
|
|
||||||
#define GETSHADOW Shadow_Nearest
|
|
||||||
#else
|
|
||||||
#define GETSHADOW Shadow_DoBilinear_2x2
|
|
||||||
#endif
|
|
||||||
#define KERNEL 1.0
|
|
||||||
#elif FILTER_MODE == 2
|
|
||||||
#define GETSHADOW Shadow_DoDither_2x2
|
|
||||||
#define KERNEL 1.0
|
|
||||||
#elif FILTER_MODE == 3
|
|
||||||
#define GETSHADOW Shadow_DoPCF
|
|
||||||
#define KERNEL 4.0
|
|
||||||
#elif FILTER_MODE == 4
|
|
||||||
#define GETSHADOW Shadow_DoPCFPoisson
|
|
||||||
#define KERNEL 4.0
|
|
||||||
#elif FILTER_MODE == 5
|
|
||||||
#define GETSHADOW Shadow_DoPCF
|
|
||||||
#define KERNEL 8.0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uniform SHADOWMAP m_ShadowMap0;
|
|
||||||
uniform SHADOWMAP m_ShadowMap1;
|
|
||||||
uniform SHADOWMAP m_ShadowMap2;
|
|
||||||
uniform SHADOWMAP m_ShadowMap3;
|
|
||||||
#ifdef POINTLIGHT
|
|
||||||
uniform SHADOWMAP m_ShadowMap4;
|
|
||||||
uniform SHADOWMAP m_ShadowMap5;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PSSM
|
|
||||||
uniform vec4 m_Splits;
|
|
||||||
#endif
|
|
||||||
uniform float m_ShadowIntensity;
|
|
||||||
|
|
||||||
const vec2 pixSize2 = vec2(1.0 / SHADOWMAP_SIZE);
|
|
||||||
float shadowBorderScale = 1.0;
|
|
||||||
|
|
||||||
float Shadow_BorderCheck(in vec2 coord){
|
|
||||||
// Fastest, "hack" method (uses 4-5 instructions)
|
|
||||||
vec4 t = vec4(coord.xy, 0.0, 1.0);
|
|
||||||
t = step(t.wwxy, t.xyzz);
|
|
||||||
return dot(t,t);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Shadow_Nearest(in SHADOWMAP tex, in vec4 projCoord){
|
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
|
||||||
if (border > 0.0){
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
return SHADOWCOMPARE(tex,projCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Shadow_DoDither_2x2(in SHADOWMAP tex, in vec4 projCoord){
|
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
|
||||||
if (border > 0.0)
|
|
||||||
return 1.0;
|
|
||||||
|
|
||||||
vec2 pixSize = pixSize2 * shadowBorderScale;
|
|
||||||
|
|
||||||
float shadow = 0.0;
|
|
||||||
ivec2 o = ivec2(mod(floor(gl_FragCoord.xy), 2.0));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, 1.5)+o), projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, 1.5)+o), projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2(-1.5, -0.5)+o), projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy+pixSize*(vec2( 0.5, -0.5)+o), projCoord.zw));
|
|
||||||
shadow *= 0.25;
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Shadow_DoBilinear_2x2(in SHADOWMAP tex, in vec4 projCoord){
|
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
|
||||||
if (border > 0.0)
|
|
||||||
return 1.0;
|
|
||||||
|
|
||||||
#ifdef GL_ARB_gpu_shader5
|
|
||||||
vec4 coord = vec4(projCoord.xyz / projCoord.www,0.0);
|
|
||||||
vec4 gather = SHADOWGATHER(tex, coord);
|
|
||||||
#else
|
|
||||||
vec4 gather = vec4(0.0);
|
|
||||||
gather.x = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 1));
|
|
||||||
gather.y = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 1));
|
|
||||||
gather.z = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(1, 0));
|
|
||||||
gather.w = SHADOWCOMPAREOFFSET(tex, projCoord, ivec2(0, 0));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vec2 f = fract( projCoord.xy * SHADOWMAP_SIZE );
|
|
||||||
vec2 mx = mix( gather.wx, gather.zy, f.x );
|
|
||||||
return mix( mx.x, mx.y, f.y );
|
|
||||||
}
|
|
||||||
|
|
||||||
float Shadow_DoPCF(in SHADOWMAP tex, in vec4 projCoord){
|
|
||||||
|
|
||||||
vec2 pixSize = pixSize2 * shadowBorderScale;
|
|
||||||
float shadow = 0.0;
|
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
|
||||||
if (border > 0.0)
|
|
||||||
return 1.0;
|
|
||||||
|
|
||||||
float bound = KERNEL * 0.5 - 0.5;
|
|
||||||
bound *= PCFEDGE;
|
|
||||||
for (float y = -bound; y <= bound; y += PCFEDGE){
|
|
||||||
for (float x = -bound; x <= bound; x += PCFEDGE){
|
|
||||||
vec4 coord = vec4(projCoord.xy + vec2(x,y) * pixSize, projCoord.zw);
|
|
||||||
shadow += SHADOWCOMPARE(tex, coord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shadow = shadow / (KERNEL * KERNEL);
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//12 tap poisson disk
|
|
||||||
const vec2 poissonDisk0 = vec2(-0.1711046, -0.425016);
|
|
||||||
const vec2 poissonDisk1 = vec2(-0.7829809, 0.2162201);
|
|
||||||
const vec2 poissonDisk2 = vec2(-0.2380269, -0.8835521);
|
|
||||||
const vec2 poissonDisk3 = vec2(0.4198045, 0.1687819);
|
|
||||||
const vec2 poissonDisk4 = vec2(-0.684418, -0.3186957);
|
|
||||||
const vec2 poissonDisk5 = vec2(0.6026866, -0.2587841);
|
|
||||||
const vec2 poissonDisk6 = vec2(-0.2412762, 0.3913516);
|
|
||||||
const vec2 poissonDisk7 = vec2(0.4720655, -0.7664126);
|
|
||||||
const vec2 poissonDisk8 = vec2(0.9571564, 0.2680693);
|
|
||||||
const vec2 poissonDisk9 = vec2(-0.5238616, 0.802707);
|
|
||||||
const vec2 poissonDisk10 = vec2(0.5653144, 0.60262);
|
|
||||||
const vec2 poissonDisk11 = vec2(0.0123658, 0.8627419);
|
|
||||||
|
|
||||||
|
|
||||||
float Shadow_DoPCFPoisson(in SHADOWMAP tex, in vec4 projCoord){
|
|
||||||
|
|
||||||
float shadow = 0.0;
|
|
||||||
float border = Shadow_BorderCheck(projCoord.xy);
|
|
||||||
if (border > 0.0){
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 texelSize = pixSize2 * 4.0 * PCFEDGE * shadowBorderScale;
|
|
||||||
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk0 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk1 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk2 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk3 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk4 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk5 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk6 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk7 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk8 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk9 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk10 * texelSize, projCoord.zw));
|
|
||||||
shadow += SHADOWCOMPARE(tex, vec4(projCoord.xy + poissonDisk11 * texelSize, projCoord.zw));
|
|
||||||
|
|
||||||
//this is divided by 12
|
|
||||||
return shadow * 0.08333333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef POINTLIGHT
|
|
||||||
float getPointLightShadows(in vec4 worldPos,in vec3 lightPos,
|
|
||||||
in SHADOWMAP shadowMap0,in SHADOWMAP shadowMap1,in SHADOWMAP shadowMap2,in SHADOWMAP shadowMap3,in SHADOWMAP shadowMap4,in SHADOWMAP shadowMap5,
|
|
||||||
in vec4 projCoord0,in vec4 projCoord1,in vec4 projCoord2,in vec4 projCoord3,in vec4 projCoord4,in vec4 projCoord5){
|
|
||||||
float shadow = 1.0;
|
|
||||||
vec3 vect = worldPos.xyz - lightPos;
|
|
||||||
vec3 absv= abs(vect);
|
|
||||||
float maxComp = max(absv.x,max(absv.y,absv.z));
|
|
||||||
if(maxComp == absv.y){
|
|
||||||
if(vect.y < 0.0){
|
|
||||||
shadow = GETSHADOW(shadowMap0, projCoord0 / projCoord0.w);
|
|
||||||
}else{
|
|
||||||
shadow = GETSHADOW(shadowMap1, projCoord1 / projCoord1.w);
|
|
||||||
}
|
|
||||||
}else if(maxComp == absv.z){
|
|
||||||
if(vect.z < 0.0){
|
|
||||||
shadow = GETSHADOW(shadowMap2, projCoord2 / projCoord2.w);
|
|
||||||
}else{
|
|
||||||
shadow = GETSHADOW(shadowMap3, projCoord3 / projCoord3.w);
|
|
||||||
}
|
|
||||||
}else if(maxComp == absv.x){
|
|
||||||
if(vect.x < 0.0){
|
|
||||||
shadow = GETSHADOW(shadowMap4, projCoord4 / projCoord4.w);
|
|
||||||
}else{
|
|
||||||
shadow = GETSHADOW(shadowMap5, projCoord5 / projCoord5.w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#ifdef PSSM
|
|
||||||
float getDirectionalLightShadows(in vec4 splits,in float shadowPosition,
|
|
||||||
in SHADOWMAP shadowMap0,in SHADOWMAP shadowMap1,in SHADOWMAP shadowMap2,in SHADOWMAP shadowMap3,
|
|
||||||
in vec4 projCoord0,in vec4 projCoord1,in vec4 projCoord2,in vec4 projCoord3){
|
|
||||||
float shadow = 1.0;
|
|
||||||
if(shadowPosition < splits.x){
|
|
||||||
shadow = GETSHADOW(shadowMap0, projCoord0 );
|
|
||||||
}else if( shadowPosition < splits.y){
|
|
||||||
shadowBorderScale = 0.5;
|
|
||||||
shadow = GETSHADOW(shadowMap1, projCoord1);
|
|
||||||
}else if( shadowPosition < splits.z){
|
|
||||||
shadowBorderScale = 0.25;
|
|
||||||
shadow = GETSHADOW(shadowMap2, projCoord2);
|
|
||||||
}else if( shadowPosition < splits.w){
|
|
||||||
shadowBorderScale = 0.125;
|
|
||||||
shadow = GETSHADOW(shadowMap3, projCoord3);
|
|
||||||
}
|
|
||||||
return shadow;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
float getSpotLightShadows(in SHADOWMAP shadowMap,in vec4 projCoord){
|
|
||||||
float shadow = 1.0;
|
|
||||||
projCoord /= projCoord.w;
|
|
||||||
shadow = GETSHADOW(shadowMap,projCoord);
|
|
||||||
|
|
||||||
//a small falloff to make the shadow blend nicely into the not lighten
|
|
||||||
//we translate the texture coordinate value to a -1,1 range so the length
|
|
||||||
//of the texture coordinate vector is actually the radius of the lighten area on the ground
|
|
||||||
projCoord = projCoord * 2.0 - 1.0;
|
|
||||||
float fallOff = ( length(projCoord.xy) - 0.9 ) / 0.1;
|
|
||||||
return mix(shadow,1.0,clamp(fallOff,0.0,1.0));
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
@ -169,9 +169,23 @@ public class J3MLoader implements AssetLoader {
|
|||||||
return matchList;
|
return matchList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTexturePathDeclaredTheTraditionalWay(final int numberOfValues, final int numberOfTextureOptions, final String texturePath) {
|
private boolean isTexturePathDeclaredTheTraditionalWay(final List<TextureOptionValue> optionValues, final String texturePath) {
|
||||||
return (numberOfValues > 1 && (texturePath.startsWith("Flip Repeat ") || texturePath.startsWith("Flip ") ||
|
final boolean startsWithOldStyle = texturePath.startsWith("Flip Repeat ") || texturePath.startsWith("Flip ") ||
|
||||||
texturePath.startsWith("Repeat ") || texturePath.startsWith("Repeat Flip "))) || numberOfTextureOptions == 0;
|
texturePath.startsWith("Repeat ") || texturePath.startsWith("Repeat Flip ");
|
||||||
|
|
||||||
|
if (!startsWithOldStyle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionValues.size() == 1 && (optionValues.get(0).textureOption == TextureOption.Flip || optionValues.get(0).textureOption == TextureOption.Repeat)) {
|
||||||
|
return true;
|
||||||
|
} else if (optionValues.size() == 2 && optionValues.get(0).textureOption == TextureOption.Flip && optionValues.get(1).textureOption == TextureOption.Repeat) {
|
||||||
|
return true;
|
||||||
|
} else if (optionValues.size() == 2 && optionValues.get(0).textureOption == TextureOption.Repeat && optionValues.get(1).textureOption == TextureOption.Flip) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Texture parseTextureType(final VarType type, final String value) {
|
private Texture parseTextureType(final VarType type, final String value) {
|
||||||
@ -187,7 +201,7 @@ public class J3MLoader implements AssetLoader {
|
|||||||
String texturePath = value.trim();
|
String texturePath = value.trim();
|
||||||
|
|
||||||
// If there are no valid "new" texture options specified but the path is split into several parts, lets parse the old way.
|
// If there are no valid "new" texture options specified but the path is split into several parts, lets parse the old way.
|
||||||
if (isTexturePathDeclaredTheTraditionalWay(textureValues.size(), textureOptionValues.size(), texturePath)) {
|
if (isTexturePathDeclaredTheTraditionalWay(textureOptionValues, texturePath)) {
|
||||||
boolean flipY = false;
|
boolean flipY = false;
|
||||||
|
|
||||||
if (texturePath.startsWith("Flip Repeat ") || texturePath.startsWith("Repeat Flip ")) {
|
if (texturePath.startsWith("Flip Repeat ") || texturePath.startsWith("Repeat Flip ")) {
|
||||||
@ -623,6 +637,7 @@ public class J3MLoader implements AssetLoader {
|
|||||||
|
|
||||||
material = new Material(def);
|
material = new Material(def);
|
||||||
material.setKey(key);
|
material.setKey(key);
|
||||||
|
material.setName(split[0].trim());
|
||||||
// material.setAssetName(fileName);
|
// material.setAssetName(fileName);
|
||||||
}else if (split.length == 1){
|
}else if (split.length == 1){
|
||||||
if (extending){
|
if (extending){
|
||||||
|
@ -80,6 +80,7 @@ public class J3MLoaderTest {
|
|||||||
final Texture textureMin = Mockito.mock(Texture.class);
|
final Texture textureMin = Mockito.mock(Texture.class);
|
||||||
final Texture textureMag = Mockito.mock(Texture.class);
|
final Texture textureMag = Mockito.mock(Texture.class);
|
||||||
final Texture textureCombined = Mockito.mock(Texture.class);
|
final Texture textureCombined = Mockito.mock(Texture.class);
|
||||||
|
final Texture textureLooksLikeOldStyle = Mockito.mock(Texture.class);
|
||||||
|
|
||||||
final TextureKey textureKeyNoParameters = setupMockForTexture("Empty", "empty.png", false, textureNoParameters);
|
final TextureKey textureKeyNoParameters = setupMockForTexture("Empty", "empty.png", false, textureNoParameters);
|
||||||
final TextureKey textureKeyFlip = setupMockForTexture("Flip", "flip.png", true, textureFlip);
|
final TextureKey textureKeyFlip = setupMockForTexture("Flip", "flip.png", true, textureFlip);
|
||||||
@ -88,6 +89,7 @@ public class J3MLoaderTest {
|
|||||||
setupMockForTexture("Min", "min.png", false, textureMin);
|
setupMockForTexture("Min", "min.png", false, textureMin);
|
||||||
setupMockForTexture("Mag", "mag.png", false, textureMag);
|
setupMockForTexture("Mag", "mag.png", false, textureMag);
|
||||||
setupMockForTexture("Combined", "combined.png", true, textureCombined);
|
setupMockForTexture("Combined", "combined.png", true, textureCombined);
|
||||||
|
setupMockForTexture("LooksLikeOldStyle", "oldstyle.png", true, textureLooksLikeOldStyle);
|
||||||
|
|
||||||
j3MLoader.load(assetInfo);
|
j3MLoader.load(assetInfo);
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ Material Test : matdef.j3md {
|
|||||||
Min: MinTrilinear "min.png"
|
Min: MinTrilinear "min.png"
|
||||||
Mag: MagBilinear "mag.png"
|
Mag: MagBilinear "mag.png"
|
||||||
RepeatAxis: WrapRepeat_T "repeat-axis.png"
|
RepeatAxis: WrapRepeat_T "repeat-axis.png"
|
||||||
Combined: MagNearest MinBilinearNoMipMaps Flip WrapRepeat "combined.png"
|
Combined: Flip MagNearest MinBilinearNoMipMaps WrapRepeat "combined.png"
|
||||||
|
LooksLikeOldStyle: Flip WrapRepeat "oldstyle.png"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,6 +19,6 @@ void main(void)
|
|||||||
#ifdef NUM_BONES
|
#ifdef NUM_BONES
|
||||||
Skinning_Compute(modelSpacePos,modelSpaceNormals);
|
Skinning_Compute(modelSpacePos,modelSpaceNormals);
|
||||||
#endif
|
#endif
|
||||||
normal = normalize(g_NormalMatrix * modelSpaceNormals);
|
normal = normalize(TransformNormal(modelSpaceNormals));
|
||||||
gl_Position = g_WorldViewProjectionMatrix * modelSpacePos;
|
gl_Position = TransformWorldViewProjection(modelSpacePos);
|
||||||
}
|
}
|
@ -5,11 +5,15 @@ if (!hasProperty('mainClass')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task run(dependsOn: 'build', type:JavaExec) {
|
task run(dependsOn: 'build', type:JavaExec) {
|
||||||
main = mainClass
|
main = mainClass
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
if( assertions == "true" ){
|
if (System.properties['os.name'].toLowerCase().contains('mac')) {
|
||||||
enableAssertions = true;
|
jvmArgs "-XstartOnFirstThread"
|
||||||
}
|
jvmArgs "-Djava.awt.headless=true"
|
||||||
|
}
|
||||||
|
if( assertions == "true" ){
|
||||||
|
enableAssertions = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -260,8 +260,8 @@ public class TestChooser extends JDialog {
|
|||||||
for (int i = 0; i < appClass.length; i++) {
|
for (int i = 0; i < appClass.length; i++) {
|
||||||
Class<?> clazz = (Class)appClass[i];
|
Class<?> clazz = (Class)appClass[i];
|
||||||
try {
|
try {
|
||||||
Object app = clazz.newInstance();
|
if (Application.class.isAssignableFrom(clazz)) {
|
||||||
if (app instanceof Application) {
|
Object app = clazz.newInstance();
|
||||||
if (app instanceof SimpleApplication) {
|
if (app instanceof SimpleApplication) {
|
||||||
final Method settingMethod = clazz.getMethod("setShowSettings", boolean.class);
|
final Method settingMethod = clazz.getMethod("setShowSettings", boolean.class);
|
||||||
settingMethod.invoke(app, showSetting);
|
settingMethod.invoke(app, showSetting);
|
||||||
@ -283,7 +283,7 @@ public class TestChooser extends JDialog {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final Method mainMethod = clazz.getMethod("main", (new String[0]).getClass());
|
final Method mainMethod = clazz.getMethod("main", (new String[0]).getClass());
|
||||||
mainMethod.invoke(app, new Object[]{new String[0]});
|
mainMethod.invoke(clazz, new Object[]{new String[0]});
|
||||||
}
|
}
|
||||||
// wait for destroy
|
// wait for destroy
|
||||||
System.gc();
|
System.gc();
|
||||||
|
367
jme3-examples/src/main/java/jme3test/app/TestCloner.java
Normal file
367
jme3-examples/src/main/java/jme3test/app/TestCloner.java
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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 jme3test.app;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import com.jme3.util.clone.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class TestCloner {
|
||||||
|
|
||||||
|
public static void main( String... args ) {
|
||||||
|
|
||||||
|
System.out.println("Clone test:");
|
||||||
|
|
||||||
|
Cloner cloner = new Cloner();
|
||||||
|
|
||||||
|
RegularObject ro = new RegularObject(42);
|
||||||
|
System.out.println("Regular Object:" + ro);
|
||||||
|
RegularObject roCloneLegacy = ro.clone();
|
||||||
|
System.out.println("Regular Object Clone:" + roCloneLegacy);
|
||||||
|
RegularObject roClone = cloner.clone(ro);
|
||||||
|
System.out.println("cloner: Regular Object Clone:" + roClone);
|
||||||
|
|
||||||
|
System.out.println("------------------------------------");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
cloner = new Cloner();
|
||||||
|
RegularSubclass rsc = new RegularSubclass(69, "test");
|
||||||
|
System.out.println("Regular subclass:" + rsc);
|
||||||
|
RegularSubclass rscCloneLegacy = (RegularSubclass)rsc.clone();
|
||||||
|
System.out.println("Regular subclass Clone:" + rscCloneLegacy);
|
||||||
|
RegularSubclass rscClone = cloner.clone(rsc);
|
||||||
|
System.out.println("cloner: Regular subclass Clone:" + rscClone);
|
||||||
|
|
||||||
|
System.out.println("------------------------------------");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
cloner = new Cloner();
|
||||||
|
Parent parent = new Parent("Foo", 34);
|
||||||
|
System.out.println("Parent:" + parent);
|
||||||
|
Parent parentCloneLegacy = parent.clone();
|
||||||
|
System.out.println("Parent Clone:" + parentCloneLegacy);
|
||||||
|
Parent parentClone = cloner.clone(parent);
|
||||||
|
System.out.println("cloner: Parent Clone:" + parentClone);
|
||||||
|
|
||||||
|
System.out.println("------------------------------------");
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
cloner = new Cloner();
|
||||||
|
GraphNode root = new GraphNode("root");
|
||||||
|
GraphNode child1 = root.addLink("child1");
|
||||||
|
GraphNode child2 = root.addLink("child2");
|
||||||
|
GraphNode shared = child1.addLink("shared");
|
||||||
|
child2.addLink(shared);
|
||||||
|
|
||||||
|
// Add a circular reference to get fancy
|
||||||
|
shared.addLink(root);
|
||||||
|
|
||||||
|
System.out.println("Simple graph:");
|
||||||
|
root.dump(" ");
|
||||||
|
|
||||||
|
GraphNode rootClone = cloner.clone(root);
|
||||||
|
System.out.println("clone:");
|
||||||
|
rootClone.dump(" ");
|
||||||
|
|
||||||
|
System.out.println("original:");
|
||||||
|
root.dump(" ");
|
||||||
|
|
||||||
|
GraphNode reclone = Cloner.deepClone(root);
|
||||||
|
System.out.println("reclone:");
|
||||||
|
reclone.dump(" ");
|
||||||
|
|
||||||
|
System.out.println("------------------------------------");
|
||||||
|
System.out.println();
|
||||||
|
cloner = new Cloner();
|
||||||
|
|
||||||
|
ArrayHolder arrays = new ArrayHolder(5, 3, 7, 3, 7, 2, 1, 4);
|
||||||
|
System.out.println("Array holder:" + arrays);
|
||||||
|
ArrayHolder arraysClone = cloner.clone(arrays);
|
||||||
|
System.out.println("Array holder clone:" + arraysClone);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RegularObject implements Cloneable {
|
||||||
|
protected int i;
|
||||||
|
|
||||||
|
public RegularObject( int i ) {
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegularObject clone() {
|
||||||
|
try {
|
||||||
|
return (RegularObject)super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
||||||
|
+ "[i=" + i + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RegularSubclass extends RegularObject {
|
||||||
|
protected String name;
|
||||||
|
|
||||||
|
public RegularSubclass( int i, String name ) {
|
||||||
|
super(i);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
||||||
|
+ "[i=" + i + ", name=" + name + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Parent implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
|
private RegularObject ro;
|
||||||
|
private RegularSubclass rsc;
|
||||||
|
|
||||||
|
public Parent( String name, int age ) {
|
||||||
|
this.ro = new RegularObject(age);
|
||||||
|
this.rsc = new RegularSubclass(age, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Parent clone() {
|
||||||
|
try {
|
||||||
|
return (Parent)super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Parent jmeClone() {
|
||||||
|
// Ok to delegate to clone() in this case because no deep
|
||||||
|
// cloning is done there.
|
||||||
|
return clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.ro = cloner.clone(ro);
|
||||||
|
this.rsc = cloner.clone(rsc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
||||||
|
+ "[ro=" + ro + ", rsc=" + rsc + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GraphNode implements Cloneable, JmeCloneable {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private List<GraphNode> links = new ArrayList<>();
|
||||||
|
|
||||||
|
public GraphNode( String name ) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump( String indent ) {
|
||||||
|
dump(indent, new HashSet<GraphNode>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dump( String indent, Set<GraphNode> visited ) {
|
||||||
|
if( visited.contains(this) ) {
|
||||||
|
// already been here
|
||||||
|
System.out.println(indent + this + " ** circular.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.out.println(indent + this);
|
||||||
|
visited.add(this);
|
||||||
|
for( GraphNode n : links ) {
|
||||||
|
n.dump(indent + " ", visited);
|
||||||
|
}
|
||||||
|
visited.remove(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNode addLink( String name ) {
|
||||||
|
GraphNode node = new GraphNode(name);
|
||||||
|
links.add(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNode addLink( GraphNode node ) {
|
||||||
|
links.add(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<GraphNode> getLinks() {
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphNode jmeClone() {
|
||||||
|
try {
|
||||||
|
return (GraphNode)super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.links = cloner.clone(links);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
||||||
|
+ "[name=" + name + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ArrayHolder implements JmeCloneable {
|
||||||
|
|
||||||
|
private int[] intArray;
|
||||||
|
private int[][] intArray2D;
|
||||||
|
private Object[] objects;
|
||||||
|
private RegularObject[] regularObjects;
|
||||||
|
private String[] strings;
|
||||||
|
|
||||||
|
public ArrayHolder( int... values ) {
|
||||||
|
this.intArray = values;
|
||||||
|
this.intArray2D = new int[values.length][2];
|
||||||
|
for( int i = 0; i < values.length; i++ ) {
|
||||||
|
intArray2D[i][0] = values[i] + 1;
|
||||||
|
intArray2D[i][1] = values[i] * 2;
|
||||||
|
}
|
||||||
|
this.objects = new Object[values.length];
|
||||||
|
this.regularObjects = new RegularObject[values.length];
|
||||||
|
this.strings = new String[values.length];
|
||||||
|
for( int i = 0; i < values.length; i++ ) {
|
||||||
|
objects[i] = values[i];
|
||||||
|
regularObjects[i] = new RegularObject(values[i]);
|
||||||
|
strings[i] = String.valueOf(values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayHolder jmeClone() {
|
||||||
|
try {
|
||||||
|
return (ArrayHolder)super.clone();
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
intArray = cloner.clone(intArray);
|
||||||
|
intArray2D = cloner.clone(intArray2D);
|
||||||
|
|
||||||
|
// Boxed types are not cloneable so this will fail
|
||||||
|
//objects = cloner.clone(objects);
|
||||||
|
|
||||||
|
regularObjects = cloner.clone(regularObjects);
|
||||||
|
|
||||||
|
// Strings are also not cloneable
|
||||||
|
//strings = cloner.clone(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("intArray=" + intArray);
|
||||||
|
for( int i = 0; i < intArray.length; i++ ) {
|
||||||
|
if( i == 0 ) {
|
||||||
|
sb.append("[");
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(intArray[i]);
|
||||||
|
}
|
||||||
|
sb.append("], ");
|
||||||
|
|
||||||
|
sb.append("intArray2D=" + intArray2D);
|
||||||
|
for( int i = 0; i < intArray2D.length; i++ ) {
|
||||||
|
if( i == 0 ) {
|
||||||
|
sb.append("[");
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append("intArray2D[" + i + "]=" + intArray2D[i]);
|
||||||
|
for( int j = 0; j < 2; j++ ) {
|
||||||
|
if( j == 0 ) {
|
||||||
|
sb.append("[");
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(intArray2D[i][j]);
|
||||||
|
}
|
||||||
|
sb.append("], ");
|
||||||
|
}
|
||||||
|
sb.append("], ");
|
||||||
|
|
||||||
|
sb.append("objectArray=" + objects);
|
||||||
|
for( int i = 0; i < objects.length; i++ ) {
|
||||||
|
if( i == 0 ) {
|
||||||
|
sb.append("[");
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(objects[i]);
|
||||||
|
}
|
||||||
|
sb.append("], ");
|
||||||
|
|
||||||
|
sb.append("objectArray=" + regularObjects);
|
||||||
|
for( int i = 0; i < regularObjects.length; i++ ) {
|
||||||
|
if( i == 0 ) {
|
||||||
|
sb.append("[");
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(regularObjects[i]);
|
||||||
|
}
|
||||||
|
sb.append("], ");
|
||||||
|
|
||||||
|
sb.append("stringArray=" + strings);
|
||||||
|
for( int i = 0; i < strings.length; i++ ) {
|
||||||
|
if( i == 0 ) {
|
||||||
|
sb.append("[");
|
||||||
|
} else {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append(strings[i]);
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
|
||||||
|
return getClass().getSimpleName() + "@" + System.identityHashCode(this)
|
||||||
|
+ "[" + sb + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -46,13 +46,15 @@ import com.jme3.renderer.RenderManager;
|
|||||||
import com.jme3.renderer.ViewPort;
|
import com.jme3.renderer.ViewPort;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PhysicsHoverControl uses a RayCast Vehicle with "slippery wheels" to simulate a hovering tank
|
* PhysicsHoverControl uses a RayCast Vehicle with "slippery wheels" to simulate a hovering tank
|
||||||
* @author normenhansen
|
* @author normenhansen
|
||||||
*/
|
*/
|
||||||
public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsControl, PhysicsTickListener {
|
public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsControl, PhysicsTickListener, JmeCloneable {
|
||||||
|
|
||||||
protected Spatial spatial;
|
protected Spatial spatial;
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
@ -94,10 +96,21 @@ public class PhysicsHoverControl extends PhysicsVehicle implements PhysicsContro
|
|||||||
createWheels();
|
createWheels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
throw new UnsupportedOperationException("Not supported yet.");
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
this.spatial = spatial;
|
this.spatial = spatial;
|
||||||
setUserObject(spatial);
|
setUserObject(spatial);
|
||||||
|
@ -40,12 +40,14 @@ import com.jme3.input.controls.KeyTrigger;
|
|||||||
import com.jme3.light.AmbientLight;
|
import com.jme3.light.AmbientLight;
|
||||||
import com.jme3.light.DirectionalLight;
|
import com.jme3.light.DirectionalLight;
|
||||||
import com.jme3.material.Material;
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.material.RenderState;
|
||||||
import com.jme3.math.ColorRGBA;
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.math.FastMath;
|
import com.jme3.math.FastMath;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector2f;
|
import com.jme3.math.Vector2f;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.post.FilterPostProcessor;
|
import com.jme3.post.FilterPostProcessor;
|
||||||
|
import com.jme3.post.ssao.SSAOFilter;
|
||||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
@ -69,6 +71,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
private Geometry ground;
|
private Geometry ground;
|
||||||
private Material matGroundU;
|
private Material matGroundU;
|
||||||
private Material matGroundL;
|
private Material matGroundL;
|
||||||
|
private AmbientLight al;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
TestDirectionalLightShadow app = new TestDirectionalLightShadow();
|
TestDirectionalLightShadow app = new TestDirectionalLightShadow();
|
||||||
@ -99,7 +102,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
mat[0] = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
|
mat[0] = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
|
||||||
mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
|
mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
|
||||||
mat[1].setBoolean("UseMaterialColors", true);
|
mat[1].setBoolean("UseMaterialColors", true);
|
||||||
mat[1].setColor("Ambient", ColorRGBA.White.mult(0.5f));
|
mat[1].setColor("Ambient", ColorRGBA.White);
|
||||||
mat[1].setColor("Diffuse", ColorRGBA.White.clone());
|
mat[1].setColor("Diffuse", ColorRGBA.White.clone());
|
||||||
|
|
||||||
|
|
||||||
@ -110,9 +113,14 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
TangentBinormalGenerator.generate(obj[1]);
|
TangentBinormalGenerator.generate(obj[1]);
|
||||||
TangentBinormalGenerator.generate(obj[0]);
|
TangentBinormalGenerator.generate(obj[0]);
|
||||||
|
|
||||||
|
Spatial t = obj[0].clone(false);
|
||||||
|
t.setLocalScale(10f);
|
||||||
|
t.setMaterial(mat[1]);
|
||||||
|
rootNode.attachChild(t);
|
||||||
|
t.setLocalTranslation(0, 25, 0);
|
||||||
|
|
||||||
for (int i = 0; i < 60; i++) {
|
for (int i = 0; i < 60; i++) {
|
||||||
Spatial t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
|
t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
|
||||||
t.setLocalScale(FastMath.nextRandomFloat() * 10f);
|
t.setLocalScale(FastMath.nextRandomFloat() * 10f);
|
||||||
t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]);
|
t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]);
|
||||||
rootNode.attachChild(t);
|
rootNode.attachChild(t);
|
||||||
@ -142,8 +150,8 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
rootNode.addLight(l);
|
rootNode.addLight(l);
|
||||||
|
|
||||||
|
|
||||||
AmbientLight al = new AmbientLight();
|
al = new AmbientLight();
|
||||||
al.setColor(ColorRGBA.White.mult(0.5f));
|
al.setColor(ColorRGBA.White.mult(0.02f));
|
||||||
rootNode.addLight(al);
|
rootNode.addLight(al);
|
||||||
|
|
||||||
Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false);
|
Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false);
|
||||||
@ -156,8 +164,11 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
@Override
|
@Override
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp() {
|
||||||
// put the camera in a bad position
|
// put the camera in a bad position
|
||||||
cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f));
|
// cam.setLocation(new Vector3f(65.25412f, 44.38738f, 9.087874f));
|
||||||
cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f));
|
// cam.setRotation(new Quaternion(0.078139365f, 0.050241485f, -0.003942559f, 0.9956679f));
|
||||||
|
|
||||||
|
cam.setLocation(new Vector3f(3.3720117f, 42.838284f, -83.43792f));
|
||||||
|
cam.setRotation(new Quaternion(0.13833192f, -0.08969371f, 0.012581267f, 0.9862358f));
|
||||||
|
|
||||||
flyCam.setMoveSpeed(100);
|
flyCam.setMoveSpeed(100);
|
||||||
|
|
||||||
@ -166,7 +177,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
|
dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
|
||||||
dlsr.setLight(l);
|
dlsr.setLight(l);
|
||||||
dlsr.setLambda(0.55f);
|
dlsr.setLambda(0.55f);
|
||||||
dlsr.setShadowIntensity(0.6f);
|
dlsr.setShadowIntensity(0.8f);
|
||||||
dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
|
dlsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
|
||||||
dlsr.displayDebug();
|
dlsr.displayDebug();
|
||||||
viewPort.addProcessor(dlsr);
|
viewPort.addProcessor(dlsr);
|
||||||
@ -174,7 +185,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
|
dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
|
||||||
dlsf.setLight(l);
|
dlsf.setLight(l);
|
||||||
dlsf.setLambda(0.55f);
|
dlsf.setLambda(0.55f);
|
||||||
dlsf.setShadowIntensity(0.6f);
|
dlsf.setShadowIntensity(0.8f);
|
||||||
dlsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
|
dlsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
|
||||||
dlsf.setEnabled(false);
|
dlsf.setEnabled(false);
|
||||||
|
|
||||||
@ -205,10 +216,11 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
inputManager.addMapping("fwd", new KeyTrigger(KeyInput.KEY_PGUP));
|
inputManager.addMapping("fwd", new KeyTrigger(KeyInput.KEY_PGUP));
|
||||||
inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_PGDN));
|
inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_PGDN));
|
||||||
inputManager.addMapping("pp", new KeyTrigger(KeyInput.KEY_P));
|
inputManager.addMapping("pp", new KeyTrigger(KeyInput.KEY_P));
|
||||||
|
inputManager.addMapping("backShadows", new KeyTrigger(KeyInput.KEY_B));
|
||||||
|
|
||||||
|
|
||||||
inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown",
|
inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown",
|
||||||
"switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp", "stabilize", "distance");
|
"switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp", "stabilize", "distance", "ShadowUp", "ShadowDown", "backShadows");
|
||||||
|
|
||||||
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort);
|
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort);
|
||||||
|
|
||||||
@ -255,12 +267,19 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
|
|||||||
dlsf.setLambda(dlsr.getLambda() - 0.01f);
|
dlsf.setLambda(dlsr.getLambda() - 0.01f);
|
||||||
System.out.println("Lambda : " + dlsr.getLambda());
|
System.out.println("Lambda : " + dlsr.getLambda());
|
||||||
}
|
}
|
||||||
|
if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && keyPressed) {
|
||||||
|
al.setColor(ColorRGBA.White.mult((1 - dlsr.getShadowIntensity()) * 0.2f));
|
||||||
|
}
|
||||||
|
|
||||||
if (name.equals("debug") && keyPressed) {
|
if (name.equals("debug") && keyPressed) {
|
||||||
dlsr.displayFrustum();
|
dlsr.displayFrustum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name.equals("backShadows") && keyPressed) {
|
||||||
|
dlsr.setRenderBackFacesShadows(!dlsr.isRenderBackFacesShadows());
|
||||||
|
dlsf.setRenderBackFacesShadows(!dlsf.isRenderBackFacesShadows());
|
||||||
|
}
|
||||||
|
|
||||||
if (name.equals("stabilize") && keyPressed) {
|
if (name.equals("stabilize") && keyPressed) {
|
||||||
dlsr.setEnabledStabilization(!dlsr.isEnabledStabilization());
|
dlsr.setEnabledStabilization(!dlsr.isEnabledStabilization());
|
||||||
dlsf.setEnabledStabilization(!dlsf.isEnabledStabilization());
|
dlsf.setEnabledStabilization(!dlsf.isEnabledStabilization());
|
||||||
|
@ -32,7 +32,10 @@
|
|||||||
package jme3test.light;
|
package jme3test.light;
|
||||||
|
|
||||||
import com.jme3.app.SimpleApplication;
|
import com.jme3.app.SimpleApplication;
|
||||||
|
import com.jme3.input.controls.ActionListener;
|
||||||
|
import com.jme3.light.AmbientLight;
|
||||||
import com.jme3.light.PointLight;
|
import com.jme3.light.PointLight;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
import com.jme3.math.Quaternion;
|
import com.jme3.math.Quaternion;
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
import com.jme3.post.FilterPostProcessor;
|
import com.jme3.post.FilterPostProcessor;
|
||||||
@ -45,7 +48,7 @@ import com.jme3.shadow.EdgeFilteringMode;
|
|||||||
import com.jme3.shadow.PointLightShadowFilter;
|
import com.jme3.shadow.PointLightShadowFilter;
|
||||||
import com.jme3.shadow.PointLightShadowRenderer;
|
import com.jme3.shadow.PointLightShadowRenderer;
|
||||||
|
|
||||||
public class TestPointLightShadows extends SimpleApplication {
|
public class TestPointLightShadows extends SimpleApplication implements ActionListener{
|
||||||
public static final int SHADOWMAP_SIZE = 512;
|
public static final int SHADOWMAP_SIZE = 512;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@ -55,13 +58,19 @@ public class TestPointLightShadows extends SimpleApplication {
|
|||||||
Node lightNode;
|
Node lightNode;
|
||||||
PointLightShadowRenderer plsr;
|
PointLightShadowRenderer plsr;
|
||||||
PointLightShadowFilter plsf;
|
PointLightShadowFilter plsf;
|
||||||
|
AmbientLight al;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp () {
|
||||||
flyCam.setMoveSpeed(10);
|
flyCam.setMoveSpeed(10);
|
||||||
cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f));
|
cam.setLocation(new Vector3f(0.040581334f, 1.7745866f, 6.155161f));
|
||||||
cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f));
|
cam.setRotation(new Quaternion(4.3868728E-5f, 0.9999293f, -0.011230096f, 0.0039059948f));
|
||||||
|
|
||||||
|
al = new AmbientLight(ColorRGBA.White.mult(0.02f));
|
||||||
|
rootNode.addLight(al);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o");
|
Node scene = (Node) assetManager.loadModel("Models/Test/CornellBox.j3o");
|
||||||
scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
|
scene.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
|
||||||
@ -89,6 +98,7 @@ public class TestPointLightShadows extends SimpleApplication {
|
|||||||
plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
|
plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
|
||||||
plsr.setShadowZExtend(15);
|
plsr.setShadowZExtend(15);
|
||||||
plsr.setShadowZFadeLength(5);
|
plsr.setShadowZFadeLength(5);
|
||||||
|
plsr.setShadowIntensity(0.9f);
|
||||||
// plsr.setFlushQueues(false);
|
// plsr.setFlushQueues(false);
|
||||||
//plsr.displayFrustum();
|
//plsr.displayFrustum();
|
||||||
plsr.displayDebug();
|
plsr.displayDebug();
|
||||||
@ -99,18 +109,27 @@ public class TestPointLightShadows extends SimpleApplication {
|
|||||||
plsf.setLight((PointLight) scene.getLocalLightList().get(0));
|
plsf.setLight((PointLight) scene.getLocalLightList().get(0));
|
||||||
plsf.setShadowZExtend(15);
|
plsf.setShadowZExtend(15);
|
||||||
plsf.setShadowZFadeLength(5);
|
plsf.setShadowZFadeLength(5);
|
||||||
|
plsf.setShadowIntensity(0.8f);
|
||||||
plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
|
plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
|
||||||
plsf.setEnabled(false);
|
plsf.setEnabled(false);
|
||||||
|
|
||||||
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
|
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
|
||||||
fpp.addFilter(plsf);
|
fpp.addFilter(plsf);
|
||||||
viewPort.addProcessor(fpp);
|
viewPort.addProcessor(fpp);
|
||||||
|
inputManager.addListener(this,"ShadowUp","ShadowDown");
|
||||||
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
|
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void simpleUpdate(float tpf) {
|
public void simpleUpdate(float tpf) {
|
||||||
// lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f);
|
// lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAction(String name, boolean isPressed, float tpf) {
|
||||||
|
if ((name.equals("ShadowUp") || name.equals("ShadowDown")) && isPressed) {
|
||||||
|
al.setColor(ColorRGBA.White.mult((1 - plsr.getShadowIntensity()) * 0.2f));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -67,6 +67,8 @@ import com.jme3.texture.Texture;
|
|||||||
import com.jme3.texture.Texture.WrapMode;
|
import com.jme3.texture.Texture.WrapMode;
|
||||||
import com.jme3.util.SkyFactory;
|
import com.jme3.util.SkyFactory;
|
||||||
import com.jme3.util.TangentBinormalGenerator;
|
import com.jme3.util.TangentBinormalGenerator;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class TestPssmShadow extends SimpleApplication implements ActionListener {
|
public class TestPssmShadow extends SimpleApplication implements ActionListener {
|
||||||
@ -249,10 +251,20 @@ public class TestPssmShadow extends SimpleApplication implements ActionListener
|
|||||||
time = 0;
|
time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class TestSpotLight extends SimpleApplication {
|
|||||||
Geometry lightMdl;
|
Geometry lightMdl;
|
||||||
public void setupLighting(){
|
public void setupLighting(){
|
||||||
AmbientLight al=new AmbientLight();
|
AmbientLight al=new AmbientLight();
|
||||||
al.setColor(ColorRGBA.White.mult(0.8f));
|
al.setColor(ColorRGBA.White.mult(0.02f));
|
||||||
rootNode.addLight(al);
|
rootNode.addLight(al);
|
||||||
|
|
||||||
spot=new SpotLight();
|
spot=new SpotLight();
|
||||||
|
@ -65,7 +65,7 @@ public class TestSpotLightShadows extends SimpleApplication {
|
|||||||
|
|
||||||
public void setupLighting() {
|
public void setupLighting() {
|
||||||
AmbientLight al = new AmbientLight();
|
AmbientLight al = new AmbientLight();
|
||||||
al.setColor(ColorRGBA.White.mult(0.3f));
|
al.setColor(ColorRGBA.White.mult(0.02f));
|
||||||
rootNode.addLight(al);
|
rootNode.addLight(al);
|
||||||
|
|
||||||
rootNode.setShadowMode(ShadowMode.CastAndReceive);
|
rootNode.setShadowMode(ShadowMode.CastAndReceive);
|
||||||
@ -132,11 +132,6 @@ public class TestSpotLightShadows extends SimpleApplication {
|
|||||||
}, "stop");
|
}, "stop");
|
||||||
|
|
||||||
inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_1));
|
inputManager.addMapping("stop", new KeyTrigger(KeyInput.KEY_1));
|
||||||
|
|
||||||
MaterialDebugAppState s = new MaterialDebugAppState();
|
|
||||||
s.registerBinding("Common/MatDefs/Shadow/PostShadow15.frag", rootNode);
|
|
||||||
s.registerBinding(new KeyTrigger(KeyInput.KEY_R), rootNode);
|
|
||||||
stateManager.attach(s);
|
|
||||||
flyCam.setDragToRotate(true);
|
flyCam.setDragToRotate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ public class TestSpotLightTerrain extends SimpleApplication {
|
|||||||
rootNode.addLight(sl);
|
rootNode.addLight(sl);
|
||||||
|
|
||||||
AmbientLight ambLight = new AmbientLight();
|
AmbientLight ambLight = new AmbientLight();
|
||||||
ambLight.setColor(new ColorRGBA(0.8f, 0.8f, 0.8f, 0.2f));
|
ambLight.setColor(ColorRGBA.Black);
|
||||||
rootNode.addLight(ambLight);
|
rootNode.addLight(ambLight);
|
||||||
|
|
||||||
cam.setLocation(new Vector3f(-41.219646f, -84.8363f, -171.67267f));
|
cam.setLocation(new Vector3f(-41.219646f, -84.8363f, -171.67267f));
|
||||||
|
@ -41,6 +41,8 @@ import java.awt.Component;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import jme3test.network.TestChatServer.ChatMessage;
|
import jme3test.network.TestChatServer.ChatMessage;
|
||||||
|
|
||||||
@ -115,6 +117,18 @@ public class TestChatClient extends JFrame {
|
|||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
|
|
||||||
|
// Increate the logging level for networking...
|
||||||
|
System.out.println("Setting logging to max");
|
||||||
|
Logger networkLog = Logger.getLogger("com.jme3.network");
|
||||||
|
networkLog.setLevel(Level.FINEST);
|
||||||
|
|
||||||
|
// And we have to tell JUL's handler also
|
||||||
|
// turn up logging in a very convoluted way
|
||||||
|
Logger rootLog = Logger.getLogger("");
|
||||||
|
if( rootLog.getHandlers().length > 0 ) {
|
||||||
|
rootLog.getHandlers()[0].setLevel(Level.FINEST);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: in JME 3.1 this is generally unnecessary as the server will
|
// Note: in JME 3.1 this is generally unnecessary as the server will
|
||||||
// send a message with all server-registered classes.
|
// send a message with all server-registered classes.
|
||||||
// TestChatServer.initializeClasses();
|
// TestChatServer.initializeClasses();
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
*/
|
*/
|
||||||
package jme3test.network;
|
package jme3test.network;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import com.jme3.network.*;
|
import com.jme3.network.*;
|
||||||
import com.jme3.network.serializing.Serializable;
|
import com.jme3.network.serializing.Serializable;
|
||||||
import com.jme3.network.serializing.Serializer;
|
import com.jme3.network.serializing.Serializer;
|
||||||
@ -56,11 +59,15 @@ public class TestChatServer {
|
|||||||
private boolean isRunning;
|
private boolean isRunning;
|
||||||
|
|
||||||
public TestChatServer() throws IOException {
|
public TestChatServer() throws IOException {
|
||||||
initializeClasses();
|
|
||||||
|
|
||||||
// Use this to test the client/server name version check
|
// Use this to test the client/server name version check
|
||||||
this.server = Network.createServer(NAME, VERSION, PORT, UDP_PORT);
|
this.server = Network.createServer(NAME, VERSION, PORT, UDP_PORT);
|
||||||
|
|
||||||
|
// Initialize our own messages only after the server has been created.
|
||||||
|
// It registers some additional messages with the serializer by default
|
||||||
|
// that need to go before custom messages.
|
||||||
|
initializeClasses();
|
||||||
|
|
||||||
ChatHandler handler = new ChatHandler();
|
ChatHandler handler = new ChatHandler();
|
||||||
server.addMessageListener(handler, ChatMessage.class);
|
server.addMessageListener(handler, ChatMessage.class);
|
||||||
|
|
||||||
@ -121,6 +128,18 @@ public class TestChatServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
|
|
||||||
|
// Increate the logging level for networking...
|
||||||
|
System.out.println("Setting logging to max");
|
||||||
|
Logger networkLog = Logger.getLogger("com.jme3.network");
|
||||||
|
networkLog.setLevel(Level.FINEST);
|
||||||
|
|
||||||
|
// And we have to tell JUL's handler also
|
||||||
|
// turn up logging in a very convoluted way
|
||||||
|
Logger rootLog = Logger.getLogger("");
|
||||||
|
if( rootLog.getHandlers().length > 0 ) {
|
||||||
|
rootLog.getHandlers()[0].setLevel(Level.FINEST);
|
||||||
|
}
|
||||||
|
|
||||||
TestChatServer chatServer = new TestChatServer();
|
TestChatServer chatServer = new TestChatServer();
|
||||||
chatServer.start();
|
chatServer.start();
|
||||||
|
@ -99,24 +99,6 @@ public abstract class LwjglContext implements JmeContext {
|
|||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void loadNatives() {
|
|
||||||
if (JmeSystem.isLowPermissions()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("LWJGL".equals(settings.getAudioRenderer())) {
|
|
||||||
NativeLibraryLoader.loadNativeLibrary("openal-lwjgl3", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NativeLibraryLoader.isUsingNativeBullet()) {
|
|
||||||
NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeLibraryLoader.loadNativeLibrary("glfw-lwjgl3", true);
|
|
||||||
NativeLibraryLoader.loadNativeLibrary("jemalloc-lwjgl3", true);
|
|
||||||
NativeLibraryLoader.loadNativeLibrary("lwjgl3", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getNumSamplesToUse() {
|
protected int getNumSamplesToUse() {
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
if (settings.getSamples() > 1) {
|
if (settings.getSamples() > 1) {
|
||||||
@ -134,6 +116,17 @@ public abstract class LwjglContext implements JmeContext {
|
|||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void loadNatives() {
|
||||||
|
if (JmeSystem.isLowPermissions()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NativeLibraryLoader.isUsingNativeBullet()) {
|
||||||
|
NativeLibraryLoader.loadNativeLibrary("bulletjme", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void initContextFirstTime() {
|
protected void initContextFirstTime() {
|
||||||
final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3));
|
final GLCapabilities capabilities = createCapabilities(settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3));
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
private GLFWWindowSizeCallback windowSizeCallback;
|
private GLFWWindowSizeCallback windowSizeCallback;
|
||||||
private GLFWWindowFocusCallback windowFocusCallback;
|
private GLFWWindowFocusCallback windowFocusCallback;
|
||||||
|
|
||||||
|
private Thread mainThread;
|
||||||
|
|
||||||
public LwjglWindow(final JmeContext.Type type) {
|
public LwjglWindow(final JmeContext.Type type) {
|
||||||
if (!JmeContext.Type.Display.equals(type) && !JmeContext.Type.OffscreenSurface.equals(type) && !JmeContext.Type.Canvas.equals(type)) {
|
if (!JmeContext.Type.Display.equals(type) && !JmeContext.Type.OffscreenSurface.equals(type) && !JmeContext.Type.Canvas.equals(type)) {
|
||||||
throw new IllegalArgumentException("Unsupported type '" + type.name() + "' provided");
|
throw new IllegalArgumentException("Unsupported type '" + type.name() + "' provided");
|
||||||
@ -210,7 +212,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void invoke(final long window, final int focused) {
|
public void invoke(final long window, final int focused) {
|
||||||
final boolean focus = (focused == GL_TRUE);
|
final boolean focus = (focused == GL_TRUE);
|
||||||
|
|
||||||
if (wasActive != focus) {
|
if (wasActive != focus) {
|
||||||
if (!wasActive) {
|
if (!wasActive) {
|
||||||
listener.gainFocus();
|
listener.gainFocus();
|
||||||
@ -241,10 +242,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
glfwSwapInterval(0);
|
glfwSwapInterval(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the window visible
|
|
||||||
if (Type.Display.equals(type)) {
|
|
||||||
glfwShowWindow(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwShowWindow(window);
|
glfwShowWindow(window);
|
||||||
|
|
||||||
@ -286,17 +283,16 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void create(boolean waitFor) {
|
public void create(boolean waitFor) {
|
||||||
if (created.get()) {
|
if (created.get()) {
|
||||||
LOGGER.warning("create() called when display is already created!");
|
LOGGER.warning("create() called when display is already created!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new Thread(this, THREAD_NAME).start();
|
// NOTE: this is required for Mac OS X!
|
||||||
|
mainThread = Thread.currentThread();
|
||||||
if (waitFor) {
|
run();
|
||||||
waitFor(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,6 +303,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
if (!JmeSystem.isLowPermissions()) {
|
if (!JmeSystem.isLowPermissions()) {
|
||||||
// Enable uncaught exception handler only for current thread
|
// Enable uncaught exception handler only for current thread
|
||||||
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||||
|
@Override
|
||||||
public void uncaughtException(Thread thread, Throwable thrown) {
|
public void uncaughtException(Thread thread, Throwable thrown) {
|
||||||
listener.handleError("Uncaught exception thrown in " + thread.toString(), thrown);
|
listener.handleError("Uncaught exception thrown in " + thread.toString(), thrown);
|
||||||
if (needClose.get()) {
|
if (needClose.get()) {
|
||||||
@ -318,6 +315,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadNatives();
|
||||||
|
|
||||||
timer = new NanoTimer();
|
timer = new NanoTimer();
|
||||||
|
|
||||||
// For canvas, this will create a pbuffer,
|
// For canvas, this will create a pbuffer,
|
||||||
@ -434,13 +433,13 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
LOGGER.fine("Display destroyed.");
|
LOGGER.fine("Display destroyed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
throw new IllegalStateException("SystemListener is not set on context!"
|
throw new IllegalStateException("SystemListener is not set on context!"
|
||||||
+ "Must set with JmeContext.setSystemListener().");
|
+ "Must set with JmeContext.setSystemListener().");
|
||||||
}
|
}
|
||||||
|
|
||||||
loadNatives();
|
|
||||||
LOGGER.log(Level.FINE, "Using LWJGL {0}", Version.getVersion());
|
LOGGER.log(Level.FINE, "Using LWJGL {0}", Version.getVersion());
|
||||||
|
|
||||||
if (!initInThread()) {
|
if (!initInThread()) {
|
||||||
@ -497,6 +496,11 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable {
|
|||||||
public void destroy(boolean waitFor) {
|
public void destroy(boolean waitFor) {
|
||||||
needClose.set(true);
|
needClose.set(true);
|
||||||
|
|
||||||
|
if (mainThread == Thread.currentThread()) {
|
||||||
|
// Ignore waitFor.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (waitFor) {
|
if (waitFor) {
|
||||||
waitFor(false);
|
waitFor(false);
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,5 @@ sourceSets {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':jme3-core')
|
compile project(':jme3-core')
|
||||||
|
testCompile project(':jme3-desktop')
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.material.plugin.export.material;
|
||||||
|
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.export.Savable;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.material.MaterialDef;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a Material to a j3m file with proper formatting.
|
||||||
|
*
|
||||||
|
* usage is :
|
||||||
|
* <pre>
|
||||||
|
* J3MExporter exporter = new J3MExporter();
|
||||||
|
* exporter.save(material, myFile);
|
||||||
|
* //or
|
||||||
|
* exporter.save(material, myOutputStream);
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author tsr
|
||||||
|
* @author nehon (documentation and safety check)
|
||||||
|
*/
|
||||||
|
public class J3MExporter implements JmeExporter {
|
||||||
|
|
||||||
|
private final J3MRootOutputCapsule rootCapsule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a J3MExporter
|
||||||
|
*/
|
||||||
|
public J3MExporter() {
|
||||||
|
rootCapsule = new J3MRootOutputCapsule(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(Savable object, OutputStream f) throws IOException {
|
||||||
|
|
||||||
|
if (!(object instanceof Material)) {
|
||||||
|
throw new IllegalArgumentException("J3MExporter can only save com.jme3.material.Material class");
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStreamWriter out = new OutputStreamWriter(f, Charset.forName("UTF-8"));
|
||||||
|
|
||||||
|
rootCapsule.clear();
|
||||||
|
object.write(this);
|
||||||
|
rootCapsule.writeToStream(out);
|
||||||
|
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(Savable object, File f) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(f)) {
|
||||||
|
save(object, fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OutputCapsule getCapsule(Savable object) {
|
||||||
|
if ((object instanceof Material) || (object instanceof MaterialDef)) {
|
||||||
|
return rootCapsule;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootCapsule.getCapsule(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,383 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.material.plugin.export.material;
|
||||||
|
|
||||||
|
import com.jme3.asset.TextureKey;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.export.Savable;
|
||||||
|
import com.jme3.material.MatParam;
|
||||||
|
import com.jme3.material.MatParamTexture;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
import com.jme3.shader.VarType;
|
||||||
|
import com.jme3.texture.Texture;
|
||||||
|
import com.jme3.texture.Texture.WrapMode;
|
||||||
|
import com.jme3.util.IntMap;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.BitSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author tsr
|
||||||
|
*/
|
||||||
|
public class J3MOutputCapsule implements OutputCapsule {
|
||||||
|
|
||||||
|
private final HashMap<String, String> parameters;
|
||||||
|
protected final J3MExporter exporter;
|
||||||
|
|
||||||
|
public J3MOutputCapsule(J3MExporter exporter) {
|
||||||
|
this.exporter = exporter;
|
||||||
|
parameters = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeToStream(OutputStreamWriter out) throws IOException {
|
||||||
|
for (String key : parameters.keySet()) {
|
||||||
|
out.write(" ");
|
||||||
|
writeParameter(out, key, parameters.get(key));
|
||||||
|
out.write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeParameter(OutputStreamWriter out, String name, String value) throws IOException {
|
||||||
|
out.write(name);
|
||||||
|
out.write(" : ");
|
||||||
|
out.write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
parameters.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void putParameter(String name, String value) {
|
||||||
|
parameters.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(boolean value, String name, boolean defVal) throws IOException {
|
||||||
|
if (value == defVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
putParameter(name, ((value) ? "On" : "Off"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeStringSavableMap(Map<String, ? extends Savable> map, String name, Map<String, ? extends Savable> defVal) throws IOException {
|
||||||
|
for (String key : map.keySet()) {
|
||||||
|
Savable value = map.get(key);
|
||||||
|
if (defVal == null || !defVal.containsKey(key) || !defVal.get(key).equals(value)) {
|
||||||
|
putParameter(key, format(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String format(Savable value) {
|
||||||
|
if (value instanceof MatParamTexture) {
|
||||||
|
return formatMatParamTexture((MatParamTexture) value);
|
||||||
|
}
|
||||||
|
if (value instanceof MatParam) {
|
||||||
|
return formatMatParam((MatParam) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException(value.getClass() + ": Not supported yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatMatParam(MatParam param){
|
||||||
|
VarType type = param.getVarType();
|
||||||
|
Object val = param.getValue();
|
||||||
|
switch (type) {
|
||||||
|
case Boolean:
|
||||||
|
case Float:
|
||||||
|
case Int:
|
||||||
|
return val.toString();
|
||||||
|
case Vector2:
|
||||||
|
Vector2f v2 = (Vector2f) val;
|
||||||
|
return v2.getX() + " " + v2.getY();
|
||||||
|
case Vector3:
|
||||||
|
Vector3f v3 = (Vector3f) val;
|
||||||
|
return v3.getX() + " " + v3.getY() + " " + v3.getZ();
|
||||||
|
case Vector4:
|
||||||
|
// can be either ColorRGBA, Vector4f or Quaternion
|
||||||
|
if (val instanceof Vector4f) {
|
||||||
|
Vector4f v4 = (Vector4f) val;
|
||||||
|
return v4.getX() + " " + v4.getY() + " "
|
||||||
|
+ v4.getZ() + " " + v4.getW();
|
||||||
|
} else if (val instanceof ColorRGBA) {
|
||||||
|
ColorRGBA color = (ColorRGBA) val;
|
||||||
|
return color.getRed() + " " + color.getGreen() + " "
|
||||||
|
+ color.getBlue() + " " + color.getAlpha();
|
||||||
|
} else if (val instanceof Quaternion) {
|
||||||
|
Quaternion quat = (Quaternion) val;
|
||||||
|
return quat.getX() + " " + quat.getY() + " "
|
||||||
|
+ quat.getZ() + " " + quat.getW();
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Unexpected Vector4 type: " + val);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return null; // parameter type not supported in J3M
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String formatMatParamTexture(MatParamTexture param) {
|
||||||
|
StringBuilder ret = new StringBuilder();
|
||||||
|
Texture tex = (Texture) param.getValue();
|
||||||
|
TextureKey key;
|
||||||
|
if (tex != null) {
|
||||||
|
key = (TextureKey) tex.getKey();
|
||||||
|
|
||||||
|
if (key != null && key.isFlipY()) {
|
||||||
|
ret.append("Flip ");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.append(formatWrapMode(tex, Texture.WrapAxis.S));
|
||||||
|
ret.append(formatWrapMode(tex, Texture.WrapAxis.T));
|
||||||
|
ret.append(formatWrapMode(tex, Texture.WrapAxis.R));
|
||||||
|
|
||||||
|
//Min and Mag filter
|
||||||
|
Texture.MinFilter def = Texture.MinFilter.BilinearNoMipMaps;
|
||||||
|
if (tex.getImage().hasMipmaps() || (key != null && key.isGenerateMips())) {
|
||||||
|
def = Texture.MinFilter.Trilinear;
|
||||||
|
}
|
||||||
|
if (tex.getMinFilter() != def) {
|
||||||
|
ret.append("Min").append(tex.getMinFilter().name()).append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tex.getMagFilter() != Texture.MagFilter.Bilinear) {
|
||||||
|
ret.append("Mag").append(tex.getMagFilter().name()).append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret.append("\"").append(key.getName()).append("\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static String formatWrapMode(Texture texVal, Texture.WrapAxis axis) {
|
||||||
|
WrapMode mode;
|
||||||
|
try {
|
||||||
|
mode = texVal.getWrap(axis);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
//this axis doesn't exist on the texture
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (mode != WrapMode.EdgeClamp) {
|
||||||
|
return "Wrap" + mode.name() + "_" + axis.name() + " ";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Enum value, String name, Enum defVal) throws IOException {
|
||||||
|
if (value == defVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
putParameter(name, value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(float value, String name, float defVal) throws IOException {
|
||||||
|
if (value == defVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
putParameter(name, Float.toString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(float[] value, String name, float[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(float[][] value, String name, float[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(double value, String name, double defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(double[] value, String name, double[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(double[][] value, String name, double[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(long value, String name, long defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(long[] value, String name, long[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(long[][] value, String name, long[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(short value, String name, short defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(short[] value, String name, short[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(short[][] value, String name, short[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(boolean[] value, String name, boolean[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(boolean[][] value, String name, boolean[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String value, String name, String defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String[] value, String name, String[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String[][] value, String name, String[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(BitSet value, String name, BitSet defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Savable object, String name, Savable defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Savable[] objects, String name, Savable[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Savable[][] objects, String name, Savable[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSavableArrayList(ArrayList array, String name, ArrayList defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSavableArrayListArray(ArrayList[] array, String name, ArrayList[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSavableArrayListArray2D(ArrayList[][] array, String name, ArrayList[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeFloatBufferArrayList(ArrayList<FloatBuffer> array, String name, ArrayList<FloatBuffer> defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeByteBufferArrayList(ArrayList<ByteBuffer> array, String name, ArrayList<ByteBuffer> defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSavableMap(Map<? extends Savable, ? extends Savable> map, String name, Map<? extends Savable, ? extends Savable> defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeIntSavableMap(IntMap<? extends Savable> map, String name, IntMap<? extends Savable> defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(FloatBuffer value, String name, FloatBuffer defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(IntBuffer value, String name, IntBuffer defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ByteBuffer value, String name, ByteBuffer defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ShortBuffer value, String name, ShortBuffer defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte value, String name, byte defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] value, String name, byte[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[][] value, String name, byte[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int value, String name, int defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int[] value, String name, int[] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int[][] value, String name, int[][] defVal) throws IOException {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.material.plugin.export.material;
|
||||||
|
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.export.Savable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author tsr
|
||||||
|
*/
|
||||||
|
public class J3MRenderStateOutputCapsule extends J3MOutputCapsule {
|
||||||
|
protected final static HashMap<String, String> NAME_MAP;
|
||||||
|
protected String offsetUnit;
|
||||||
|
|
||||||
|
static {
|
||||||
|
NAME_MAP = new HashMap<>();
|
||||||
|
NAME_MAP.put( "wireframe", "Wireframe");
|
||||||
|
NAME_MAP.put( "cullMode", "FaceCull");
|
||||||
|
NAME_MAP.put( "depthWrite", "DepthWrite");
|
||||||
|
NAME_MAP.put( "depthTest", "DepthTest");
|
||||||
|
NAME_MAP.put( "blendMode", "Blend");
|
||||||
|
NAME_MAP.put( "alphaFallOff", "AlphaTestFalloff");
|
||||||
|
NAME_MAP.put( "offsetFactor", "PolyOffset");
|
||||||
|
NAME_MAP.put( "colorWrite", "ColorWrite");
|
||||||
|
NAME_MAP.put( "pointSprite", "PointSprite");
|
||||||
|
NAME_MAP.put( "depthFunc", "DepthFunc");
|
||||||
|
NAME_MAP.put( "alphaFunc", "AlphaFunc");
|
||||||
|
}
|
||||||
|
public J3MRenderStateOutputCapsule(J3MExporter exporter) {
|
||||||
|
super(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputCapsule getCapsule(Savable object) {
|
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
super.clear();
|
||||||
|
offsetUnit = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToStream(OutputStreamWriter out) throws IOException {
|
||||||
|
out.write(" AdditionalRenderState {\n");
|
||||||
|
super.writeToStream(out);
|
||||||
|
out.write(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeParameter(OutputStreamWriter out, String name, String value) throws IOException {
|
||||||
|
out.write(name);
|
||||||
|
out.write(" ");
|
||||||
|
out.write(value);
|
||||||
|
|
||||||
|
if( "PolyOffset".equals(name) ) {
|
||||||
|
out.write(" ");
|
||||||
|
out.write(offsetUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void putParameter(String name, String value ) {
|
||||||
|
if( "offsetUnits".equals(name) ) {
|
||||||
|
offsetUnit = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !NAME_MAP.containsKey(name) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
super.putParameter(NAME_MAP.get(name), value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.material.plugin.export.material;
|
||||||
|
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.export.Savable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tsr
|
||||||
|
*/
|
||||||
|
public class J3MRootOutputCapsule extends J3MOutputCapsule {
|
||||||
|
|
||||||
|
private final HashMap<Savable, J3MOutputCapsule> outCapsules;
|
||||||
|
private String name;
|
||||||
|
private String materialDefinition;
|
||||||
|
private Boolean isTransparent;
|
||||||
|
|
||||||
|
public J3MRootOutputCapsule(J3MExporter exporter) {
|
||||||
|
super(exporter);
|
||||||
|
outCapsules = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
super.clear();
|
||||||
|
isTransparent = null;
|
||||||
|
name = "";
|
||||||
|
materialDefinition = "";
|
||||||
|
outCapsules.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public OutputCapsule getCapsule(Savable object) {
|
||||||
|
if (!outCapsules.containsKey(object)) {
|
||||||
|
outCapsules.put(object, new J3MRenderStateOutputCapsule(exporter));
|
||||||
|
}
|
||||||
|
|
||||||
|
return outCapsules.get(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToStream(OutputStreamWriter out) throws IOException {
|
||||||
|
out.write("Material " + name + " : " + materialDefinition + " {\n\n");
|
||||||
|
if (isTransparent != null)
|
||||||
|
out.write(" Transparent " + ((isTransparent) ? "On" : "Off") + "\n\n");
|
||||||
|
|
||||||
|
out.write(" MaterialParameters {\n");
|
||||||
|
super.writeToStream(out);
|
||||||
|
out.write(" }\n\n");
|
||||||
|
|
||||||
|
for (J3MOutputCapsule c : outCapsules.values()) {
|
||||||
|
c.writeToStream(out);
|
||||||
|
}
|
||||||
|
out.write("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String value, String name, String defVal) throws IOException {
|
||||||
|
switch (name) {
|
||||||
|
case "material_def":
|
||||||
|
materialDefinition = value;
|
||||||
|
break;
|
||||||
|
case "name":
|
||||||
|
this.name = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException(name + " string material parameter not supported yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(boolean value, String name, boolean defVal) throws IOException {
|
||||||
|
if( value == defVal)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (name) {
|
||||||
|
case "is_transparent":
|
||||||
|
isTransparent = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException(name + " boolean material parameter not supported yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Savable object, String name, Savable defVal) throws IOException {
|
||||||
|
if(object != null && !object.equals(defVal)) {
|
||||||
|
object.write(exporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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.material.plugin;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetInfo;
|
||||||
|
import com.jme3.asset.AssetKey;
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.material.RenderState;
|
||||||
|
import com.jme3.material.plugin.export.material.J3MExporter;
|
||||||
|
import com.jme3.material.plugins.J3MLoader;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.system.JmeSystem;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import com.jme3.texture.Texture;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class TestMaterialWrite {
|
||||||
|
|
||||||
|
private AssetManager assetManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
assetManager = JmeSystem.newAssetManager(
|
||||||
|
TestMaterialWrite.class.getResource("/com/jme3/asset/Desktop.cfg"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteMat() throws Exception {
|
||||||
|
|
||||||
|
Material mat = new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md");
|
||||||
|
|
||||||
|
mat.setBoolean("UseMaterialColors", true);
|
||||||
|
mat.setColor("Diffuse", ColorRGBA.White);
|
||||||
|
mat.setColor("Ambient", ColorRGBA.DarkGray);
|
||||||
|
mat.setFloat("AlphaDiscardThreshold", 0.5f);
|
||||||
|
|
||||||
|
mat.setFloat("Shininess", 2.5f);
|
||||||
|
|
||||||
|
Texture tex = assetManager.loadTexture("Common/Textures/MissingTexture.png");
|
||||||
|
tex.setMagFilter(Texture.MagFilter.Nearest);
|
||||||
|
tex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
||||||
|
tex.setWrap(Texture.WrapAxis.S, Texture.WrapMode.Repeat);
|
||||||
|
tex.setWrap(Texture.WrapAxis.T, Texture.WrapMode.MirroredRepeat);
|
||||||
|
|
||||||
|
mat.setTexture("DiffuseMap", tex);
|
||||||
|
mat.getAdditionalRenderState().setDepthWrite(false);
|
||||||
|
mat.getAdditionalRenderState().setDepthTest(false);
|
||||||
|
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
|
||||||
|
|
||||||
|
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
J3MExporter exporter = new J3MExporter();
|
||||||
|
try {
|
||||||
|
exporter.save(mat, stream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println(stream.toString());
|
||||||
|
|
||||||
|
J3MLoader loader = new J3MLoader();
|
||||||
|
AssetInfo info = new AssetInfo(assetManager, new AssetKey("test")) {
|
||||||
|
@Override
|
||||||
|
public InputStream openStream() {
|
||||||
|
return new ByteArrayInputStream(stream.toByteArray());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Material mat2 = (Material)loader.load(info);
|
||||||
|
|
||||||
|
assertTrue(mat.contentEquals(mat2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -40,6 +40,8 @@ import com.jme3.renderer.ViewPort;
|
|||||||
import com.jme3.scene.Spatial;
|
import com.jme3.scene.Spatial;
|
||||||
import com.jme3.scene.control.AbstractControl;
|
import com.jme3.scene.control.AbstractControl;
|
||||||
import com.jme3.scene.control.Control;
|
import com.jme3.scene.control.Control;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
@ -67,6 +69,14 @@ public class NormalRecalcControl extends AbstractControl {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
NormalRecalcControl control = (NormalRecalcControl)super.jmeClone();
|
||||||
|
control.setEnabled(true);
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
NormalRecalcControl control = new NormalRecalcControl(terrain);
|
NormalRecalcControl control = new NormalRecalcControl(terrain);
|
||||||
control.setSpatial(spatial);
|
control.setSpatial(spatial);
|
||||||
|
@ -46,6 +46,8 @@ import com.jme3.scene.control.Control;
|
|||||||
import com.jme3.terrain.Terrain;
|
import com.jme3.terrain.Terrain;
|
||||||
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
|
import com.jme3.terrain.geomipmap.lodcalc.DistanceLodCalculator;
|
||||||
import com.jme3.terrain.geomipmap.lodcalc.LodCalculator;
|
import com.jme3.terrain.geomipmap.lodcalc.LodCalculator;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
|
import com.jme3.util.clone.JmeCloneable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -298,9 +300,32 @@ public class TerrainLodControl extends AbstractControl {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object jmeClone() {
|
||||||
|
if (spatial instanceof Terrain) {
|
||||||
|
TerrainLodControl cloned = new TerrainLodControl((Terrain) spatial, cameras);
|
||||||
|
cloned.setLodCalculator(lodCalculator.clone());
|
||||||
|
cloned.spatial = spatial;
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.lodCalculator = cloner.clone(lodCalculator);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Not deep clone of the cameras themselves
|
||||||
|
this.cameras = cloner.javaClone(cameras);
|
||||||
|
} catch( CloneNotSupportedException e ) {
|
||||||
|
throw new RuntimeException("Error cloning", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
if (spatial instanceof Terrain) {
|
if (spatial instanceof Terrain) {
|
||||||
List<Camera> cameraClone = new ArrayList<Camera>();
|
List<Camera> cameraClone = new ArrayList<Camera>();
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
Material Signpost : Common/MatDefs/Light/Lighting.j3md {
|
Material Signpost : Common/MatDefs/Light/Lighting.j3md {
|
||||||
MaterialParameters {
|
MaterialParameters {
|
||||||
Shininess: 4.0
|
Shininess: 4.0
|
||||||
DiffuseMap: Models/Sign Post/Sign Post.jpg
|
DiffuseMap: "Models/Sign Post/Sign Post.jpg"
|
||||||
NormalMap: Models/Sign Post/Sign Post_normal.jpg
|
NormalMap: "Models/Sign Post/Sign Post_normal.jpg"
|
||||||
SpecularMap: Models/Sign Post/Sign Post_specular.jpg
|
SpecularMap: "Models/Sign Post/Sign Post_specular.jpg"
|
||||||
UseMaterialColors : true
|
UseMaterialColors : true
|
||||||
Ambient : 0.5 0.5 0.5 1.0
|
Ambient : 1.0 1.0 1.0 1.0
|
||||||
Diffuse : 1.0 1.0 1.0 1.0
|
Diffuse : 1.0 1.0 1.0 1.0
|
||||||
Specular : 1.0 1.0 1.0 1.0
|
Specular : 1.0 1.0 1.0 1.0
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
X-Comment: Created with jMonkeyPlatform
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user