Merge remote-tracking branch 'origin/master' into jme3-vr-dev
This commit is contained in:
commit
f7a852b755
README.md
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures
jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes
jme3-core/src
main
plugins/java/com/jme3/texture/plugins
jme3-examples/src/main/java/jme3test
light
model/anim
scene/instancing
jme3-lwjgl3/src/main/java/com/jme3
jme3-terrain/src/main
java/com/jme3/terrain/geomipmap
resources/Common/MatDefs/Terrain
@ -3,11 +3,11 @@ jMonkeyEngine
|
||||
|
||||
[](https://travis-ci.org/jMonkeyEngine/jmonkeyengine)
|
||||
|
||||
jMonkeyEngine is a 3D game engine for adventurous Java developers. It’s open source, cross platform and cutting edge. And it is all beautifully documented. The 3.0 branch is the latest stable version of the jMonkeyEngine 3 SDK, a complete game development suite. We'll be frequently submitting stable 3.0.x updates until the major 3.1 version arrives.
|
||||
jMonkeyEngine is a 3D game engine for adventurous Java developers. It’s open-source, cross-platform, and cutting-edge. 3.1.0 is the latest stable version of the jMonkeyEngine 3 SDK, a complete game development suite. We'll release 3.1.x updates until the major 3.2 release arrives.
|
||||
|
||||
The engine is used by several commercial game studios and computer-science courses. Here's a taste:
|
||||
|
||||

|
||||

|
||||
|
||||
- [jME powered games on IndieDB](http://www.indiedb.com/engines/jmonkeyengine/games)
|
||||
- [Maker's Tale](http://steamcommunity.com/sharedfiles/filedetails/?id=93461954t)
|
||||
|
@ -42,6 +42,7 @@ import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.asset.AssetInfo;
|
||||
import com.jme3.asset.AssetLoadException;
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.asset.AssetNotFoundException;
|
||||
import com.jme3.asset.BlenderKey;
|
||||
@ -486,7 +487,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
key.setGenerateMips(generateMipmaps);
|
||||
result = assetManager.loadTexture(key);
|
||||
result.setKey(key);
|
||||
} catch (AssetNotFoundException e) {
|
||||
} catch (AssetNotFoundException | AssetLoadException e) {
|
||||
LOGGER.fine(e.getLocalizedMessage());
|
||||
}
|
||||
} else {
|
||||
@ -522,7 +523,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
// If texture is found return it;
|
||||
return result;
|
||||
}
|
||||
} catch (AssetNotFoundException e) {
|
||||
} catch (AssetNotFoundException | AssetLoadException e) {
|
||||
LOGGER.fine(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
@ -532,7 +533,7 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
try {
|
||||
TextureKey key = new TextureKey(name);
|
||||
assetManager.loadTexture(key);
|
||||
} catch (AssetNotFoundException e) {
|
||||
} catch (AssetNotFoundException | AssetLoadException e) {
|
||||
LOGGER.fine(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
@ -119,14 +119,6 @@ public class CompoundCollisionShape extends CollisionShape {
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING - CompoundCollisionShape scaling has no effect.
|
||||
*/
|
||||
@Override
|
||||
public void setScale(Vector3f scale) {
|
||||
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "CompoundCollisionShape cannot be scaled");
|
||||
}
|
||||
|
||||
private native long createShape();
|
||||
|
||||
private native long addChildShape(long objectId, long childId, Vector3f location, Matrix3f rotation);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -33,7 +33,11 @@ package com.jme3.animation;
|
||||
|
||||
import com.jme3.export.*;
|
||||
import com.jme3.math.*;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Mesh;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.util.SafeArrayList;
|
||||
import com.jme3.util.TempVars;
|
||||
import com.jme3.util.clone.JmeCloneable;
|
||||
import com.jme3.util.clone.Cloner;
|
||||
@ -80,7 +84,10 @@ public final class Bone implements Savable, JmeCloneable {
|
||||
* The attachment node.
|
||||
*/
|
||||
private Node attachNode;
|
||||
|
||||
/**
|
||||
* A geometry animated by this node, used when updating the attachments node.
|
||||
*/
|
||||
private Geometry targetGeometry = null;
|
||||
/**
|
||||
* Bind transform is the local bind transform of this bone. (local space)
|
||||
*/
|
||||
@ -187,7 +194,8 @@ public final class Bone implements Savable, JmeCloneable {
|
||||
this.children = cloner.clone(children);
|
||||
|
||||
this.attachNode = cloner.clone(attachNode);
|
||||
|
||||
this.targetGeometry = cloner.clone(targetGeometry);
|
||||
|
||||
this.bindPos = cloner.clone(bindPos);
|
||||
this.bindRot = cloner.clone(bindRot);
|
||||
this.bindScale = cloner.clone(bindScale);
|
||||
@ -505,9 +513,39 @@ public final class Bone implements Savable, JmeCloneable {
|
||||
}
|
||||
|
||||
if (attachNode != null) {
|
||||
updateAttachNode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the local transform of the attachments node.
|
||||
*/
|
||||
private void updateAttachNode() {
|
||||
Node attachParent = attachNode.getParent();
|
||||
if (attachParent == null || targetGeometry == null
|
||||
|| targetGeometry.getParent() == attachParent
|
||||
&& targetGeometry.getLocalTransform().isIdentity()) {
|
||||
/*
|
||||
* The animated meshes are in the same coordinate system as the
|
||||
* attachments node: no further transforms are needed.
|
||||
*/
|
||||
attachNode.setLocalTranslation(modelPos);
|
||||
attachNode.setLocalRotation(modelRot);
|
||||
attachNode.setLocalScale(modelScale);
|
||||
|
||||
} else {
|
||||
Spatial loopSpatial = targetGeometry;
|
||||
Transform combined = new Transform(modelPos, modelRot, modelScale);
|
||||
/*
|
||||
* Climb the scene graph applying local transforms until the
|
||||
* attachments node's parent is reached.
|
||||
*/
|
||||
while (loopSpatial != attachParent && loopSpatial != null) {
|
||||
Transform localTransform = loopSpatial.getLocalTransform();
|
||||
combined.combineWithParent(localTransform);
|
||||
loopSpatial = loopSpatial.getParent();
|
||||
}
|
||||
attachNode.setLocalTransform(combined);
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,15 +699,32 @@ public final class Bone implements Savable, JmeCloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attachment node.
|
||||
* Attach models and effects to this node to make
|
||||
* them follow this bone's motions.
|
||||
* Access the attachments node of this bone. If this bone doesn't already
|
||||
* have an attachments node, create one. Models and effects attached to the
|
||||
* attachments node will follow this bone's motions.
|
||||
*
|
||||
* @param boneIndex this bone's index in its skeleton (≥0)
|
||||
* @param targets a list of geometries animated by this bone's skeleton (not
|
||||
* null, unaffected)
|
||||
*/
|
||||
Node getAttachmentsNode() {
|
||||
Node getAttachmentsNode(int boneIndex, SafeArrayList<Geometry> targets) {
|
||||
targetGeometry = null;
|
||||
/*
|
||||
* Search for a geometry animated by this particular bone.
|
||||
*/
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimatedByBone(boneIndex)) {
|
||||
targetGeometry = geometry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachNode == null) {
|
||||
attachNode = new Node(name + "_attachnode");
|
||||
attachNode.setUserData("AttachedBone", this);
|
||||
}
|
||||
|
||||
return attachNode;
|
||||
}
|
||||
|
||||
@ -823,6 +878,7 @@ public final class Bone implements Savable, JmeCloneable {
|
||||
}
|
||||
|
||||
attachNode = (Node) input.readSavable("attachNode", null);
|
||||
targetGeometry = (Geometry) input.readSavable("targetGeometry", null);
|
||||
|
||||
localPos.set(bindPos);
|
||||
localRot.set(bindRot);
|
||||
@ -845,6 +901,7 @@ public final class Bone implements Savable, JmeCloneable {
|
||||
|
||||
output.write(name, "name", null);
|
||||
output.write(attachNode, "attachNode", null);
|
||||
output.write(targetGeometry, "targetGeometry", null);
|
||||
output.write(bindPos, "bindPos", null);
|
||||
output.write(bindRot, "bindRot", null);
|
||||
output.write(bindScale, "bindScale", new Vector3f(1.0f, 1.0f, 1.0f));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -52,7 +52,6 @@ import java.io.IOException;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
@ -71,10 +70,12 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
* The skeleton of the model.
|
||||
*/
|
||||
private Skeleton skeleton;
|
||||
|
||||
/**
|
||||
* List of targets which this controller effects.
|
||||
* List of geometries affected by this control.
|
||||
*/
|
||||
private SafeArrayList<Mesh> targets = new SafeArrayList<Mesh>(Mesh.class);
|
||||
private SafeArrayList<Geometry> targets = new SafeArrayList<Geometry>(Geometry.class);
|
||||
|
||||
/**
|
||||
* Used to track when a mesh was updated. Meshes are only updated if they
|
||||
* are visible in at least one camera.
|
||||
@ -124,8 +125,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
for (Material m : materials) {
|
||||
m.setInt("NumberOfBones", numBones);
|
||||
}
|
||||
for (Mesh mesh : targets) {
|
||||
if (mesh.isAnimated()) {
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
mesh.prepareForAnim(false);
|
||||
}
|
||||
}
|
||||
@ -137,8 +139,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
m.clearParam("NumberOfBones");
|
||||
}
|
||||
}
|
||||
for (Mesh mesh : targets) {
|
||||
if (mesh.isAnimated()) {
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
mesh.prepareForAnim(true);
|
||||
}
|
||||
}
|
||||
@ -210,15 +213,22 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
this.skeleton = skeleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* If specified the geometry has an animated mesh, add its mesh and material
|
||||
* to the lists of animation targets.
|
||||
*/
|
||||
private void findTargets(Geometry geometry) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
targets.add(geometry);
|
||||
materials.add(geometry.getMaterial());
|
||||
}
|
||||
}
|
||||
|
||||
private void findTargets(Node node) {
|
||||
for (Spatial child : node.getChildren()) {
|
||||
if (child instanceof Geometry) {
|
||||
Geometry geom = (Geometry) child;
|
||||
Mesh mesh = geom.getMesh();
|
||||
if (mesh.isAnimated()) {
|
||||
targets.add(mesh);
|
||||
materials.add(geom.getMaterial());
|
||||
}
|
||||
findTargets((Geometry) child);
|
||||
} else if (child instanceof Node) {
|
||||
findTargets((Node) child);
|
||||
}
|
||||
@ -236,10 +246,11 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
offsetMatrices = skeleton.computeSkinningMatrices();
|
||||
|
||||
for (Mesh mesh : targets) {
|
||||
// NOTE: This assumes that code higher up
|
||||
// Already ensured those targets are animated
|
||||
// otherwise a crash will happen in skin update
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
// NOTE: This assumes code higher up has
|
||||
// already ensured this mesh is animated.
|
||||
// Otherwise a crash will happen in skin update.
|
||||
softwareSkinUpdate(mesh, offsetMatrices);
|
||||
}
|
||||
}
|
||||
@ -313,8 +324,9 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
|
||||
//only do this for software updates
|
||||
void resetToBind() {
|
||||
for (Mesh mesh : targets) {
|
||||
if (mesh.isAnimated()) {
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
if (mesh != null && mesh.isAnimated()) {
|
||||
Buffer bwBuff = mesh.getBuffer(Type.BoneWeight).getData();
|
||||
Buffer biBuff = mesh.getBuffer(Type.BoneIndex).getData();
|
||||
if (!biBuff.hasArray() || !bwBuff.hasArray()) {
|
||||
@ -432,9 +444,13 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the attachments node of the named bone. If the bone doesn't
|
||||
* already have an attachments node, create one and attach it to the scene
|
||||
* graph. Models and effects attached to the attachments node will follow
|
||||
* the bone's motions.
|
||||
*
|
||||
* @param boneName the name of the bone
|
||||
* @return the node attached to this bone
|
||||
* @return the attachments node of the bone
|
||||
*/
|
||||
public Node getAttachmentsNode(String boneName) {
|
||||
Bone b = skeleton.getBone(boneName);
|
||||
@ -443,9 +459,20 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
+ "in the skeleton.");
|
||||
}
|
||||
|
||||
Node n = b.getAttachmentsNode();
|
||||
Node model = (Node) spatial;
|
||||
model.attachChild(n);
|
||||
updateTargetsAndMaterials(spatial);
|
||||
int boneIndex = skeleton.getBoneIndex(b);
|
||||
Node n = b.getAttachmentsNode(boneIndex, targets);
|
||||
/*
|
||||
* Select a node to parent the attachments node.
|
||||
*/
|
||||
Node parent;
|
||||
if (spatial instanceof Node) {
|
||||
parent = (Node) spatial; // the usual case
|
||||
} else {
|
||||
parent = spatial.getParent();
|
||||
}
|
||||
parent.attachChild(n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -459,12 +486,20 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a copy of array of the targets meshes of this control
|
||||
* Enumerate the target meshes of this control.
|
||||
*
|
||||
* @return
|
||||
* @return a new array
|
||||
*/
|
||||
public Mesh[] getTargets() {
|
||||
return targets.toArray(new Mesh[targets.size()]);
|
||||
public Mesh[] getTargets() {
|
||||
Mesh[] result = new Mesh[targets.size()];
|
||||
int i = 0;
|
||||
for (Geometry geometry : targets) {
|
||||
Mesh mesh = geometry.getMesh();
|
||||
result[i] = mesh;
|
||||
i++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -758,12 +793,19 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
|
||||
skeleton = (Skeleton) in.readSavable("skeleton", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the lists of animation targets.
|
||||
*
|
||||
* @param spatial the controlled spatial
|
||||
*/
|
||||
private void updateTargetsAndMaterials(Spatial spatial) {
|
||||
targets.clear();
|
||||
materials.clear();
|
||||
if (spatial != null && spatial instanceof Node) {
|
||||
Node node = (Node) spatial;
|
||||
findTargets(node);
|
||||
materials.clear();
|
||||
|
||||
if (spatial instanceof Node) {
|
||||
findTargets((Node) spatial);
|
||||
} else if (spatial instanceof Geometry) {
|
||||
findTargets((Geometry) spatial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -288,6 +288,17 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
|
||||
rot.set(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for exact identity.
|
||||
*
|
||||
* @return true if exactly equal to {@link #IDENTITY}, otherwise false
|
||||
*/
|
||||
public boolean isIdentity() {
|
||||
return translation.x == 0f && translation.y == 0f && translation.z == 0f
|
||||
&& scale.x == 1f && scale.y == 1f && scale.z == 1f
|
||||
&& rot.w == 1f && rot.x == 0f && rot.y == 0f && rot.z == 0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 jMonkeyEngine
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -1408,6 +1408,45 @@ public class Mesh implements Savable, Cloneable, JmeCloneable {
|
||||
getBuffer(Type.HWBoneIndex) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the specified bone animates this mesh.
|
||||
*
|
||||
* @param boneIndex the bone's index in its skeleton
|
||||
* @return true if the specified bone animates this mesh, otherwise false
|
||||
*/
|
||||
public boolean isAnimatedByBone(int boneIndex) {
|
||||
VertexBuffer biBuf = getBuffer(VertexBuffer.Type.BoneIndex);
|
||||
VertexBuffer wBuf = getBuffer(VertexBuffer.Type.BoneWeight);
|
||||
if (biBuf == null || wBuf == null) {
|
||||
return false; // no bone animation data
|
||||
}
|
||||
|
||||
ByteBuffer boneIndexBuffer = (ByteBuffer) biBuf.getData();
|
||||
boneIndexBuffer.rewind();
|
||||
int numBoneIndices = boneIndexBuffer.remaining();
|
||||
assert numBoneIndices % 4 == 0 : numBoneIndices;
|
||||
int numVertices = boneIndexBuffer.remaining() / 4;
|
||||
|
||||
FloatBuffer weightBuffer = (FloatBuffer) wBuf.getData();
|
||||
weightBuffer.rewind();
|
||||
int numWeights = weightBuffer.remaining();
|
||||
assert numWeights == numVertices * 4 : numWeights;
|
||||
/*
|
||||
* Test each vertex to determine whether the bone affects it.
|
||||
*/
|
||||
byte biByte = (byte) boneIndex; // bone indices wrap after 127
|
||||
for (int vIndex = 0; vIndex < numVertices; vIndex++) {
|
||||
for (int wIndex = 0; wIndex < 4; wIndex++) {
|
||||
byte bIndex = boneIndexBuffer.get();
|
||||
float weight = weightBuffer.get();
|
||||
if (wIndex < maxNumWeights && bIndex == biByte && weight != 0f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the count of vertices used for each tessellation patch
|
||||
* @param patchVertexCount
|
||||
|
@ -141,7 +141,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
protected SafeArrayList<MatParamOverride> localOverrides;
|
||||
protected SafeArrayList<MatParamOverride> worldOverrides;
|
||||
|
||||
/**
|
||||
/**
|
||||
* This spatial's name.
|
||||
*/
|
||||
protected String name;
|
||||
@ -170,60 +170,6 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
*/
|
||||
protected transient int refreshFlags = 0;
|
||||
|
||||
public void refreshFlagOr(int flag){
|
||||
refreshFlags |= flag;
|
||||
//logger.warning("Changing refresh flags for spatial " + getName()+", flags: "+getRefreshFlagsDescription());
|
||||
}
|
||||
|
||||
public void refreshFlagAnd(int flag){
|
||||
refreshFlags &= flag;
|
||||
//logger.warning("Changing refresh flags for spatial " + getName()+", flags: "+getRefreshFlagsDescription());
|
||||
}
|
||||
|
||||
public int refreshFlagGetAnd(int flag){
|
||||
return (refreshFlags & flag);
|
||||
}
|
||||
|
||||
public int getRefreshFlags(){
|
||||
return refreshFlags;
|
||||
}
|
||||
|
||||
public String getRefreshFlagsDescription(){
|
||||
String str = "";
|
||||
|
||||
if (refreshFlags == 0){
|
||||
str += "OK";
|
||||
} else {
|
||||
|
||||
// need light resort + combine transforms
|
||||
if ((refreshFlags & RF_TRANSFORM) == RF_TRANSFORM){
|
||||
str += "RF_TRANSFORM ";
|
||||
}
|
||||
|
||||
// need light resort + combine transforms
|
||||
if ((refreshFlags & RF_BOUND) == RF_BOUND){
|
||||
str += "RF_BOUND ";
|
||||
}
|
||||
|
||||
// changes in light lists
|
||||
if ((refreshFlags & RF_LIGHTLIST) == RF_LIGHTLIST){
|
||||
str += "RF_LIGHTLIST ";
|
||||
}
|
||||
|
||||
// some child need geometry update
|
||||
if ((refreshFlags & RF_CHILD_LIGHTLIST) == RF_CHILD_LIGHTLIST){
|
||||
str += "RF_CHILD_LIGHTLIST ";
|
||||
}
|
||||
|
||||
// some child need geometry update
|
||||
if ((refreshFlags & RF_MATPARAM_OVERRIDE) == RF_MATPARAM_OVERRIDE){
|
||||
str += "RF_MATPARAM_OVERRIDE ";
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if a subclass requires updateLogicalState() even
|
||||
* if it doesn't have any controls. Defaults to true thus implementing
|
||||
@ -263,7 +209,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
|
||||
localOverrides = new SafeArrayList<>(MatParamOverride.class);
|
||||
worldOverrides = new SafeArrayList<>(MatParamOverride.class);
|
||||
refreshFlagOr(RF_BOUND);
|
||||
refreshFlags |= RF_BOUND;
|
||||
}
|
||||
|
||||
public void setKey(AssetKey key) {
|
||||
@ -326,35 +272,35 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
* a refresh is required.
|
||||
*/
|
||||
protected void setTransformRefresh() {
|
||||
refreshFlagOr(RF_TRANSFORM);
|
||||
refreshFlags |= RF_TRANSFORM;
|
||||
setBoundRefresh();
|
||||
}
|
||||
|
||||
protected void setLightListRefresh() {
|
||||
refreshFlagOr(RF_LIGHTLIST);
|
||||
refreshFlags |= RF_LIGHTLIST;
|
||||
// Make sure next updateGeometricState() visits this branch
|
||||
// to update lights.
|
||||
Spatial p = parent;
|
||||
while (p != null) {
|
||||
if ((p.refreshFlagGetAnd(RF_CHILD_LIGHTLIST)) != 0) {
|
||||
if ((p.refreshFlags & RF_CHILD_LIGHTLIST) != 0) {
|
||||
// The parent already has this flag,
|
||||
// so must all ancestors.
|
||||
return;
|
||||
}
|
||||
p.refreshFlagOr(RF_CHILD_LIGHTLIST);
|
||||
p.refreshFlags |= RF_CHILD_LIGHTLIST;
|
||||
p = p.parent;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setMatParamOverrideRefresh() {
|
||||
refreshFlagOr(RF_MATPARAM_OVERRIDE);
|
||||
refreshFlags |= RF_MATPARAM_OVERRIDE;
|
||||
Spatial p = parent;
|
||||
while (p != null) {
|
||||
if ((p.refreshFlagGetAnd(RF_MATPARAM_OVERRIDE)) != 0) {
|
||||
if ((p.refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
p.refreshFlagOr(RF_MATPARAM_OVERRIDE);
|
||||
p.refreshFlags |= RF_MATPARAM_OVERRIDE;
|
||||
p = p.parent;
|
||||
}
|
||||
}
|
||||
@ -364,15 +310,15 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
* a refresh is required.
|
||||
*/
|
||||
protected void setBoundRefresh() {
|
||||
refreshFlagOr(RF_BOUND);
|
||||
refreshFlags |= RF_BOUND;
|
||||
|
||||
Spatial p = parent;
|
||||
while (p != null) {
|
||||
if ((p.refreshFlagGetAnd(RF_BOUND)) != 0) {
|
||||
if ((p.refreshFlags & RF_BOUND) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
p.refreshFlagOr(RF_BOUND);
|
||||
p.refreshFlags |= RF_BOUND;
|
||||
p = p.parent;
|
||||
}
|
||||
}
|
||||
@ -407,14 +353,11 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
* (should be rendered), false if outside.
|
||||
*/
|
||||
public boolean checkCulling(Camera cam) {
|
||||
if (getRefreshFlags() != 0) {
|
||||
/*
|
||||
if (refreshFlags != 0) {
|
||||
throw new IllegalStateException("Scene graph is not properly updated for rendering.\n"
|
||||
+ "State was changed after rootNode.updateGeometricState() call. \n"
|
||||
+ "Make sure you do not modify the scene from another thread!\n"
|
||||
+ "Problem spatial name: " + getName()+", flags: "+getRefreshFlagsDescription());
|
||||
*/
|
||||
logger.warning("Invalid refresh flags for spatial " + getName()+", flags: "+getRefreshFlagsDescription());
|
||||
+ "Problem spatial name: " + getName());
|
||||
}
|
||||
|
||||
CullHint cm = getCullHint();
|
||||
@ -628,28 +571,28 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
// for a node, the world bound is a combination of all it's children
|
||||
// bounds
|
||||
// -> handled by subclass
|
||||
refreshFlagAnd(~RF_BOUND);
|
||||
refreshFlags &= ~RF_BOUND;
|
||||
}
|
||||
|
||||
protected void updateWorldLightList() {
|
||||
if (parent == null) {
|
||||
worldLights.update(localLights, null);
|
||||
refreshFlagAnd(~RF_LIGHTLIST);
|
||||
refreshFlags &= ~RF_LIGHTLIST;
|
||||
} else {
|
||||
assert (parent.refreshFlagGetAnd(RF_LIGHTLIST)) == 0;
|
||||
assert (parent.refreshFlags & RF_LIGHTLIST) == 0;
|
||||
worldLights.update(localLights, parent.worldLights);
|
||||
refreshFlagAnd(~RF_LIGHTLIST);
|
||||
refreshFlags &= ~RF_LIGHTLIST;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateMatParamOverrides() {
|
||||
refreshFlagAnd(~RF_MATPARAM_OVERRIDE);
|
||||
refreshFlags &= ~RF_MATPARAM_OVERRIDE;
|
||||
|
||||
worldOverrides.clear();
|
||||
if (parent == null) {
|
||||
worldOverrides.addAll(localOverrides);
|
||||
} else {
|
||||
assert (parent.refreshFlagGetAnd(RF_MATPARAM_OVERRIDE)) == 0;
|
||||
assert (parent.refreshFlags & RF_MATPARAM_OVERRIDE) == 0;
|
||||
worldOverrides.addAll(parent.worldOverrides);
|
||||
worldOverrides.addAll(localOverrides);
|
||||
}
|
||||
@ -700,13 +643,13 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
protected void updateWorldTransforms() {
|
||||
if (parent == null) {
|
||||
worldTransform.set(localTransform);
|
||||
refreshFlagAnd(~RF_TRANSFORM);
|
||||
refreshFlags &= ~RF_TRANSFORM;
|
||||
} else {
|
||||
// check if transform for parent is updated
|
||||
assert ((parent.refreshFlagGetAnd(RF_TRANSFORM)) == 0);
|
||||
assert ((parent.refreshFlags & RF_TRANSFORM) == 0);
|
||||
worldTransform.set(localTransform);
|
||||
worldTransform.combineWithParent(parent.worldTransform);
|
||||
refreshFlagAnd(~RF_TRANSFORM);
|
||||
refreshFlags &= ~RF_TRANSFORM;
|
||||
}
|
||||
}
|
||||
|
||||
@ -715,13 +658,13 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
* efficient manner possible.
|
||||
*/
|
||||
void checkDoTransformUpdate() {
|
||||
if ((refreshFlagGetAnd(RF_TRANSFORM)) == 0) {
|
||||
if ((refreshFlags & RF_TRANSFORM) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent == null) {
|
||||
worldTransform.set(localTransform);
|
||||
refreshFlagAnd(~RF_TRANSFORM);
|
||||
refreshFlags &= ~RF_TRANSFORM;
|
||||
} else {
|
||||
TempVars vars = TempVars.get();
|
||||
|
||||
@ -732,14 +675,14 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
Spatial hisParent = rootNode.parent;
|
||||
if (hisParent == null) {
|
||||
rootNode.worldTransform.set(rootNode.localTransform);
|
||||
rootNode.refreshFlagAnd(~RF_TRANSFORM);
|
||||
rootNode.refreshFlags &= ~RF_TRANSFORM;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
stack[i] = rootNode;
|
||||
|
||||
if ((hisParent.refreshFlagGetAnd(RF_TRANSFORM)) == 0) {
|
||||
if ((hisParent.refreshFlags & RF_TRANSFORM) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -764,7 +707,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
* manner possible.
|
||||
*/
|
||||
void checkDoBoundUpdate() {
|
||||
if ((refreshFlagGetAnd(RF_BOUND)) == 0) {
|
||||
if ((refreshFlags & RF_BOUND) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -954,20 +897,19 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
|
||||
// NOTE: Update world transforms first because
|
||||
// bound transform depends on them.
|
||||
if ((refreshFlagGetAnd(RF_LIGHTLIST)) != 0) {
|
||||
if ((refreshFlags & RF_LIGHTLIST) != 0) {
|
||||
updateWorldLightList();
|
||||
}
|
||||
if ((refreshFlagGetAnd(RF_TRANSFORM)) != 0) {
|
||||
if ((refreshFlags & RF_TRANSFORM) != 0) {
|
||||
updateWorldTransforms();
|
||||
}
|
||||
if ((refreshFlagGetAnd(RF_BOUND)) != 0) {
|
||||
if ((refreshFlags & RF_BOUND) != 0) {
|
||||
updateWorldBound();
|
||||
}
|
||||
if ((refreshFlagGetAnd(RF_MATPARAM_OVERRIDE)) != 0) {
|
||||
if ((refreshFlags & RF_MATPARAM_OVERRIDE) != 0) {
|
||||
updateMatParamOverrides();
|
||||
}
|
||||
|
||||
assert getRefreshFlags() == 0;
|
||||
assert refreshFlags == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1185,8 +1127,7 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>addLight</code> adds the given light to the Spatial; causing
|
||||
all
|
||||
* <code>addLight</code> adds the given light to the Spatial; causing all
|
||||
* child Spatials to be affected by it.
|
||||
*
|
||||
* @param light The light to add.
|
||||
@ -1909,4 +1850,4 @@ public abstract class Spatial implements Savable, Cloneable, Collidable, Cloneab
|
||||
}
|
||||
|
||||
protected abstract void breadthFirstTraversal(SceneGraphVisitor visitor, Queue<Spatial> queue);
|
||||
}
|
||||
}
|
@ -73,7 +73,6 @@ public class SkeletonInterBoneWire extends Mesh {
|
||||
}
|
||||
|
||||
this.setMode(Mode.Points);
|
||||
this.setPointSize(1);
|
||||
this.boneLengths = boneLengths;
|
||||
|
||||
VertexBuffer pb = new VertexBuffer(Type.Position);
|
||||
|
@ -84,7 +84,6 @@ public class SkeletonPoints extends Mesh {
|
||||
pb.setupData(Usage.Stream, 3, Format.Float, fpb);
|
||||
this.setBuffer(pb);
|
||||
|
||||
this.setPointSize(7);
|
||||
this.updateCounts();
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
*/
|
||||
package com.jme3.scene.instancing;
|
||||
|
||||
import com.jme3.bounding.BoundingVolume;
|
||||
import com.jme3.export.InputCapsule;
|
||||
import com.jme3.export.JmeExporter;
|
||||
import com.jme3.export.JmeImporter;
|
||||
@ -309,6 +310,7 @@ public class InstancedGeometry extends Geometry {
|
||||
} else {
|
||||
// Deleting element in the middle
|
||||
}
|
||||
setBoundRefresh();
|
||||
}
|
||||
|
||||
public void addInstance(Geometry geometry) {
|
||||
@ -327,6 +329,31 @@ public class InstancedGeometry extends Geometry {
|
||||
|
||||
geometries[freeIndex] = geometry;
|
||||
InstancedNode.setGeometryStartIndex2(geometry, freeIndex);
|
||||
setBoundRefresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateWorldBound() {
|
||||
refreshFlags &= ~RF_BOUND;
|
||||
BoundingVolume resultBound = null;
|
||||
|
||||
for (int i = 0; i < firstUnusedIndex; i++) {
|
||||
Geometry geom = geometries[i];
|
||||
|
||||
if (geom != null) {
|
||||
if (resultBound != null) {
|
||||
// merge current world bound with child world bound
|
||||
resultBound.mergeLocal(geom.getWorldBound());
|
||||
} else {
|
||||
// set world bound to first non-null child world bound
|
||||
if (geom.getWorldBound() != null) {
|
||||
resultBound = geom.getWorldBound().clone(this.worldBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.worldBound = resultBound;
|
||||
}
|
||||
|
||||
public Geometry[] getGeometries() {
|
||||
|
@ -982,7 +982,7 @@ public final class AppSettings extends HashMap<String, Object> {
|
||||
* size window.
|
||||
*/
|
||||
public void setResizable(boolean resizable) {
|
||||
putBoolean("Resizable", true);
|
||||
putBoolean("Resizable", resizable);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,6 +5,7 @@ MaterialDef Unshaded {
|
||||
Texture2D LightMap
|
||||
Color Color (Color)
|
||||
Boolean VertexColor (UseVertexColor)
|
||||
Float PointSize : 1.0
|
||||
Boolean SeparateTexCoord
|
||||
|
||||
// Texture of the glowing parts of the material
|
||||
@ -71,6 +72,7 @@ MaterialDef Unshaded {
|
||||
HAS_COLORMAP : ColorMap
|
||||
HAS_LIGHTMAP : LightMap
|
||||
HAS_VERTEXCOLOR : VertexColor
|
||||
HAS_POINTSIZE : PointSize
|
||||
HAS_COLOR : Color
|
||||
NUM_BONES : NumberOfBones
|
||||
DISCARD_ALPHA : AlphaDiscardThreshold
|
||||
@ -176,6 +178,7 @@ MaterialDef Unshaded {
|
||||
HAS_GLOWCOLOR : GlowColor
|
||||
NUM_BONES : NumberOfBones
|
||||
INSTANCING : UseInstancing
|
||||
HAS_POINTSIZE : PointSize
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,9 @@ varying vec2 texCoord1;
|
||||
varying vec2 texCoord2;
|
||||
|
||||
varying vec4 vertColor;
|
||||
#ifdef HAS_POINTSIZE
|
||||
uniform float m_PointSize;
|
||||
#endif
|
||||
|
||||
void main(){
|
||||
#ifdef NEED_TEXCOORD1
|
||||
@ -30,6 +33,10 @@ void main(){
|
||||
vertColor = inColor;
|
||||
#endif
|
||||
|
||||
#ifdef HAS_POINTSIZE
|
||||
gl_PointSize = m_PointSize;
|
||||
#endif
|
||||
|
||||
vec4 modelSpacePos = vec4(inPosition, 1.0);
|
||||
#ifdef NUM_BONES
|
||||
Skinning_Compute(modelSpacePos);
|
||||
|
@ -38,15 +38,16 @@ uniform mat3 g_NormalMatrix;
|
||||
// 2 vertex attributes which now can be used for additional per-vertex data.
|
||||
attribute mat4 inInstanceData;
|
||||
|
||||
// Extract the world matrix out of the instance data, leaving out the
|
||||
// quaternion at the end.
|
||||
mat4 worldMatrix = mat4(vec4(inInstanceData[0].xyz, 0.0),
|
||||
vec4(inInstanceData[1].xyz, 0.0),
|
||||
vec4(inInstanceData[2].xyz, 0.0),
|
||||
vec4(inInstanceData[3].xyz, 1.0));
|
||||
|
||||
|
||||
vec4 TransformWorld(vec4 position)
|
||||
{
|
||||
// Extract the world matrix out of the instance data, leaving out the
|
||||
// quaternion at the end.
|
||||
mat4 worldMatrix = mat4(vec4(inInstanceData[0].xyz, 0.0),
|
||||
vec4(inInstanceData[1].xyz, 0.0),
|
||||
vec4(inInstanceData[2].xyz, 0.0),
|
||||
vec4(inInstanceData[3].xyz, 1.0));
|
||||
return (worldMatrix * position);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ void Skinning_Compute(inout vec4 position, inout vec3 normal){
|
||||
}
|
||||
}
|
||||
|
||||
void Skinning_Compute(inout vec4 position, inout vec3 tangent, inout vec3 normal){
|
||||
void Skinning_Compute(inout vec4 position, inout vec3 normal, inout vec3 tangent){
|
||||
if (inHWBoneWeight.x != 0.0) {
|
||||
#if NUM_WEIGHTS_PER_VERT == 1
|
||||
position = m_BoneMatrices[int(inHWBoneIndex.x)] * position;
|
||||
|
@ -204,7 +204,7 @@ public class DDSLoader implements AssetLoader {
|
||||
|
||||
if (!directx10) {
|
||||
if (!is(caps1, DDSCAPS_TEXTURE)) {
|
||||
throw new IOException("File is not a texture");
|
||||
logger.warning("Texture is missing the DDSCAPS_TEXTURE-flag");
|
||||
}
|
||||
|
||||
if (depth <= 0) {
|
||||
|
@ -98,7 +98,7 @@ public class TestSpotLightTerrain extends SimpleApplication {
|
||||
ambLight.setColor(ColorRGBA.Black);
|
||||
rootNode.addLight(ambLight);
|
||||
|
||||
cam.setLocation(new Vector3f(-41.219646f, -84.8363f, -171.67267f));
|
||||
cam.setLocation(new Vector3f(-41.219646f, 0.8363f, -171.67267f));
|
||||
cam.setRotation(new Quaternion(-0.04562731f, 0.89917684f, -0.09668826f, -0.4243236f));
|
||||
sl.setDirection(cam.getDirection());
|
||||
sl.setPosition(cam.getLocation());
|
||||
|
@ -115,7 +115,8 @@ public class TestAnimBlendBug extends SimpleApplication implements ActionListene
|
||||
SkeletonDebugger skeletonDebug = new SkeletonDebugger("skeleton1", control1.getSkeleton());
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
mat.getAdditionalRenderState().setWireframe(true);
|
||||
mat.setColor("Color", ColorRGBA.Green);
|
||||
mat.setColor("Color", ColorRGBA.Red);
|
||||
mat.setFloat("PointSize", 7f);
|
||||
mat.getAdditionalRenderState().setDepthTest(false);
|
||||
skeletonDebug.setMaterial(mat);
|
||||
model1.attachChild(skeletonDebug);
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2017 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.model.anim;
|
||||
|
||||
import com.jme3.animation.AnimChannel;
|
||||
import com.jme3.animation.AnimControl;
|
||||
import com.jme3.animation.AnimEventListener;
|
||||
import com.jme3.animation.LoopMode;
|
||||
import com.jme3.animation.SkeletonControl;
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.input.KeyInput;
|
||||
import com.jme3.input.controls.ActionListener;
|
||||
import com.jme3.input.controls.KeyTrigger;
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.shape.Box;
|
||||
|
||||
/**
|
||||
* Simple application to an test attachments node on the Jaime model.
|
||||
*
|
||||
* Derived from {@link jme3test.model.anim.TestOgreAnim}.
|
||||
*/
|
||||
public class TestAttachmentsNode extends SimpleApplication
|
||||
implements AnimEventListener, ActionListener {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestAttachmentsNode app = new TestAttachmentsNode();
|
||||
app.start();
|
||||
}
|
||||
|
||||
private AnimChannel channel;
|
||||
private AnimControl control;
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
flyCam.setMoveSpeed(10f);
|
||||
cam.setLocation(new Vector3f(6.4f, 7.5f, 12.8f));
|
||||
cam.setRotation(new Quaternion(-0.060740203f, 0.93925786f, -0.2398315f, -0.2378785f));
|
||||
|
||||
DirectionalLight dl = new DirectionalLight();
|
||||
dl.setDirection(new Vector3f(-0.1f, -0.7f, -1).normalizeLocal());
|
||||
dl.setColor(ColorRGBA.White);
|
||||
rootNode.addLight(dl);
|
||||
|
||||
Spatial model = assetManager.loadModel("Models/Jaime/Jaime.j3o");
|
||||
control = model.getControl(AnimControl.class);
|
||||
SkeletonControl skeletonControl = model.getControl(SkeletonControl.class);
|
||||
|
||||
model.center();
|
||||
model.setLocalScale(5f);
|
||||
|
||||
control.addListener(this);
|
||||
channel = control.createChannel();
|
||||
channel.setAnim("Idle");
|
||||
|
||||
Box box = new Box(0.3f, 0.02f, 0.02f);
|
||||
Geometry saber = new Geometry("saber", box);
|
||||
saber.move(0.4f, 0.05f, 0.01f);
|
||||
Material red = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
|
||||
saber.setMaterial(red);
|
||||
Node n = skeletonControl.getAttachmentsNode("hand.R");
|
||||
n.attachChild(saber);
|
||||
rootNode.attachChild(model);
|
||||
|
||||
inputManager.addListener(this, "Attack");
|
||||
inputManager.addMapping("Attack", new KeyTrigger(KeyInput.KEY_SPACE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimCycleDone(AnimControl control, AnimChannel channel, String animName) {
|
||||
if (animName.equals("Punches")) {
|
||||
channel.setAnim("Idle", 0.5f);
|
||||
channel.setLoopMode(LoopMode.DontLoop);
|
||||
channel.setSpeed(1f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimChange(AnimControl control, AnimChannel channel, String animName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAction(String binding, boolean value, float tpf) {
|
||||
if (binding.equals("Attack") && value) {
|
||||
if (!channel.getAnimationName().equals("Punches")) {
|
||||
channel.setAnim("Punches", 0.5f);
|
||||
channel.setLoopMode(LoopMode.Cycle);
|
||||
channel.setSpeed(0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -106,6 +106,7 @@ public class TestOgreComplexAnim extends SimpleApplication {
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
mat.getAdditionalRenderState().setWireframe(true);
|
||||
mat.setColor("Color", ColorRGBA.Green);
|
||||
mat.setFloat("PointSize", 7f);
|
||||
mat.getAdditionalRenderState().setDepthTest(false);
|
||||
skeletonDebug.setMaterial(mat);
|
||||
|
||||
|
@ -0,0 +1,62 @@
|
||||
package jme3test.scene.instancing;
|
||||
|
||||
import com.jme3.app.SimpleApplication;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.instancing.InstancedNode;
|
||||
import com.jme3.scene.shape.Box;
|
||||
|
||||
public class TestInstanceNodeWithLight extends SimpleApplication {
|
||||
// Try to test with different offset
|
||||
private static float offset = 12;
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestInstanceNodeWithLight app = new TestInstanceNodeWithLight();
|
||||
app.start();
|
||||
}
|
||||
|
||||
Geometry box;
|
||||
PointLight pointLight;
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
InstancedNode instancedNode = new InstancedNode("testInstancedNode");
|
||||
rootNode.attachChild(instancedNode);
|
||||
|
||||
box = new Geometry("Box", new Box(0.5f, 0.5f, 0.5f));
|
||||
Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
||||
material.setBoolean("UseInstancing", true);
|
||||
material.setColor("Diffuse", ColorRGBA.Red);
|
||||
material.setBoolean("UseMaterialColors", true);
|
||||
box.setMaterial(material);
|
||||
|
||||
instancedNode.attachChild(box);
|
||||
instancedNode.instance();
|
||||
|
||||
pointLight = new PointLight();
|
||||
pointLight.setColor(ColorRGBA.White);
|
||||
pointLight.setRadius(10f);
|
||||
rootNode.addLight(pointLight);
|
||||
|
||||
box.setLocalTranslation(new Vector3f(offset, 0, 0));
|
||||
pointLight.setPosition(new Vector3f(offset - 3f, 0, 0));
|
||||
|
||||
cam.setLocation(new Vector3f(offset - 5f, 0, 0));
|
||||
cam.lookAtDirection(Vector3f.UNIT_X, Vector3f.UNIT_Y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleUpdate(float tpf) {
|
||||
offset += tpf;
|
||||
|
||||
System.err.println(offset);
|
||||
box.setLocalTranslation(new Vector3f(offset, 0, 0));
|
||||
pointLight.setPosition(new Vector3f(offset - 3f, 0, 0));
|
||||
|
||||
cam.setLocation(new Vector3f(offset - 5f, 0, 0));
|
||||
cam.lookAtDirection(Vector3f.UNIT_X, Vector3f.UNIT_Y);
|
||||
}
|
||||
}
|
@ -238,17 +238,35 @@ public class GlfwMouseInput implements MouseInput {
|
||||
return (long) (glfwGetTime() * 1000000000);
|
||||
}
|
||||
|
||||
private long createGlfwCursor(JmeCursor jmeCursor) {
|
||||
GLFWImage glfwImage = new GLFWImage(BufferUtils.createByteBuffer(GLFWImage.SIZEOF));
|
||||
private ByteBuffer transformCursorImage(IntBuffer imageData, int w, int h) {
|
||||
ByteBuffer buf = BufferUtils.createByteBuffer(imageData.capacity() * 4);
|
||||
|
||||
// Transform image: ARGB -> RGBA, vertical flip
|
||||
for (int y = h-1; y >= 0; --y) {
|
||||
for (int x = 0; x < w; ++x) {
|
||||
int pixel = imageData.get(y*w + x);
|
||||
buf.put((byte) ((pixel >> 16) & 0xFF)); // red
|
||||
buf.put((byte) ((pixel >> 8) & 0xFF)); // green
|
||||
buf.put((byte) ( pixel & 0xFF)); // blue
|
||||
buf.put((byte) ((pixel >> 24) & 0xFF)); // alpha
|
||||
}
|
||||
}
|
||||
|
||||
buf.flip();
|
||||
return buf;
|
||||
}
|
||||
|
||||
private long createGlfwCursor(JmeCursor jmeCursor) {
|
||||
// TODO: currently animated cursors are not supported
|
||||
IntBuffer imageData = jmeCursor.getImagesData();
|
||||
ByteBuffer buf = BufferUtils.createByteBuffer(imageData.capacity() * 4);
|
||||
buf.asIntBuffer().put(imageData);
|
||||
ByteBuffer buf = transformCursorImage(imageData, jmeCursor.getWidth(), jmeCursor.getHeight());
|
||||
|
||||
GLFWImage glfwImage = new GLFWImage(BufferUtils.createByteBuffer(GLFWImage.SIZEOF));
|
||||
glfwImage.set(jmeCursor.getWidth(), jmeCursor.getHeight(), buf);
|
||||
|
||||
return glfwCreateCursor(glfwImage, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot());
|
||||
int hotspotX = jmeCursor.getXHotSpot();
|
||||
int hotspotY = jmeCursor.getHeight() - jmeCursor.getYHotSpot();
|
||||
return glfwCreateCursor(glfwImage, hotspotX, hotspotY);
|
||||
}
|
||||
|
||||
public void setNativeCursor(JmeCursor jmeCursor) {
|
||||
|
@ -2,8 +2,12 @@ package com.jme3.util;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.nio.*;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* The implementation of the {@link BufferAllocator} which use {@link MemoryUtil} to manage memory.
|
||||
@ -12,13 +16,130 @@ import java.nio.ByteBuffer;
|
||||
*/
|
||||
public class LWJGLBufferAllocator implements BufferAllocator {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(LWJGLBufferAllocator.class.getName());
|
||||
|
||||
/**
|
||||
* The reference queue.
|
||||
*/
|
||||
private static final ReferenceQueue<Buffer> DUMMY_QUEUE = new ReferenceQueue<Buffer>();
|
||||
|
||||
/**
|
||||
* The LWJGL byte buffer deallocator.
|
||||
*/
|
||||
private static class Deallocator extends PhantomReference<ByteBuffer> {
|
||||
|
||||
/**
|
||||
* The address of LWJGL byte buffer.
|
||||
*/
|
||||
private volatile Long address;
|
||||
|
||||
Deallocator(final ByteBuffer referent, final ReferenceQueue<? super ByteBuffer> queue, final Long address) {
|
||||
super(referent, queue);
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param address the address of LWJGL byte buffer.
|
||||
*/
|
||||
void setAddress(final Long address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free memory.
|
||||
*/
|
||||
void free() {
|
||||
if (address == null) return;
|
||||
MemoryUtil.nmemFree(address);
|
||||
DEALLOCATORS.remove(address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The cleaner thread.
|
||||
*/
|
||||
private static final Thread CLEAN_THREAD = new Thread(LWJGLBufferAllocator::freeByteBuffers);
|
||||
|
||||
/**
|
||||
* The map with created deallocators.
|
||||
*/
|
||||
private static final Map<Long, Deallocator> DEALLOCATORS = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
CLEAN_THREAD.setDaemon(true);
|
||||
CLEAN_THREAD.setName("Thread to free LWJGL byte buffers");
|
||||
CLEAN_THREAD.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free unnecessary LWJGL byte buffers.
|
||||
*/
|
||||
private static void freeByteBuffers() {
|
||||
try {
|
||||
for (; ; ) {
|
||||
final Deallocator deallocator = (Deallocator) DUMMY_QUEUE.remove();
|
||||
deallocator.free();
|
||||
}
|
||||
} catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyDirectBuffer(final Buffer buffer) {
|
||||
|
||||
final long address = getAddress(buffer);
|
||||
|
||||
if (address == -1) {
|
||||
LOGGER.warning("Not found address of the " + buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
// disable deallocator
|
||||
final Deallocator deallocator = DEALLOCATORS.remove(address);
|
||||
|
||||
if (deallocator == null) {
|
||||
LOGGER.warning("Not found a deallocator for address " + address);
|
||||
return;
|
||||
}
|
||||
|
||||
deallocator.setAddress(null);
|
||||
|
||||
MemoryUtil.memFree(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get memory address of the buffer.
|
||||
*
|
||||
* @param buffer the buffer.
|
||||
* @return the address or -1.
|
||||
*/
|
||||
private long getAddress(final Buffer buffer) {
|
||||
|
||||
if (buffer instanceof ByteBuffer) {
|
||||
return MemoryUtil.memAddress((ByteBuffer) buffer, 0);
|
||||
} else if (buffer instanceof ShortBuffer) {
|
||||
return MemoryUtil.memAddress((ShortBuffer) buffer, 0);
|
||||
} else if (buffer instanceof CharBuffer) {
|
||||
return MemoryUtil.memAddress((CharBuffer) buffer, 0);
|
||||
} else if (buffer instanceof IntBuffer) {
|
||||
return MemoryUtil.memAddress((IntBuffer) buffer, 0);
|
||||
} else if (buffer instanceof FloatBuffer) {
|
||||
return MemoryUtil.memAddress((FloatBuffer) buffer, 0);
|
||||
} else if (buffer instanceof LongBuffer) {
|
||||
return MemoryUtil.memAddress((LongBuffer) buffer, 0);
|
||||
} else if (buffer instanceof DoubleBuffer) {
|
||||
return MemoryUtil.memAddress((DoubleBuffer) buffer, 0);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer allocate(final int size) {
|
||||
return MemoryUtil.memAlloc(size);
|
||||
final Long address = MemoryUtil.nmemAlloc(size);
|
||||
final ByteBuffer byteBuffer = MemoryUtil.memByteBuffer(address, size);
|
||||
DEALLOCATORS.put(address, new Deallocator(byteBuffer, DUMMY_QUEUE, address));
|
||||
return byteBuffer;
|
||||
}
|
||||
}
|
||||
|
@ -303,22 +303,29 @@ public class TerrainPatch extends Geometry {
|
||||
|
||||
protected void setHeight(List<LocationHeight> locationHeights, boolean overrideHeight) {
|
||||
|
||||
final float[] heightArray = geomap.getHeightArray();
|
||||
final VertexBuffer vertexBuffer = mesh.getBuffer(Type.Position);
|
||||
final FloatBuffer floatBuffer = mesh.getFloatBuffer(Type.Position);
|
||||
|
||||
for (LocationHeight lh : locationHeights) {
|
||||
if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size)
|
||||
|
||||
if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size) {
|
||||
continue;
|
||||
int idx = lh.z * size + lh.x;
|
||||
if (overrideHeight) {
|
||||
geomap.getHeightArray()[idx] = lh.h;
|
||||
} else {
|
||||
float h = getMesh().getFloatBuffer(Type.Position).get(idx*3+1);
|
||||
geomap.getHeightArray()[idx] = h+lh.h;
|
||||
}
|
||||
|
||||
int idx = lh.z * size + lh.x;
|
||||
|
||||
if (overrideHeight) {
|
||||
heightArray[idx] = lh.h;
|
||||
} else {
|
||||
float currentHeight = floatBuffer.get(idx * 3 + 1);
|
||||
heightArray[idx] = currentHeight + lh.h;
|
||||
}
|
||||
}
|
||||
|
||||
FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
|
||||
getMesh().clearBuffer(Type.Position);
|
||||
getMesh().setBuffer(Type.Position, 3, newVertexBuffer);
|
||||
floatBuffer.clear();
|
||||
geomap.writeVertexArray(floatBuffer, stepScale, false);
|
||||
vertexBuffer.setUpdateNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,6 +150,7 @@ varying vec2 texCoord;
|
||||
|
||||
vec4 calculateDiffuseBlend(in vec2 texCoord) {
|
||||
vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy );
|
||||
vec4 diffuseColor = vec4(1.0);
|
||||
|
||||
#ifdef ALPHAMAP_1
|
||||
vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy );
|
||||
@ -157,9 +158,10 @@ varying vec2 texCoord;
|
||||
#ifdef ALPHAMAP_2
|
||||
vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy );
|
||||
#endif
|
||||
|
||||
vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale);
|
||||
diffuseColor *= alphaBlend.r;
|
||||
#ifdef DIFFUSEMAP
|
||||
diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale);
|
||||
diffuseColor *= alphaBlend.r;
|
||||
#endif
|
||||
#ifdef DIFFUSEMAP_1
|
||||
vec4 diffuseColor1 = texture2D(m_DiffuseMap_1, texCoord * m_DiffuseMap_1_scale);
|
||||
diffuseColor = mix( diffuseColor, diffuseColor1, alphaBlend.g );
|
||||
|
@ -151,6 +151,7 @@ varying vec3 lightVec;
|
||||
|
||||
vec4 calculateDiffuseBlend(in vec2 texCoord) {
|
||||
vec4 alphaBlend = texture2D( m_AlphaMap, texCoord.xy );
|
||||
vec4 diffuseColor = vec4(1.0);
|
||||
|
||||
#ifdef ALPHAMAP_1
|
||||
vec4 alphaBlend1 = texture2D( m_AlphaMap_1, texCoord.xy );
|
||||
@ -158,9 +159,10 @@ varying vec3 lightVec;
|
||||
#ifdef ALPHAMAP_2
|
||||
vec4 alphaBlend2 = texture2D( m_AlphaMap_2, texCoord.xy );
|
||||
#endif
|
||||
|
||||
vec4 diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale);
|
||||
diffuseColor *= alphaBlend.r;
|
||||
#ifdef DIFFUSEMAP
|
||||
diffuseColor = texture2D(m_DiffuseMap, texCoord * m_DiffuseMap_0_scale);
|
||||
diffuseColor *= alphaBlend.r;
|
||||
#endif
|
||||
#ifdef DIFFUSEMAP_1
|
||||
vec4 diffuseColor1 = texture2D(m_DiffuseMap_1, texCoord * m_DiffuseMap_1_scale);
|
||||
diffuseColor = mix( diffuseColor, diffuseColor1, alphaBlend.g );
|
||||
|
@ -272,29 +272,7 @@ MaterialDef Terrain Lighting {
|
||||
|
||||
}
|
||||
|
||||
Technique GBuf {
|
||||
|
||||
VertexShader GLSL100: Common/MatDefs/Light/GBuf.vert
|
||||
FragmentShader GLSL100: Common/MatDefs/Light/GBuf.frag
|
||||
|
||||
WorldParameters {
|
||||
WorldViewProjectionMatrix
|
||||
WorldMatrix
|
||||
}
|
||||
|
||||
Defines {
|
||||
VERTEX_COLOR : UseVertexColor
|
||||
MATERIAL_COLORS : UseMaterialColors
|
||||
V_TANGENT : VTangent
|
||||
MINNAERT : Minnaert
|
||||
WARDISO : WardIso
|
||||
|
||||
DIFFUSEMAP : DiffuseMap
|
||||
NORMALMAP : NormalMap
|
||||
SPECULARMAP : SpecularMap
|
||||
PARALLAXMAP : ParallaxMap
|
||||
}
|
||||
}
|
||||
|
||||
Technique Glow {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user