Merge branch 'master' into experimental
Conflicts: jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
This commit is contained in:
commit
a3638f3e0c
@ -59,6 +59,7 @@ import com.jme3.scene.plugins.blender.file.FileBlockHeader;
|
|||||||
import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode;
|
import com.jme3.scene.plugins.blender.file.FileBlockHeader.BlockCode;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||||
|
import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -389,11 +390,11 @@ public class BlenderContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if("ME".equals(namePrefix)) {
|
} else if("ME".equals(namePrefix)) {
|
||||||
List<Node> features = (List<Node>) linkedFeatures.get("meshes");
|
List<TemporalMesh> temporalMeshes = (List<TemporalMesh>) linkedFeatures.get("meshes");
|
||||||
if(features != null) {
|
if(temporalMeshes != null) {
|
||||||
for(Node feature : features) {
|
for(TemporalMesh temporalMesh : temporalMeshes) {
|
||||||
if(featureName.equals(feature.getName())) {
|
if(featureName.equals(temporalMesh.getName())) {
|
||||||
return feature;
|
return temporalMesh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import com.jme3.math.Vector3f;
|
|||||||
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
import com.jme3.scene.plugins.blender.file.BlenderFileException;
|
||||||
import com.jme3.scene.plugins.blender.file.Pointer;
|
import com.jme3.scene.plugins.blender.file.Pointer;
|
||||||
import com.jme3.scene.plugins.blender.file.Structure;
|
import com.jme3.scene.plugins.blender.file.Structure;
|
||||||
|
import com.jme3.scene.plugins.blender.math.Vector3d;
|
||||||
import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
|
import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,6 +25,8 @@ public class Edge {
|
|||||||
|
|
||||||
/** The vertices indexes. */
|
/** The vertices indexes. */
|
||||||
private int index1, index2;
|
private int index1, index2;
|
||||||
|
/** The vertices that can be set if we need and abstract edge outside the mesh (for computations). */
|
||||||
|
private Vector3f v1, v2;
|
||||||
/** The weight of the edge. */
|
/** The weight of the edge. */
|
||||||
private float crease;
|
private float crease;
|
||||||
/** A variable that indicates if this edge belongs to any face or not. */
|
/** A variable that indicates if this edge belongs to any face or not. */
|
||||||
@ -31,6 +34,13 @@ public class Edge {
|
|||||||
/** The mesh that owns the edge. */
|
/** The mesh that owns the edge. */
|
||||||
private TemporalMesh temporalMesh;
|
private TemporalMesh temporalMesh;
|
||||||
|
|
||||||
|
public Edge(Vector3f v1, Vector3f v2) {
|
||||||
|
this.v1 = v1 == null ? new Vector3f() : v1;
|
||||||
|
this.v2 = v2 == null ? new Vector3f() : v2;
|
||||||
|
index1 = 0;
|
||||||
|
index2 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor only stores the indexes of the vertices. The position vertices should be stored
|
* This constructor only stores the indexes of the vertices. The position vertices should be stored
|
||||||
* outside this class.
|
* outside this class.
|
||||||
@ -74,14 +84,14 @@ public class Edge {
|
|||||||
* @return the first vertex of the edge
|
* @return the first vertex of the edge
|
||||||
*/
|
*/
|
||||||
public Vector3f getFirstVertex() {
|
public Vector3f getFirstVertex() {
|
||||||
return temporalMesh.getVertices().get(index1);
|
return temporalMesh == null ? v1 : temporalMesh.getVertices().get(index1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the second vertex of the edge
|
* @return the second vertex of the edge
|
||||||
*/
|
*/
|
||||||
public Vector3f getSecondVertex() {
|
public Vector3f getSecondVertex() {
|
||||||
return temporalMesh.getVertices().get(index2);
|
return temporalMesh == null ? v2 : temporalMesh.getVertices().get(index2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -188,27 +198,81 @@ public class Edge {
|
|||||||
* @return <b>true</b> if the edges cross and false otherwise
|
* @return <b>true</b> if the edges cross and false otherwise
|
||||||
*/
|
*/
|
||||||
public boolean cross(Edge edge) {
|
public boolean cross(Edge edge) {
|
||||||
Vector3f P1 = this.getFirstVertex();
|
return this.getCrossPoint(edge) != null;
|
||||||
Vector3f P2 = edge.getFirstVertex();
|
}
|
||||||
Vector3f u = this.getSecondVertex().subtract(P1);
|
|
||||||
Vector3f v = edge.getSecondVertex().subtract(P2);
|
/**
|
||||||
float t2 = (u.x * (P2.y - P1.y) - u.y * (P2.x - P1.x)) / (u.y * v.x - u.x * v.y);
|
* The method computes the crossing pint of this edge and another edge. If
|
||||||
float t1 = (P2.x - P1.x + v.x * t2) / u.x;
|
* there is no crossing then null is returned.
|
||||||
Vector3f p1 = P1.add(u.mult(t1));
|
*
|
||||||
Vector3f p2 = P2.add(v.mult(t2));
|
* @param edge
|
||||||
|
* the edge to compute corss point with
|
||||||
|
* @return cross point on null if none exist
|
||||||
|
*/
|
||||||
|
public Vector3f getCrossPoint(Edge edge) {
|
||||||
|
return this.getCrossPoint(edge, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method computes the crossing pint of this edge and another edge. If
|
||||||
|
* there is no crossing then null is returned. This method also allows to
|
||||||
|
* get the crossing point of the straight lines that contain these edges if
|
||||||
|
* you set the 'extend' parameter to true.
|
||||||
|
*
|
||||||
|
* @param edge
|
||||||
|
* the edge to compute corss point with
|
||||||
|
* @param extendThisEdge
|
||||||
|
* set to <b>true</b> to find a crossing point along the whole
|
||||||
|
* straight that contains the current edge
|
||||||
|
* @param extendSecondEdge
|
||||||
|
* set to <b>true</b> to find a crossing point along the whole
|
||||||
|
* straight that contains the given edge
|
||||||
|
* @return cross point on null if none exist
|
||||||
|
*/
|
||||||
|
public Vector3f getCrossPoint(Edge edge, boolean extendThisEdge, boolean extendSecondEdge) {
|
||||||
|
Vector3d P1 = new Vector3d(this.getFirstVertex());
|
||||||
|
Vector3d P2 = new Vector3d(edge.getFirstVertex());
|
||||||
|
Vector3d u = new Vector3d(this.getSecondVertex()).subtract(P1).normalizeLocal();
|
||||||
|
Vector3d v = new Vector3d(edge.getSecondVertex()).subtract(P2).normalizeLocal();
|
||||||
|
|
||||||
|
double t1 = 0, t2 = 0;
|
||||||
|
if(u.x == 0 && v.x == 0) {
|
||||||
|
t2 = (u.z * (P2.y - P1.y) - u.y * (P2.z - P1.z)) / (u.y * v.z - u.z * v.y);
|
||||||
|
t1 = (P2.z - P1.z + v.z * t2) / u.z;
|
||||||
|
} else if(u.y == 0 && v.y == 0) {
|
||||||
|
t2 = (u.x * (P2.z - P1.z) - u.z * (P2.x - P1.x)) / (u.z * v.x - u.x * v.z);
|
||||||
|
t1 = (P2.x - P1.x + v.x * t2) / u.x;
|
||||||
|
} else if(u.z == 0 && v.z == 0) {
|
||||||
|
t2 = (u.x * (P2.y - P1.y) - u.y * (P2.x - P1.x)) / (u.y * v.x - u.x * v.y);
|
||||||
|
t1 = (P2.x - P1.x + v.x * t2) / u.x;
|
||||||
|
} else {
|
||||||
|
t2 = (P1.y * u.x - P1.x * u.y + P2.x * u.y - P2.y * u.x) / (v.y * u.x - u.y * v.x);
|
||||||
|
t1 = (P2.x - P1.x + v.x * t2) / u.x;
|
||||||
|
if(Math.abs(P1.z - P2.z + u.z * t1 - v.z * t2) > FastMath.FLT_EPSILON) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vector3d p1 = P1.add(u.mult(t1));
|
||||||
|
Vector3d p2 = P2.add(v.mult(t2));
|
||||||
|
|
||||||
if (p1.distance(p2) <= FastMath.FLT_EPSILON) {
|
if (p1.distance(p2) <= FastMath.FLT_EPSILON) {
|
||||||
|
if(extendThisEdge && extendSecondEdge) {
|
||||||
|
return p1.toVector3f();
|
||||||
|
}
|
||||||
// the lines cross, check if p1 and p2 are within the edges
|
// the lines cross, check if p1 and p2 are within the edges
|
||||||
Vector3f p = p1.subtract(P1);
|
Vector3d p = p1.subtract(P1);
|
||||||
float cos = p.dot(u) / (p.length() * u.length());
|
double cos = p.dot(u) / p.length();
|
||||||
if (cos > 0 && p.length() <= u.length()) {
|
if (extendThisEdge || p.length()<= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() <= this.getLength()) {
|
||||||
// p1 is inside the first edge, lets check the other edge now
|
// p1 is inside the first edge, lets check the other edge now
|
||||||
p = p2.subtract(P2);
|
p = p2.subtract(P2);
|
||||||
cos = p.dot(v) / (p.length() * v.length());
|
cos = p.dot(v) / p.length();
|
||||||
return cos > 0 && p.length() <= u.length();
|
if(extendSecondEdge || p.length()<= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() <= edge.getLength()) {
|
||||||
|
return p1.toVector3f();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -276,6 +276,20 @@ public class Face implements Comparator<Integer> {
|
|||||||
List<Face> facesToTriangulate = new ArrayList<Face>(Arrays.asList(this.clone()));
|
List<Face> facesToTriangulate = new ArrayList<Face>(Arrays.asList(this.clone()));
|
||||||
while (facesToTriangulate.size() > 0) {
|
while (facesToTriangulate.size() > 0) {
|
||||||
Face face = facesToTriangulate.remove(0);
|
Face face = facesToTriangulate.remove(0);
|
||||||
|
// two special cases will improve the computations speed
|
||||||
|
if(face.getIndexes().size() == 3) {
|
||||||
|
triangulatedFaces.add(face.getIndexes().clone());
|
||||||
|
} else if(face.getIndexes().size() == 4) {
|
||||||
|
// in case face has 4 verts we use the plain triangulation
|
||||||
|
indexes[0] = face.getIndex(0);
|
||||||
|
indexes[1] = face.getIndex(1);
|
||||||
|
indexes[2] = face.getIndex(2);
|
||||||
|
triangulatedFaces.add(new IndexesLoop(indexes));
|
||||||
|
|
||||||
|
indexes[1] = face.getIndex(2);
|
||||||
|
indexes[2] = face.getIndex(3);
|
||||||
|
triangulatedFaces.add(new IndexesLoop(indexes));
|
||||||
|
} else {
|
||||||
int previousIndex1 = -1, previousIndex2 = -1, previousIndex3 = -1;
|
int previousIndex1 = -1, previousIndex2 = -1, previousIndex3 = -1;
|
||||||
while (face.vertexCount() > 0) {
|
while (face.vertexCount() > 0) {
|
||||||
indexes[0] = face.getIndex(0);
|
indexes[0] = face.getIndex(0);
|
||||||
@ -298,8 +312,9 @@ public class Face implements Comparator<Integer> {
|
|||||||
triangulatedFaces.add(new IndexesLoop(indexes));
|
triangulatedFaces.add(new IndexesLoop(indexes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (BlenderFileException e) {
|
} catch (BlenderFileException e) {
|
||||||
LOGGER.log(Level.WARNING, "Errors occured during face triangulation: {0}. The face will be triangulated with the most direct algorithm, " + "but the results might not be identical to blender.", e.getLocalizedMessage());
|
LOGGER.log(Level.WARNING, "Errors occured during face triangulation: {0}. The face will be triangulated with the most direct algorithm, but the results might not be identical to blender.", e.getLocalizedMessage());
|
||||||
indexes[0] = this.getIndex(0);
|
indexes[0] = this.getIndex(0);
|
||||||
for (int i = 1; i < this.vertexCount() - 1; ++i) {
|
for (int i = 1; i < this.vertexCount() - 1; ++i) {
|
||||||
indexes[1] = this.getIndex(i);
|
indexes[1] = this.getIndex(i);
|
||||||
@ -338,12 +353,18 @@ public class Face implements Comparator<Integer> {
|
|||||||
/**
|
/**
|
||||||
* The method finds the closest vertex to the one specified by <b>index</b>.
|
* The method finds the closest vertex to the one specified by <b>index</b>.
|
||||||
* If the vertexToIgnore is positive than it will be ignored in the result.
|
* If the vertexToIgnore is positive than it will be ignored in the result.
|
||||||
* The closes vertex must be able to create an edge that is fully contained within the face and does not cross
|
* The closest vertex must be able to create an edge that is fully contained
|
||||||
* any other edges.
|
* within the face and does not cross any other edges. Also if the
|
||||||
|
* vertexToIgnore is not negative then the condition that the edge between
|
||||||
|
* the found index and the one to ignore is inside the face must also be
|
||||||
|
* met.
|
||||||
|
*
|
||||||
* @param index
|
* @param index
|
||||||
* the index of the vertex that needs to have found the nearest neighbour
|
* the index of the vertex that needs to have found the nearest
|
||||||
|
* neighbour
|
||||||
* @param indexToIgnore
|
* @param indexToIgnore
|
||||||
* the index to ignore in the result (pass -1 if none is to be ignored)
|
* the index to ignore in the result (pass -1 if none is to be
|
||||||
|
* ignored)
|
||||||
* @return the index of the closest vertex to the given one
|
* @return the index of the closest vertex to the given one
|
||||||
*/
|
*/
|
||||||
private int findClosestVertex(int index, int indexToIgnore) {
|
private int findClosestVertex(int index, int indexToIgnore) {
|
||||||
@ -355,7 +376,7 @@ public class Face implements Comparator<Integer> {
|
|||||||
if (i != index && i != indexToIgnore) {
|
if (i != index && i != indexToIgnore) {
|
||||||
Vector3f v2 = vertices.get(i);
|
Vector3f v2 = vertices.get(i);
|
||||||
float d = v2.distance(v1);
|
float d = v2.distance(v1);
|
||||||
if (d < distance && this.contains(new Edge(index, i, 0, true, temporalMesh))) {
|
if (d < distance && this.contains(new Edge(index, i, 0, true, temporalMesh)) && (indexToIgnore < 0 || this.contains(new Edge(indexToIgnore, i, 0, true, temporalMesh)))) {
|
||||||
result = i;
|
result = i;
|
||||||
distance = d;
|
distance = d;
|
||||||
}
|
}
|
||||||
@ -376,11 +397,9 @@ public class Face implements Comparator<Integer> {
|
|||||||
int index2 = edge.getSecondIndex();
|
int index2 = edge.getSecondIndex();
|
||||||
// check if the line between the vertices is not a border edge of the face
|
// check if the line between the vertices is not a border edge of the face
|
||||||
if (!indexes.areNeighbours(index1, index2)) {
|
if (!indexes.areNeighbours(index1, index2)) {
|
||||||
List<Vector3f> vertices = temporalMesh.getVertices();
|
|
||||||
|
|
||||||
for (int i = 0; i < indexes.size(); ++i) {
|
for (int i = 0; i < indexes.size(); ++i) {
|
||||||
int i1 = this.getIndex(i);
|
int i1 = this.getIndex(i - 1);
|
||||||
int i2 = this.getIndex(i + 1);
|
int i2 = this.getIndex(i);
|
||||||
// check if the edges have no common verts (because if they do, they cannot cross)
|
// check if the edges have no common verts (because if they do, they cannot cross)
|
||||||
if (i1 != index1 && i1 != index2 && i2 != index1 && i2 != index2) {
|
if (i1 != index1 && i1 != index2 && i2 != index1 && i2 != index2) {
|
||||||
if (edge.cross(new Edge(i1, i2, 0, false, temporalMesh))) {
|
if (edge.cross(new Edge(i1, i2, 0, false, temporalMesh))) {
|
||||||
@ -389,31 +408,49 @@ public class Face implements Comparator<Integer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the edge does NOT cross any of other edges, so now we need to verify if it is inside the face or outside
|
// computing the edge's middle point
|
||||||
// we check it by comparing the angle that is created by vertices: [index1 - 1, index1, index1 + 1]
|
Vector3f edgeMiddlePoint = edge.computeCentroid();
|
||||||
// with the one creaded by vertices: [index1 - 1, index1, index2]
|
// computing the edge that is perpendicular to the given edge and has a length of 1 (length actually does not matter)
|
||||||
// if the latter is greater than it means that the edge is outside the face
|
Vector3f edgeVector = edge.getSecondVertex().subtract(edge.getFirstVertex());
|
||||||
// IMPORTANT: we assume that all vertices are in one plane (this should be ensured before creating the Face)
|
Vector3f edgeNormal = temporalMesh.getNormals().get(index1).cross(edgeVector).normalizeLocal();
|
||||||
int indexOfIndex1 = indexes.indexOf(index1);
|
Edge e = new Edge(edgeMiddlePoint, edgeNormal.add(edgeMiddlePoint));
|
||||||
int indexMinus1 = this.getIndex(indexOfIndex1 - 1);// indexOfIndex1 == 0 ? indexes.get(indexes.size() - 1) : indexes.get(indexOfIndex1 - 1);
|
// compute the vectors from the middle point to the crossing between the extended edge 'e' and other edges of the face
|
||||||
int indexPlus1 = this.getIndex(indexOfIndex1 + 1);// indexOfIndex1 == indexes.size() - 1 ? 0 : indexes.get(indexOfIndex1 + 1);
|
List<Vector3f> crossingVectors = new ArrayList<Vector3f>();
|
||||||
|
for (int i = 0; i < indexes.size(); ++i) {
|
||||||
|
int i1 = this.getIndex(i);
|
||||||
|
int i2 = this.getIndex(i + 1);
|
||||||
|
Vector3f crossPoint = e.getCrossPoint(new Edge(i1, i2, 0, false, temporalMesh), true, false);
|
||||||
|
if(crossPoint != null) {
|
||||||
|
crossingVectors.add(crossPoint.subtractLocal(edgeMiddlePoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(crossingVectors.size() == 0) {
|
||||||
|
return false;// edges do not cross
|
||||||
|
}
|
||||||
|
|
||||||
Vector3f edge1 = vertices.get(indexMinus1).subtract(vertices.get(index1)).normalizeLocal();
|
// use only distinct vertices (doubles may appear if the crossing point is a vertex)
|
||||||
Vector3f edge2 = vertices.get(indexPlus1).subtract(vertices.get(index1)).normalizeLocal();
|
List<Vector3f> distinctCrossingVectors = new ArrayList<Vector3f>();
|
||||||
Vector3f newEdge = vertices.get(index2).subtract(vertices.get(index1)).normalizeLocal();
|
for(Vector3f cv : crossingVectors) {
|
||||||
|
double minDistance = Double.MAX_VALUE;
|
||||||
|
for(Vector3f dcv : distinctCrossingVectors) {
|
||||||
|
minDistance = Math.min(minDistance, dcv.distance(cv));
|
||||||
|
}
|
||||||
|
if(minDistance > FastMath.FLT_EPSILON) {
|
||||||
|
distinctCrossingVectors.add(cv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// verify f the later computed angle is inside or outside the face
|
if(distinctCrossingVectors.size() == 0) {
|
||||||
Vector3f direction1 = edge1.cross(edge2).normalizeLocal();
|
throw new IllegalStateException("There MUST be at least 2 crossing vertices!");
|
||||||
Vector3f direction2 = edge1.cross(newEdge).normalizeLocal();
|
}
|
||||||
Vector3f normal = temporalMesh.getNormals().get(index1);
|
// checking if all crossing vectors point to the same direction (if yes then the edge is outside the face)
|
||||||
|
float direction = Math.signum(distinctCrossingVectors.get(0).dot(edgeNormal));// if at least one vector has different direction that this - it means that the edge is inside the face
|
||||||
boolean isAngle1Interior = normal.dot(direction1) < 0;
|
for(int i=1;i<distinctCrossingVectors.size();++i) {
|
||||||
boolean isAngle2Interior = normal.dot(direction2) < 0;
|
if(direction != Math.signum(distinctCrossingVectors.get(i).dot(edgeNormal))) {
|
||||||
|
return true;
|
||||||
float angle1 = isAngle1Interior ? edge1.angleBetween(edge2) : FastMath.TWO_PI - edge1.angleBetween(edge2);
|
}
|
||||||
float angle2 = isAngle2Interior ? edge1.angleBetween(newEdge) : FastMath.TWO_PI - edge1.angleBetween(newEdge);
|
}
|
||||||
|
return false;
|
||||||
return angle1 >= angle2;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,8 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
|
|||||||
}
|
}
|
||||||
TempVars vars = TempVars.get();
|
TempVars vars = TempVars.get();
|
||||||
|
|
||||||
|
Vector3f currentVelocity = vars.vect2.set(velocity);
|
||||||
|
|
||||||
// dampen existing x/z forces
|
// dampen existing x/z forces
|
||||||
float existingLeftVelocity = velocity.dot(localLeft);
|
float existingLeftVelocity = velocity.dot(localLeft);
|
||||||
float existingForwardVelocity = velocity.dot(localForward);
|
float existingForwardVelocity = velocity.dot(localForward);
|
||||||
@ -194,7 +196,7 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
|
|||||||
//add resulting vector to existing velocity
|
//add resulting vector to existing velocity
|
||||||
velocity.addLocal(localWalkDirection);
|
velocity.addLocal(localWalkDirection);
|
||||||
}
|
}
|
||||||
rigidBody.setLinearVelocity(velocity);
|
if(currentVelocity.distance(velocity) > FastMath.ZERO_TOLERANCE) rigidBody.setLinearVelocity(velocity);
|
||||||
if (jump) {
|
if (jump) {
|
||||||
//TODO: precalculate jump force
|
//TODO: precalculate jump force
|
||||||
Vector3f rotatedJumpForce = vars.vect1;
|
Vector3f rotatedJumpForce = vars.vect1;
|
||||||
|
@ -82,8 +82,10 @@ public class SphereCollisionShape extends CollisionShape {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setScale(Vector3f scale) {
|
public void setScale(Vector3f scale) {
|
||||||
|
if (!scale.equals(Vector3f.UNIT_XYZ)) {
|
||||||
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "SphereCollisionShape cannot be scaled");
|
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "SphereCollisionShape cannot be scaled");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void createShape() {
|
protected void createShape() {
|
||||||
objectId = createShape(radius);
|
objectId = createShape(radius);
|
||||||
@ -91,7 +93,7 @@ public class SphereCollisionShape extends CollisionShape {
|
|||||||
// new SphereShape(radius);
|
// new SphereShape(radius);
|
||||||
// objectId.setLocalScaling(Converter.convert(getScale()));
|
// objectId.setLocalScaling(Converter.convert(getScale()));
|
||||||
// objectId.setMargin(margin);
|
// objectId.setMargin(margin);
|
||||||
setScale(scale);
|
setScale(scale); // Set the scale to 1
|
||||||
setMargin(margin);
|
setMargin(margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,6 +661,8 @@ public class Application implements SystemListener {
|
|||||||
* Callables are executed right at the beginning of the main loop.
|
* Callables are executed right at the beginning of the main loop.
|
||||||
* They are executed even if the application is currently paused
|
* They are executed even if the application is currently paused
|
||||||
* or out of focus.
|
* or out of focus.
|
||||||
|
*
|
||||||
|
* @param callable The callable to run in the main jME3 thread
|
||||||
*/
|
*/
|
||||||
public <V> Future<V> enqueue(Callable<V> callable) {
|
public <V> Future<V> enqueue(Callable<V> callable) {
|
||||||
AppTask<V> task = new AppTask<V>(callable);
|
AppTask<V> task = new AppTask<V>(callable);
|
||||||
@ -668,6 +670,20 @@ public class Application implements SystemListener {
|
|||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues a runnable object to execute in the jME3
|
||||||
|
* rendering thread.
|
||||||
|
* <p>
|
||||||
|
* Runnables are executed right at the beginning of the main loop.
|
||||||
|
* They are executed even if the application is currently paused
|
||||||
|
* or out of focus.
|
||||||
|
*
|
||||||
|
* @param runnable The runnable to run in the main jME3 thread
|
||||||
|
*/
|
||||||
|
public void enqueue(Runnable runnable){
|
||||||
|
enqueue(new RunnableWrapper(runnable));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs tasks enqueued via {@link #enqueue(Callable)}
|
* Runs tasks enqueued via {@link #enqueue(Callable)}
|
||||||
*/
|
*/
|
||||||
@ -752,4 +768,19 @@ public class Application implements SystemListener {
|
|||||||
return viewPort;
|
return viewPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RunnableWrapper implements Callable{
|
||||||
|
private final Runnable runnable;
|
||||||
|
|
||||||
|
public RunnableWrapper(Runnable runnable){
|
||||||
|
this.runnable = runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object call(){
|
||||||
|
runnable.run();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,11 @@ public class BIHTree implements CollisionData {
|
|||||||
this.mesh = mesh;
|
this.mesh = mesh;
|
||||||
this.maxTrisPerNode = maxTrisPerNode;
|
this.maxTrisPerNode = maxTrisPerNode;
|
||||||
|
|
||||||
if (maxTrisPerNode < 1 || mesh == null) {
|
if (maxTrisPerNode < 1) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException("maxTrisPerNode cannot be less than 1");
|
||||||
|
}
|
||||||
|
if (mesh == null) {
|
||||||
|
throw new IllegalArgumentException("Mesh cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
bihSwapTmp = new float[9];
|
bihSwapTmp = new float[9];
|
||||||
@ -451,7 +454,7 @@ public class BIHTree implements CollisionData {
|
|||||||
} else if (bv instanceof BoundingBox) {
|
} else if (bv instanceof BoundingBox) {
|
||||||
bbox = new BoundingBox((BoundingBox) bv);
|
bbox = new BoundingBox((BoundingBox) bv);
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedCollisionException();
|
throw new UnsupportedCollisionException("BoundingVolume:" + bv);
|
||||||
}
|
}
|
||||||
|
|
||||||
bbox.transform(worldMatrix.invert(), bbox);
|
bbox.transform(worldMatrix.invert(), bbox);
|
||||||
@ -470,7 +473,7 @@ public class BIHTree implements CollisionData {
|
|||||||
BoundingVolume bv = (BoundingVolume) other;
|
BoundingVolume bv = (BoundingVolume) other;
|
||||||
return collideWithBoundingVolume(bv, worldMatrix, results);
|
return collideWithBoundingVolume(bv, worldMatrix, results);
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedCollisionException();
|
throw new UnsupportedCollisionException("Collidable:" + other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,11 @@ public final class DefaultLightFilter implements LightFilter {
|
|||||||
for (int i = 0; i < worldLights.size(); i++) {
|
for (int i = 0; i < worldLights.size(); i++) {
|
||||||
Light light = worldLights.get(i);
|
Light light = worldLights.get(i);
|
||||||
|
|
||||||
|
// If this light is not enabled it will be ignored.
|
||||||
|
if (!light.isEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (light.frustumCheckNeeded) {
|
if (light.frustumCheckNeeded) {
|
||||||
processedLights.add(light);
|
processedLights.add(light);
|
||||||
light.frustumCheckNeeded = false;
|
light.frustumCheckNeeded = false;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
|
* Copyright (c) 2009-2012, 2015-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
|
||||||
@ -146,4 +146,10 @@ public class DirectionalLight extends Light {
|
|||||||
direction = (Vector3f) ic.readSavable("direction", null);
|
direction = (Vector3f) ic.readSavable("direction", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DirectionalLight clone() {
|
||||||
|
DirectionalLight l = (DirectionalLight)super.clone();
|
||||||
|
l.direction = direction.clone();
|
||||||
|
return l;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
|
* Copyright (c) 2009-2012, 2015-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
|
||||||
@ -103,9 +103,6 @@ public abstract class Light implements Savable, Cloneable {
|
|||||||
*/
|
*/
|
||||||
protected transient float lastDistance = -1;
|
protected transient float lastDistance = -1;
|
||||||
|
|
||||||
/**
|
|
||||||
* If light is disabled, it will not have any
|
|
||||||
*/
|
|
||||||
protected boolean enabled = true;
|
protected boolean enabled = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -170,18 +167,22 @@ public abstract class Light implements Savable, Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Returns true if the light is enabled
|
* Returns true if this light is enabled.
|
||||||
*
|
* @return true if enabled, otherwise false.
|
||||||
* @return true if the light is enabled
|
|
||||||
*
|
|
||||||
* @see Light#setEnabled(boolean)
|
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to false in order to disable a light and have it filtered out from being included in rendering.
|
||||||
|
*
|
||||||
|
* @param enabled true to enable and false to disable the light.
|
||||||
*/
|
*/
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
this.enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the light intersects with the given bounding box.
|
* Determines if the light intersects with the given bounding box.
|
||||||
@ -227,7 +228,9 @@ public abstract class Light implements Savable, Cloneable {
|
|||||||
@Override
|
@Override
|
||||||
public Light clone(){
|
public Light clone(){
|
||||||
try {
|
try {
|
||||||
return (Light) super.clone();
|
Light l = (Light) super.clone();
|
||||||
|
l.color = color.clone();
|
||||||
|
return l;
|
||||||
} catch (CloneNotSupportedException ex) {
|
} catch (CloneNotSupportedException ex) {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
|
* Copyright (c) 2009-2012, 2015-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
|
||||||
@ -241,4 +241,11 @@ public class PointLight extends Light {
|
|||||||
this.invRadius = 0;
|
this.invRadius = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PointLight clone() {
|
||||||
|
PointLight p = (PointLight)super.clone();
|
||||||
|
p.position = position.clone();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
|
* Copyright (c) 2009-2012, 2015-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
|
||||||
@ -448,5 +448,13 @@ public class SpotLight extends Light {
|
|||||||
this.invSpotRange = 0;
|
this.invSpotRange = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpotLight clone() {
|
||||||
|
SpotLight s = (SpotLight)super.clone();
|
||||||
|
s.direction = direction.clone();
|
||||||
|
s.position = position.clone();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -976,6 +976,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|||||||
oc.write(def.getAssetName(), "material_def", null);
|
oc.write(def.getAssetName(), "material_def", null);
|
||||||
oc.write(additionalState, "render_state", null);
|
oc.write(additionalState, "render_state", null);
|
||||||
oc.write(transparent, "is_transparent", false);
|
oc.write(transparent, "is_transparent", false);
|
||||||
|
oc.write(name, "name", null);
|
||||||
oc.writeStringSavableMap(paramValues, "parameters", null);
|
oc.writeStringSavableMap(paramValues, "parameters", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -990,6 +991,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
|||||||
public void read(JmeImporter im) throws IOException {
|
public void read(JmeImporter im) throws IOException {
|
||||||
InputCapsule ic = im.getCapsule(this);
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
|
||||||
|
name = ic.readString("name", null);
|
||||||
additionalState = (RenderState) ic.readSavable("render_state", null);
|
additionalState = (RenderState) ic.readSavable("render_state", null);
|
||||||
transparent = ic.readBoolean("is_transparent", false);
|
transparent = ic.readBoolean("is_transparent", false);
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ import com.jme3.renderer.queue.RenderQueue;
|
|||||||
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
||||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
import com.jme3.scene.*;
|
import com.jme3.scene.*;
|
||||||
import com.jme3.shader.Shader;
|
import com.jme3.shader.Uniform;
|
||||||
import com.jme3.shader.UniformBinding;
|
import com.jme3.shader.UniformBinding;
|
||||||
import com.jme3.shader.UniformBindingManager;
|
import com.jme3.shader.UniformBindingManager;
|
||||||
import com.jme3.system.NullRenderer;
|
import com.jme3.system.NullRenderer;
|
||||||
@ -483,8 +483,8 @@ public class RenderManager {
|
|||||||
* Updates the given list of uniforms with {@link UniformBinding uniform bindings}
|
* Updates the given list of uniforms with {@link UniformBinding uniform bindings}
|
||||||
* based on the current world state.
|
* based on the current world state.
|
||||||
*/
|
*/
|
||||||
public void updateUniformBindings(Shader shader) {
|
public void updateUniformBindings(List<Uniform> params) {
|
||||||
uniformBindingManager.updateUniformBindings(shader);
|
uniformBindingManager.updateUniformBindings(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -556,7 +556,7 @@ public class RenderManager {
|
|||||||
forcedRenderState = tmpRs;
|
forcedRenderState = tmpRs;
|
||||||
|
|
||||||
//Reverted this part from revision 6197
|
//Reverted this part from revision 6197
|
||||||
//If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
|
//If forcedTechnique does not exists, and forcedMaterial is not set, the geom MUST NOT be rendered
|
||||||
} else if (forcedMaterial != null) {
|
} else if (forcedMaterial != null) {
|
||||||
// use forced material
|
// use forced material
|
||||||
forcedMaterial.render(g, lightList, this);
|
forcedMaterial.render(g, lightList, this);
|
||||||
@ -586,37 +586,6 @@ public class RenderManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renderGeometryListNew(GeometryList gl) {
|
|
||||||
int size = gl.size();
|
|
||||||
int pass = 0;
|
|
||||||
|
|
||||||
// Keep rendering geometries in the list
|
|
||||||
// checking each time if they need more passes.
|
|
||||||
// Geometries which need more passes are added to the beginning
|
|
||||||
// of the list and then another pass is executed.
|
|
||||||
// In the end, all geometries will have their passes rendered.
|
|
||||||
while (true) {
|
|
||||||
int writeIdx = 0;
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
Geometry obj = gl.get(i);
|
|
||||||
renderGeometry(obj);
|
|
||||||
boolean morePasses = true;
|
|
||||||
if (morePasses) {
|
|
||||||
// Geometry wants to be rendered again.
|
|
||||||
// Move it to the beginning of the list.
|
|
||||||
gl.set(writeIdx++, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No geometries were written to the beginning of the list -
|
|
||||||
// all passes are finished.
|
|
||||||
if (writeIdx == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pass++;
|
|
||||||
size = writeIdx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preloads a scene for rendering.
|
* Preloads a scene for rendering.
|
||||||
* <p>
|
* <p>
|
||||||
@ -647,9 +616,7 @@ public class RenderManager {
|
|||||||
|
|
||||||
gm.getMaterial().preload(this);
|
gm.getMaterial().preload(this);
|
||||||
Mesh mesh = gm.getMesh();
|
Mesh mesh = gm.getMesh();
|
||||||
if (mesh != null
|
if (mesh != null) {
|
||||||
&& mesh.getVertexCount() != 0
|
|
||||||
&& mesh.getTriangleCount() != 0) {
|
|
||||||
for (VertexBuffer vb : mesh.getBufferList().getArray()) {
|
for (VertexBuffer vb : mesh.getBufferList().getArray()) {
|
||||||
if (vb.getData() != null && vb.getUsage() != VertexBuffer.Usage.CpuOnly) {
|
if (vb.getData() != null && vb.getUsage() != VertexBuffer.Usage.CpuOnly) {
|
||||||
renderer.updateBufferData(vb);
|
renderer.updateBufferData(vb);
|
||||||
@ -674,10 +641,8 @@ public class RenderManager {
|
|||||||
* <p>
|
* <p>
|
||||||
* In addition to enqueuing the visible geometries, this method
|
* In addition to enqueuing the visible geometries, this method
|
||||||
* also scenes which cast or receive shadows, by putting them into the
|
* also scenes which cast or receive shadows, by putting them into the
|
||||||
* RenderQueue's
|
* RenderQueue's {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue}.
|
||||||
* {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
|
* Each Spatial which has its {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
|
||||||
* shadow queue}. Each Spatial which has its
|
|
||||||
* {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
|
|
||||||
* set to not off, will be put into the appropriate shadow queue, note that
|
* set to not off, will be put into the appropriate shadow queue, note that
|
||||||
* this process does not check for frustum culling on any
|
* this process does not check for frustum culling on any
|
||||||
* {@link ShadowMode#Cast shadow casters}, as they don't have to be
|
* {@link ShadowMode#Cast shadow casters}, as they don't have to be
|
||||||
@ -817,10 +782,8 @@ public class RenderManager {
|
|||||||
* @param singlePassLightBatchSize the number of lights.
|
* @param singlePassLightBatchSize the number of lights.
|
||||||
*/
|
*/
|
||||||
public void setSinglePassLightBatchSize(int singlePassLightBatchSize) {
|
public void setSinglePassLightBatchSize(int singlePassLightBatchSize) {
|
||||||
if (singlePassLightBatchSize < 1) {
|
// Ensure the batch size is no less than 1
|
||||||
throw new IllegalArgumentException("batch size cannot be less than 1");
|
this.singlePassLightBatchSize = singlePassLightBatchSize < 1 ? 1 : singlePassLightBatchSize;
|
||||||
}
|
|
||||||
this.singlePassLightBatchSize = singlePassLightBatchSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1026,13 +989,12 @@ public class RenderManager {
|
|||||||
* (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
|
* (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
|
||||||
* <li>If any objects remained in the render queue, they are removed
|
* <li>If any objects remained in the render queue, they are removed
|
||||||
* from the queue. This is generally objects added to the
|
* from the queue. This is generally objects added to the
|
||||||
* {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
|
* {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue}
|
||||||
* shadow queue}
|
|
||||||
* which were not rendered because of a missing shadow renderer.</li>
|
* which were not rendered because of a missing shadow renderer.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param vp
|
* @param vp View port to render
|
||||||
* @param tpf
|
* @param tpf Time per frame value
|
||||||
*/
|
*/
|
||||||
public void renderViewPort(ViewPort vp, float tpf) {
|
public void renderViewPort(ViewPort vp, float tpf) {
|
||||||
if (!vp.isEnabled()) {
|
if (!vp.isEnabled()) {
|
||||||
|
@ -36,7 +36,6 @@ import com.jme3.shader.Shader;
|
|||||||
import com.jme3.texture.FrameBuffer;
|
import com.jme3.texture.FrameBuffer;
|
||||||
import com.jme3.texture.Image;
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.util.IntMap;
|
import com.jme3.util.IntMap;
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The statistics class allows tracking of real-time rendering statistics.
|
* The statistics class allows tracking of real-time rendering statistics.
|
||||||
|
@ -687,6 +687,11 @@ public class Node extends Spatial {
|
|||||||
// childClone.parent = nodeClone;
|
// childClone.parent = nodeClone;
|
||||||
// nodeClone.children.add(childClone);
|
// nodeClone.children.add(childClone);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Reset the fields of the clone that should be in a 'new' state.
|
||||||
|
nodeClone.updateList = null;
|
||||||
|
nodeClone.updateListValid = false; // safe because parent is nulled out in super.clone()
|
||||||
|
|
||||||
return nodeClone;
|
return nodeClone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,6 +401,25 @@ public final class BufferUtils {
|
|||||||
vector.z = buf.get(index * 3 + 2);
|
vector.z = buf.get(index * 3 + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the values of the given vector from the specified buffer at the
|
||||||
|
* index provided.
|
||||||
|
*
|
||||||
|
* @param vector
|
||||||
|
* the vector to set data on
|
||||||
|
* @param buf
|
||||||
|
* the buffer to read from
|
||||||
|
* @param index
|
||||||
|
* the position (in terms of vectors, not floats) to read from
|
||||||
|
* the buf
|
||||||
|
*/
|
||||||
|
public static void populateFromBuffer(Vector4f vector, FloatBuffer buf, int index) {
|
||||||
|
vector.x = buf.get(index * 4);
|
||||||
|
vector.y = buf.get(index * 4 + 1);
|
||||||
|
vector.z = buf.get(index * 4 + 2);
|
||||||
|
vector.w = buf.get(index * 4 + 3);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a Vector3f array from the given FloatBuffer.
|
* Generates a Vector3f array from the given FloatBuffer.
|
||||||
*
|
*
|
||||||
|
@ -32,11 +32,12 @@ void main(){
|
|||||||
#ifdef POINT_SPRITE
|
#ifdef POINT_SPRITE
|
||||||
vec4 worldPos = g_WorldMatrix * pos;
|
vec4 worldPos = g_WorldMatrix * pos;
|
||||||
float d = distance(g_CameraPosition.xyz, worldPos.xyz);
|
float d = distance(g_CameraPosition.xyz, worldPos.xyz);
|
||||||
gl_PointSize = max(1.0, (inSize * SIZE_MULTIPLIER * m_Quadratic) / d);
|
float size = (inSize * SIZE_MULTIPLIER * m_Quadratic) / d);
|
||||||
|
gl_PointSize = max(1.0, size);
|
||||||
|
|
||||||
//vec4 worldViewPos = g_WorldViewMatrix * pos;
|
//vec4 worldViewPos = g_WorldViewMatrix * pos;
|
||||||
//gl_PointSize = (inSize * SIZE_MULTIPLIER * m_Quadratic)*100.0 / worldViewPos.z;
|
//gl_PointSize = (inSize * SIZE_MULTIPLIER * m_Quadratic)*100.0 / worldViewPos.z;
|
||||||
|
|
||||||
color.a *= min(gl_PointSize, 1.0);
|
color.a *= min(size, 1.0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
@ -95,6 +95,25 @@ Gamepad\ F310\ (Controller).ry=rz
|
|||||||
# keeps it from confusing the .rx mapping.
|
# keeps it from confusing the .rx mapping.
|
||||||
Gamepad\ F310\ (Controller).z=trigger
|
Gamepad\ F310\ (Controller).z=trigger
|
||||||
|
|
||||||
|
# Logitech F310 gamepad with dip switch XInput for Windows 10
|
||||||
|
Controller\ (Gamepad\ F310).0=2
|
||||||
|
Controller\ (Gamepad\ F310).1=1
|
||||||
|
Controller\ (Gamepad\ F310).2=3
|
||||||
|
Controller\ (Gamepad\ F310).3=0
|
||||||
|
|
||||||
|
Controller\ (Gamepad\ F310).6=8
|
||||||
|
Controller\ (Gamepad\ F310).7=9
|
||||||
|
|
||||||
|
Controller\ (Gamepad\ F310).8=10
|
||||||
|
Controller\ (Gamepad\ F310).9=11
|
||||||
|
|
||||||
|
Controller\ (Gamepad\ F310).rx=z
|
||||||
|
Controller\ (Gamepad\ F310).ry=rz
|
||||||
|
|
||||||
|
# requires custom code to support trigger buttons but this
|
||||||
|
# keeps it from confusing the .rx mapping.
|
||||||
|
Controller\ (Gamepad\ F310).z=trigger
|
||||||
|
|
||||||
# Alternate version of the XBOX 360 controller
|
# Alternate version of the XBOX 360 controller
|
||||||
XBOX\ 360\ For\ Windows\ (Controller).0=2
|
XBOX\ 360\ For\ Windows\ (Controller).0=2
|
||||||
XBOX\ 360\ For\ Windows\ (Controller).1=1
|
XBOX\ 360\ For\ Windows\ (Controller).1=1
|
||||||
|
@ -155,7 +155,7 @@ public class TextureAtlas {
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (normal != null && normal.getKey() != null) {
|
if (normal != null && normal.getKey() != null) {
|
||||||
addTexture(diffuse, "NormalMap", keyName);
|
addTexture(normal, "NormalMap", keyName);
|
||||||
}
|
}
|
||||||
if (specular != null && specular.getKey() != null) {
|
if (specular != null && specular.getKey() != null) {
|
||||||
addTexture(specular, "SpecularMap", keyName);
|
addTexture(specular, "SpecularMap", keyName);
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
package jme3test.app;
|
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.shape.Box;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author john01dav
|
||||||
|
*/
|
||||||
|
public class TestEnqueueRunnable extends SimpleApplication{
|
||||||
|
private ExampleAsyncTask exampleAsyncTask;
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
new TestEnqueueRunnable().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void simpleInitApp(){
|
||||||
|
Geometry geom = new Geometry("Box", new Box(1, 1, 1));
|
||||||
|
Material material = new Material(getAssetManager(), "/Common/MatDefs/Misc/Unshaded.j3md");
|
||||||
|
material.setColor("Color", ColorRGBA.Blue); //a color is needed to start with
|
||||||
|
geom.setMaterial(material);
|
||||||
|
getRootNode().attachChild(geom);
|
||||||
|
|
||||||
|
exampleAsyncTask = new ExampleAsyncTask(material);
|
||||||
|
exampleAsyncTask.getThread().start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy(){
|
||||||
|
exampleAsyncTask.endTask();
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExampleAsyncTask implements Runnable{
|
||||||
|
private final Thread thread;
|
||||||
|
private final Material material;
|
||||||
|
private volatile boolean running = true;
|
||||||
|
|
||||||
|
public ExampleAsyncTask(Material material){
|
||||||
|
this.thread = new Thread(this);
|
||||||
|
this.material = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Thread getThread(){
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
while(running){
|
||||||
|
enqueue(new Runnable(){ //primary usage of this in real applications would use lambda expressions which are unavailable at java 6
|
||||||
|
public void run(){
|
||||||
|
material.setColor("Color", ColorRGBA.randomColor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try{
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}catch(InterruptedException e){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endTask(){
|
||||||
|
running = false;
|
||||||
|
thread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -70,20 +70,18 @@ public class TestManyLightsSingle extends SimpleApplication {
|
|||||||
* Switch mode with space bar at run time
|
* Switch mode with space bar at run time
|
||||||
*/
|
*/
|
||||||
TechniqueDef.LightMode lm = TechniqueDef.LightMode.SinglePass;
|
TechniqueDef.LightMode lm = TechniqueDef.LightMode.SinglePass;
|
||||||
int lightNum = 6;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void simpleInitApp() {
|
public void simpleInitApp() {
|
||||||
renderManager.setPreferredLightMode(lm);
|
renderManager.setPreferredLightMode(lm);
|
||||||
renderManager.setSinglePassLightBatchSize(lightNum);
|
renderManager.setSinglePassLightBatchSize(6);
|
||||||
|
|
||||||
|
|
||||||
flyCam.setMoveSpeed(10);
|
flyCam.setMoveSpeed(10);
|
||||||
|
|
||||||
Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene");
|
Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene");
|
||||||
rootNode.attachChild(scene);
|
rootNode.attachChild(scene);
|
||||||
Node n = (Node) rootNode.getChild(0);
|
Node n = (Node) rootNode.getChild(0);
|
||||||
LightList lightList = n.getWorldLightList();
|
final LightList lightList = n.getWorldLightList();
|
||||||
final Geometry g = (Geometry) n.getChild("Grid-geom-1");
|
final Geometry g = (Geometry) n.getChild("Grid-geom-1");
|
||||||
|
|
||||||
g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
|
g.getMaterial().setColor("Ambient", new ColorRGBA(0.2f, 0.2f, 0.2f, 1f));
|
||||||
@ -152,8 +150,6 @@ public class TestManyLightsSingle extends SimpleApplication {
|
|||||||
// guiNode.setCullHint(CullHint.Always);
|
// guiNode.setCullHint(CullHint.Always);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
flyCam.setDragToRotate(true);
|
flyCam.setDragToRotate(true);
|
||||||
flyCam.setMoveSpeed(50);
|
flyCam.setMoveSpeed(50);
|
||||||
|
|
||||||
@ -168,27 +164,35 @@ public class TestManyLightsSingle extends SimpleApplication {
|
|||||||
helloText.setText("(Multi pass)");
|
helloText.setText("(Multi pass)");
|
||||||
} else {
|
} else {
|
||||||
lm = TechniqueDef.LightMode.SinglePass;
|
lm = TechniqueDef.LightMode.SinglePass;
|
||||||
helloText.setText("(Single pass) nb lights per batch : " + lightNum);
|
helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
|
||||||
}
|
}
|
||||||
renderManager.setPreferredLightMode(lm);
|
renderManager.setPreferredLightMode(lm);
|
||||||
reloadScene(g,boxGeo,cubeNodes);
|
reloadScene(g, boxGeo, cubeNodes);
|
||||||
}
|
}
|
||||||
if (name.equals("lightsUp") && isPressed) {
|
if (name.equals("lightsUp") && isPressed) {
|
||||||
lightNum++;
|
renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() + 1);
|
||||||
renderManager.setSinglePassLightBatchSize(lightNum);
|
helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
|
||||||
helloText.setText("(Single pass) nb lights per batch : " + lightNum);
|
|
||||||
}
|
}
|
||||||
if (name.equals("lightsDown") && isPressed) {
|
if (name.equals("lightsDown") && isPressed) {
|
||||||
lightNum--;
|
renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() - 1);
|
||||||
renderManager.setSinglePassLightBatchSize(lightNum);
|
helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
|
||||||
helloText.setText("(Single pass) nb lights per batch : " + lightNum);
|
}
|
||||||
|
if (name.equals("toggleOnOff") && isPressed) {
|
||||||
|
for (final Light light : lightList) {
|
||||||
|
if (light instanceof AmbientLight) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
light.setEnabled(!light.isEnabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "toggle", "lightsUp", "lightsDown");
|
}
|
||||||
|
}, "toggle", "lightsUp", "lightsDown", "toggleOnOff");
|
||||||
|
|
||||||
inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
|
inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
|
||||||
inputManager.addMapping("lightsUp", new KeyTrigger(KeyInput.KEY_UP));
|
inputManager.addMapping("lightsUp", new KeyTrigger(KeyInput.KEY_UP));
|
||||||
inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN));
|
inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN));
|
||||||
|
inputManager.addMapping("toggleOnOff", new KeyTrigger(KeyInput.KEY_L));
|
||||||
|
|
||||||
|
|
||||||
SpotLight spot = new SpotLight();
|
SpotLight spot = new SpotLight();
|
||||||
@ -215,12 +219,9 @@ public class TestManyLightsSingle extends SimpleApplication {
|
|||||||
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
|
guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
|
||||||
helloText = new BitmapText(guiFont, false);
|
helloText = new BitmapText(guiFont, false);
|
||||||
helloText.setSize(guiFont.getCharSet().getRenderedSize());
|
helloText.setSize(guiFont.getCharSet().getRenderedSize());
|
||||||
helloText.setText("(Single pass) nb lights per batch : " + lightNum);
|
helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize());
|
||||||
helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
|
helloText.setLocalTranslation(300, helloText.getLineHeight(), 0);
|
||||||
guiNode.attachChild(helloText);
|
guiNode.attachChild(helloText);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reloadScene(Geometry g, Geometry boxGeo, Node cubeNodes) {
|
protected void reloadScene(Geometry g, Geometry boxGeo, Node cubeNodes) {
|
||||||
|
@ -456,7 +456,7 @@ public class PhysicsVehicle extends PhysicsRigidBody {
|
|||||||
/**
|
/**
|
||||||
* Get the current forward vector of the vehicle in world coordinates
|
* Get the current forward vector of the vehicle in world coordinates
|
||||||
* @param vector The object to write the forward vector values to.
|
* @param vector The object to write the forward vector values to.
|
||||||
* Passing null will cause a new {@link Vector3f) to be created.
|
* Passing null will cause a new {@link Vector3f} to be created.
|
||||||
* @return The forward vector
|
* @return The forward vector
|
||||||
*/
|
*/
|
||||||
public Vector3f getForwardVector(Vector3f vector) {
|
public Vector3f getForwardVector(Vector3f vector) {
|
||||||
|
@ -301,6 +301,7 @@ public class DefaultClient implements Client
|
|||||||
|
|
||||||
protected void closeConnections( DisconnectInfo info )
|
protected void closeConnections( DisconnectInfo info )
|
||||||
{
|
{
|
||||||
|
synchronized(this) {
|
||||||
if( !isRunning )
|
if( !isRunning )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -324,14 +325,16 @@ public class DefaultClient implements Client
|
|||||||
// Just in case we never fully connected
|
// Just in case we never fully connected
|
||||||
connecting.countDown();
|
connecting.countDown();
|
||||||
|
|
||||||
fireDisconnected(info);
|
|
||||||
|
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
|
|
||||||
// Terminate the services
|
// Terminate the services
|
||||||
services.terminate();
|
services.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we aren't synched while firing events
|
||||||
|
fireDisconnected(info);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addClientStateListener( ClientStateListener listener )
|
public void addClientStateListener( ClientStateListener listener )
|
||||||
{
|
{
|
||||||
@ -462,11 +465,17 @@ public class DefaultClient implements Client
|
|||||||
this.id = (int)crm.getId();
|
this.id = (int)crm.getId();
|
||||||
log.log( Level.FINE, "Connection established, id:{0}.", this.id );
|
log.log( Level.FINE, "Connection established, id:{0}.", this.id );
|
||||||
connecting.countDown();
|
connecting.countDown();
|
||||||
fireConnected();
|
//fireConnected();
|
||||||
} else {
|
} else {
|
||||||
// Else it's a message letting us know that the
|
// Else it's a message letting us know that the
|
||||||
// hosted services have been started
|
// hosted services have been started
|
||||||
startServices();
|
startServices();
|
||||||
|
|
||||||
|
// Delay firing 'connected' until the services have all
|
||||||
|
// been started to avoid odd race conditions. If there is some
|
||||||
|
// need to get some kind of event before the services have been
|
||||||
|
// started then we should create a new event step.
|
||||||
|
fireConnected();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if( m instanceof ChannelInfoMessage ) {
|
} else if( m instanceof ChannelInfoMessage ) {
|
||||||
|
@ -608,7 +608,7 @@ public class DefaultServer implements Server
|
|||||||
// should always already be closed through all paths that I
|
// should always already be closed through all paths that I
|
||||||
// can conceive... but it doesn't hurt to be sure.
|
// can conceive... but it doesn't hurt to be sure.
|
||||||
for( Endpoint p : channels ) {
|
for( Endpoint p : channels ) {
|
||||||
if( p == null )
|
if( p == null || !p.isConnected() )
|
||||||
continue;
|
continue;
|
||||||
p.close();
|
p.close();
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,8 @@ public class KernelAdapter extends Thread
|
|||||||
|
|
||||||
// Kill the kernel
|
// Kill the kernel
|
||||||
kernel.terminate();
|
kernel.terminate();
|
||||||
|
|
||||||
|
join();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reportError( Endpoint p, Object context, Exception e )
|
protected void reportError( Endpoint p, Object context, Exception e )
|
||||||
@ -120,9 +122,11 @@ public class KernelAdapter extends Thread
|
|||||||
// retrieve them. For now we'll just log it. FIXME
|
// retrieve them. For now we'll just log it. FIXME
|
||||||
log.log( Level.SEVERE, "Unhandled error, endpoint:" + p + ", context:" + context, e );
|
log.log( Level.SEVERE, "Unhandled error, endpoint:" + p + ", context:" + context, e );
|
||||||
|
|
||||||
|
if( p.isConnected() ) {
|
||||||
// In lieu of other options, at least close the endpoint
|
// In lieu of other options, at least close the endpoint
|
||||||
p.close();
|
p.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected HostedConnection getConnection( Endpoint p )
|
protected HostedConnection getConnection( Endpoint p )
|
||||||
{
|
{
|
||||||
|
@ -181,7 +181,7 @@ public class MessageProtocol
|
|||||||
Message m = (Message)obj;
|
Message m = (Message)obj;
|
||||||
messages.add(m);
|
messages.add(m);
|
||||||
} catch( IOException e ) {
|
} catch( IOException e ) {
|
||||||
throw new RuntimeException( "Error deserializing object, clas ID:" + buffer.getShort(0), e );
|
throw new RuntimeException( "Error deserializing object, class ID:" + buffer.getShort(0), e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,18 @@ public abstract class AbstractKernel implements Kernel
|
|||||||
log.log( Level.SEVERE, "Unhanddled kernel error", e );
|
log.log( Level.SEVERE, "Unhanddled kernel error", e );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void wakeupReader() {
|
||||||
|
// If there are no pending messages then add one so that the
|
||||||
|
// kernel-user knows to wake up if it is only listening for
|
||||||
|
// envelopes.
|
||||||
|
if( !hasEnvelopes() ) {
|
||||||
|
// Note: this is not really a race condition. At worst, our
|
||||||
|
// event has already been handled by now and it does no harm
|
||||||
|
// to check again.
|
||||||
|
addEnvelope( EVENTS_PENDING );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected long nextEndpointId()
|
protected long nextEndpointId()
|
||||||
{
|
{
|
||||||
return nextId.getAndIncrement();
|
return nextId.getAndIncrement();
|
||||||
|
@ -106,6 +106,9 @@ public class SelectorKernel extends AbstractKernel
|
|||||||
try {
|
try {
|
||||||
thread.close();
|
thread.close();
|
||||||
thread = null;
|
thread = null;
|
||||||
|
|
||||||
|
// Need to let any caller waiting for a read() wakeup
|
||||||
|
wakeupReader();
|
||||||
} catch( IOException e ) {
|
} catch( IOException e ) {
|
||||||
throw new KernelException( "Error closing host connection:" + address, e );
|
throw new KernelException( "Error closing host connection:" + address, e );
|
||||||
}
|
}
|
||||||
@ -164,15 +167,7 @@ public class SelectorKernel extends AbstractKernel
|
|||||||
// Enqueue an endpoint event for the listeners
|
// Enqueue an endpoint event for the listeners
|
||||||
addEvent( EndpointEvent.createRemove( this, p ) );
|
addEvent( EndpointEvent.createRemove( this, p ) );
|
||||||
|
|
||||||
// If there are no pending messages then add one so that the
|
wakeupReader();
|
||||||
// kernel-user knows to wake up if it is only listening for
|
|
||||||
// envelopes.
|
|
||||||
if( !hasEnvelopes() ) {
|
|
||||||
// Note: this is not really a race condition. At worst, our
|
|
||||||
// event has already been handled by now and it does no harm
|
|
||||||
// to check again.
|
|
||||||
addEnvelope( EVENTS_PENDING );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,6 +110,9 @@ public class UdpKernel extends AbstractKernel
|
|||||||
thread.close();
|
thread.close();
|
||||||
writer.shutdown();
|
writer.shutdown();
|
||||||
thread = null;
|
thread = null;
|
||||||
|
|
||||||
|
// Need to let any caller waiting for a read() wakeup
|
||||||
|
wakeupReader();
|
||||||
} catch( IOException e ) {
|
} catch( IOException e ) {
|
||||||
throw new KernelException( "Error closing host connection:" + address, e );
|
throw new KernelException( "Error closing host connection:" + address, e );
|
||||||
}
|
}
|
||||||
@ -170,15 +173,7 @@ public class UdpKernel extends AbstractKernel
|
|||||||
|
|
||||||
addEvent( EndpointEvent.createRemove( this, p ) );
|
addEvent( EndpointEvent.createRemove( this, p ) );
|
||||||
|
|
||||||
// If there are no pending messages then add one so that the
|
wakeupReader();
|
||||||
// kernel-user knows to wake up if it is only listening for
|
|
||||||
// envelopes.
|
|
||||||
if( !hasEnvelopes() ) {
|
|
||||||
// Note: this is not really a race condition. At worst, our
|
|
||||||
// event has already been handled by now and it does no harm
|
|
||||||
// to check again.
|
|
||||||
addEnvelope( EVENTS_PENDING );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void newData( DatagramPacket packet )
|
protected void newData( DatagramPacket packet )
|
||||||
|
@ -146,15 +146,17 @@ public class SerializerRegistrationsMessage extends AbstractMessage {
|
|||||||
// that also run their own servers but realistically they would have
|
// that also run their own servers but realistically they would have
|
||||||
// to disable the ServerSerializerRegistrationsServer anyway.
|
// to disable the ServerSerializerRegistrationsServer anyway.
|
||||||
if( compiled != null ) {
|
if( compiled != null ) {
|
||||||
log.log( Level.INFO, "Skipping registration as registry is locked, presumably by a local server process.");
|
log.log(Level.INFO, "Skipping registration as registry is locked, presumably by a local server process.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.log(Level.FINE, "Registering {0} classes...", registrations.length);
|
||||||
for( Registration reg : registrations ) {
|
for( Registration reg : registrations ) {
|
||||||
log.log( Level.INFO, "Registering:{0}", reg);
|
log.log(Level.INFO, "Registering:{0}", reg);
|
||||||
reg.register();
|
reg.register();
|
||||||
}
|
}
|
||||||
|
log.log(Level.FINE, "Done registering serializable classes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -187,7 +189,7 @@ public class SerializerRegistrationsMessage extends AbstractMessage {
|
|||||||
serializer = (Serializer)serializerType.newInstance();
|
serializer = (Serializer)serializerType.newInstance();
|
||||||
}
|
}
|
||||||
SerializerRegistration result = Serializer.registerClassForId(id, type, serializer);
|
SerializerRegistration result = Serializer.registerClassForId(id, type, serializer);
|
||||||
log.log( Level.FINE, " result:{0}", result);
|
log.log(Level.FINE, " result:{0}", result);
|
||||||
} catch( ClassNotFoundException e ) {
|
} catch( ClassNotFoundException e ) {
|
||||||
throw new RuntimeException( "Class not found attempting to register:" + this, e );
|
throw new RuntimeException( "Class not found attempting to register:" + this, e );
|
||||||
} catch( InstantiationException e ) {
|
} catch( InstantiationException e ) {
|
||||||
|
@ -425,6 +425,22 @@ public abstract class Serializer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SerializerRegistration reg = writeClass(buffer, object.getClass());
|
SerializerRegistration reg = writeClass(buffer, object.getClass());
|
||||||
|
|
||||||
|
// If the caller (or us) has registered a generic base class (like Enum)
|
||||||
|
// that is meant to steer automatic resolution for things like FieldSerializer
|
||||||
|
// that have final classes in fields... then there are cases where the exact
|
||||||
|
// type isn't known by the outer class. (Think of a message object
|
||||||
|
// that has an Object field but tries to send an Enum subclass in it.)
|
||||||
|
// In that case, the SerializerRegistration object we get back isn't
|
||||||
|
// really going to be capable of recreating the object on the other
|
||||||
|
// end because it won't know what class to use. This only comes up
|
||||||
|
// in writeclassAndObejct() because we just wrote an ID to a more generic
|
||||||
|
// class than will be readable on the other end. The check is simple, though.
|
||||||
|
if( reg.getType() != object.getClass() ) {
|
||||||
|
throw new IllegalArgumentException("Class has not been registered:"
|
||||||
|
+ object.getClass() + " but resolved to generic serializer for:" + reg.getType());
|
||||||
|
}
|
||||||
|
|
||||||
reg.getSerializer().writeObject(buffer, object);
|
reg.getSerializer().writeObject(buffer, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +48,9 @@ public class EnumSerializer extends Serializer {
|
|||||||
|
|
||||||
if (ordinal == -1) return null;
|
if (ordinal == -1) return null;
|
||||||
T[] enumConstants = c.getEnumConstants();
|
T[] enumConstants = c.getEnumConstants();
|
||||||
if (enumConstants == null)
|
if (enumConstants == null) {
|
||||||
throw new SerializerException( "Class has no enum constants:" + c );
|
throw new SerializerException("Class has no enum constants:" + c + " Ordinal:" + ordinal);
|
||||||
|
}
|
||||||
return enumConstants[ordinal];
|
return enumConstants[ordinal];
|
||||||
} catch (IndexOutOfBoundsException ex) {
|
} catch (IndexOutOfBoundsException ex) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -34,11 +34,14 @@ package com.jme3.network.serializing.serializers;
|
|||||||
import com.jme3.network.serializing.Serializer;
|
import com.jme3.network.serializing.Serializer;
|
||||||
import com.jme3.network.serializing.SerializerException;
|
import com.jme3.network.serializing.SerializerException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The field serializer is the default serializer used for custom class.
|
* The field serializer is the default serializer used for custom class.
|
||||||
@ -46,16 +49,35 @@ import java.util.*;
|
|||||||
* @author Lars Wesselius, Nathan Sweet
|
* @author Lars Wesselius, Nathan Sweet
|
||||||
*/
|
*/
|
||||||
public class FieldSerializer extends Serializer {
|
public class FieldSerializer extends Serializer {
|
||||||
|
|
||||||
|
static final Logger log = Logger.getLogger(FieldSerializer.class.getName());
|
||||||
|
|
||||||
private static Map<Class, SavedField[]> savedFields = new HashMap<Class, SavedField[]>();
|
private static Map<Class, SavedField[]> savedFields = new HashMap<Class, SavedField[]>();
|
||||||
|
private static Map<Class, Constructor> savedCtors = new HashMap<Class, Constructor>();
|
||||||
|
|
||||||
protected void checkClass(Class clazz) {
|
protected void checkClass(Class clazz) {
|
||||||
|
|
||||||
// See if the class has a public no-arg constructor
|
// See if the class has a public no-arg constructor
|
||||||
try {
|
try {
|
||||||
clazz.getConstructor();
|
savedCtors.put(clazz, clazz.getConstructor());
|
||||||
|
return;
|
||||||
} catch( NoSuchMethodException e ) {
|
} catch( NoSuchMethodException e ) {
|
||||||
throw new RuntimeException( "Registration error: no-argument constructor not found on:" + clazz );
|
//throw new RuntimeException( "Registration error: no-argument constructor not found on:" + clazz );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See if it has a non-public no-arg constructor
|
||||||
|
try {
|
||||||
|
Constructor ctor = clazz.getDeclaredConstructor();
|
||||||
|
|
||||||
|
// Make sure we can call it later.
|
||||||
|
ctor.setAccessible(true);
|
||||||
|
|
||||||
|
savedCtors.put(clazz, ctor);
|
||||||
|
return;
|
||||||
|
} catch( NoSuchMethodException e ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException( "Registration error: no-argument constructor not found on:" + clazz );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(Class clazz) {
|
public void initialize(Class clazz) {
|
||||||
@ -121,7 +143,8 @@ public class FieldSerializer extends Serializer {
|
|||||||
|
|
||||||
T object;
|
T object;
|
||||||
try {
|
try {
|
||||||
object = c.newInstance();
|
Constructor<T> ctor = (Constructor<T>)savedCtors.get(c);
|
||||||
|
object = ctor.newInstance();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new SerializerException( "Error creating object of type:" + c, e );
|
throw new SerializerException( "Error creating object of type:" + c, e );
|
||||||
}
|
}
|
||||||
@ -129,6 +152,9 @@ public class FieldSerializer extends Serializer {
|
|||||||
for (SavedField savedField : fields) {
|
for (SavedField savedField : fields) {
|
||||||
Field field = savedField.field;
|
Field field = savedField.field;
|
||||||
Serializer serializer = savedField.serializer;
|
Serializer serializer = savedField.serializer;
|
||||||
|
if( log.isLoggable(Level.FINER) ) {
|
||||||
|
log.log(Level.FINER, "Reading field:{0} using serializer:{1}", new Object[]{field, serializer});
|
||||||
|
}
|
||||||
Object value;
|
Object value;
|
||||||
|
|
||||||
if (serializer != null) {
|
if (serializer != null) {
|
||||||
@ -164,9 +190,12 @@ public class FieldSerializer extends Serializer {
|
|||||||
try {
|
try {
|
||||||
val = savedField.field.get(object);
|
val = savedField.field.get(object);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
throw new SerializerException("Unable to access field:" + savedField.field + " on:" + object, e);
|
||||||
}
|
}
|
||||||
Serializer serializer = savedField.serializer;
|
Serializer serializer = savedField.serializer;
|
||||||
|
if( log.isLoggable(Level.FINER) ) {
|
||||||
|
log.log(Level.FINER, "Writing field:{0} using serializer:{1}", new Object[]{savedField.field, serializer});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (serializer != null) {
|
if (serializer != null) {
|
||||||
|
@ -351,6 +351,11 @@ public class RmiRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object invoke( short procId, Object[] args ) {
|
public Object invoke( short procId, Object[] args ) {
|
||||||
|
if( log.isLoggable(Level.FINEST) ) {
|
||||||
|
log.finest("SharedObject->invoking:" + classInfo.getMethod(procId)
|
||||||
|
+ " on:" + object
|
||||||
|
+ " with:" + (args == null ? "null" : Arrays.asList(args)));
|
||||||
|
}
|
||||||
return classInfo.getMethod(procId).invoke(object, args);
|
return classInfo.getMethod(procId).invoke(object, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,6 +225,7 @@ public class RpcConnection {
|
|||||||
private class ResponseHolder {
|
private class ResponseHolder {
|
||||||
private Object response;
|
private Object response;
|
||||||
private String error;
|
private String error;
|
||||||
|
private Throwable exception;
|
||||||
private RpcCallMessage msg;
|
private RpcCallMessage msg;
|
||||||
boolean received = false;
|
boolean received = false;
|
||||||
|
|
||||||
@ -235,6 +236,7 @@ public class RpcConnection {
|
|||||||
public synchronized void setResponse( RpcResponseMessage msg ) {
|
public synchronized void setResponse( RpcResponseMessage msg ) {
|
||||||
this.response = msg.getResult();
|
this.response = msg.getResult();
|
||||||
this.error = msg.getError();
|
this.error = msg.getError();
|
||||||
|
this.exception = msg.getThrowable();
|
||||||
this.received = true;
|
this.received = true;
|
||||||
notifyAll();
|
notifyAll();
|
||||||
}
|
}
|
||||||
@ -250,6 +252,9 @@ public class RpcConnection {
|
|||||||
if( error != null ) {
|
if( error != null ) {
|
||||||
throw new RuntimeException("Error calling remote procedure:" + msg + "\n" + error);
|
throw new RuntimeException("Error calling remote procedure:" + msg + "\n" + error);
|
||||||
}
|
}
|
||||||
|
if( exception != null ) {
|
||||||
|
throw new RuntimeException("Error calling remote procedure:" + msg, exception);
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ package com.jme3.network.service.rpc.msg;
|
|||||||
|
|
||||||
import com.jme3.network.AbstractMessage;
|
import com.jme3.network.AbstractMessage;
|
||||||
import com.jme3.network.serializing.Serializable;
|
import com.jme3.network.serializing.Serializable;
|
||||||
|
import com.jme3.network.serializing.Serializer;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ public class RpcResponseMessage extends AbstractMessage {
|
|||||||
private long msgId;
|
private long msgId;
|
||||||
private Object result;
|
private Object result;
|
||||||
private String error;
|
private String error;
|
||||||
|
private Object exception; // if it was serializable
|
||||||
|
|
||||||
public RpcResponseMessage() {
|
public RpcResponseMessage() {
|
||||||
}
|
}
|
||||||
@ -62,12 +64,31 @@ public class RpcResponseMessage extends AbstractMessage {
|
|||||||
public RpcResponseMessage( long msgId, Throwable t ) {
|
public RpcResponseMessage( long msgId, Throwable t ) {
|
||||||
this.msgId = msgId;
|
this.msgId = msgId;
|
||||||
|
|
||||||
|
// See if the exception is serializable
|
||||||
|
if( isSerializable(t) ) {
|
||||||
|
// Can send the exception itself
|
||||||
|
this.exception = t;
|
||||||
|
} else {
|
||||||
|
// We'll compose all of the info into a string
|
||||||
StringWriter sOut = new StringWriter();
|
StringWriter sOut = new StringWriter();
|
||||||
PrintWriter out = new PrintWriter(sOut);
|
PrintWriter out = new PrintWriter(sOut);
|
||||||
t.printStackTrace(out);
|
t.printStackTrace(out);
|
||||||
out.close();
|
out.close();
|
||||||
this.error = sOut.toString();
|
this.error = sOut.toString();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSerializable( Throwable error ) {
|
||||||
|
if( error == null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for( Throwable t = error; t != null; t = t.getCause() ) {
|
||||||
|
if( Serializer.getExactSerializerRegistration(t.getClass()) == null ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public long getMessageId() {
|
public long getMessageId() {
|
||||||
return msgId;
|
return msgId;
|
||||||
@ -81,10 +102,15 @@ public class RpcResponseMessage extends AbstractMessage {
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Throwable getThrowable() {
|
||||||
|
return (Throwable)exception;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + "[#" + msgId + ", result=" + result
|
return getClass().getSimpleName() + "[#" + msgId + ", result=" + result
|
||||||
+ (error != null ? ", error=" + error : "")
|
+ (error != null ? ", error=" + error : "")
|
||||||
|
+ (exception != null ? ", exception=" + exception : "")
|
||||||
+ "]";
|
+ "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
CTL_AssetPackBrowserAction=AssetPackBrowser
|
CTL_AssetPackBrowserAction=AssetPackBrowser
|
||||||
CTL_AssetPackBrowserTopComponent=AssetPackBrowser Window
|
CTL_AssetPackBrowserTopComponent=AssetPackBrowser
|
||||||
HINT_AssetPackBrowserTopComponent=This is a AssetPackBrowser window
|
HINT_AssetPackBrowserTopComponent=The AssetPackBrowser allows easy managing of your AssetPacks
|
||||||
AssetPackBrowserTopComponent.jTextField1.text=search
|
AssetPackBrowserTopComponent.jTextField1.text=search
|
||||||
AssetPackBrowserTopComponent.jButton1.text=update
|
AssetPackBrowserTopComponent.jButton1.text=update
|
||||||
AssetPackBrowserTopComponent.jButton2.text=online assetpacks
|
AssetPackBrowserTopComponent.jButton2.text=online assetpacks
|
||||||
|
@ -67,8 +67,8 @@ persistenceType = TopComponent.PERSISTENCE_ALWAYS)
|
|||||||
preferredID = "AppStateExplorerTopComponent")
|
preferredID = "AppStateExplorerTopComponent")
|
||||||
@Messages({
|
@Messages({
|
||||||
"CTL_AppStateExplorerAction=AppStateExplorer",
|
"CTL_AppStateExplorerAction=AppStateExplorer",
|
||||||
"CTL_AppStateExplorerTopComponent=AppStateExplorer Window",
|
"CTL_AppStateExplorerTopComponent=AppStateExplorer",
|
||||||
"HINT_AppStateExplorerTopComponent=This is a AppStateExplorer window"
|
"HINT_AppStateExplorerTopComponent=The AppStateExplorer provides an Overview over your current AppState"
|
||||||
})
|
})
|
||||||
public final class AppStateExplorerTopComponent extends TopComponent implements ExplorerManager.Provider {
|
public final class AppStateExplorerTopComponent extends TopComponent implements ExplorerManager.Provider {
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
CTL_FilterExplorerAction=FilterExplorer
|
CTL_FilterExplorerAction=FilterExplorer
|
||||||
CTL_FilterExplorerTopComponent=FilterExplorer Window
|
CTL_FilterExplorerTopComponent=FilterExplorer
|
||||||
HINT_FilterExplorerTopComponent=This is a FilterExplorer window
|
HINT_FilterExplorerTopComponent=The FilterExplorer provides an Overview over your current Filter
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
CTL_SceneExplorerAction=SceneExplorer
|
CTL_SceneExplorerAction=SceneExplorer
|
||||||
CTL_SceneExplorerTopComponent=SceneExplorer Window
|
CTL_SceneExplorerTopComponent=SceneExplorer
|
||||||
HINT_SceneExplorerTopComponent=This is a SceneExplorer window
|
HINT_SceneExplorerTopComponent=The SceneExplorer provides an Overview over the SceneGraph of your Scene.
|
||||||
SceneExplorerTopComponent.jButton1.text=update
|
SceneExplorerTopComponent.jButton1.text=update
|
||||||
|
@ -32,14 +32,16 @@
|
|||||||
package com.jme3.gde.terraineditor.sky;
|
package com.jme3.gde.terraineditor.sky;
|
||||||
|
|
||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.texture.Image;
|
||||||
import com.jme3.texture.Texture;
|
import com.jme3.texture.Texture;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
import org.openide.WizardDescriptor;
|
import org.openide.WizardDescriptor;
|
||||||
|
import org.openide.WizardValidationException;
|
||||||
import org.openide.util.HelpCtx;
|
import org.openide.util.HelpCtx;
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
public class SkyboxWizardPanel2 implements WizardDescriptor.Panel {
|
public class SkyboxWizardPanel2 implements WizardDescriptor.ValidatingPanel<WizardDescriptor> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The visual component that displays this panel. If you need to access the
|
* The visual component that displays this panel. If you need to access the
|
||||||
@ -77,9 +79,11 @@ public class SkyboxWizardPanel2 implements WizardDescriptor.Panel {
|
|||||||
// and uncomment the complicated stuff below.
|
// and uncomment the complicated stuff below.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final void addChangeListener(ChangeListener l) {
|
public final void addChangeListener(ChangeListener l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public final void removeChangeListener(ChangeListener l) {
|
public final void removeChangeListener(ChangeListener l) {
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -106,13 +110,55 @@ public class SkyboxWizardPanel2 implements WizardDescriptor.Panel {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validate() throws WizardValidationException {
|
||||||
|
SkyboxVisualPanel2 sky = (SkyboxVisualPanel2)component;
|
||||||
|
|
||||||
|
/* Check if there are empty textures */
|
||||||
|
if (multipleTextures) {
|
||||||
|
if (sky.getEditorNorth().getAsText() == null) { throw new WizardValidationException(null, " Texture North: Missing texture!", null); }
|
||||||
|
if (sky.getEditorSouth().getAsText() == null) { throw new WizardValidationException(null, " Texture South: Missing texture!", null); }
|
||||||
|
if (sky.getEditorWest().getAsText() == null) { throw new WizardValidationException(null, " Texture West: Missing texture!", null); }
|
||||||
|
if (sky.getEditorEast().getAsText() == null) { throw new WizardValidationException(null, " Texture East: Missing texture!", null); }
|
||||||
|
if (sky.getEditorTop().getAsText() == null) { throw new WizardValidationException(null, " Texture Top: Missing texture!", null); }
|
||||||
|
if (sky.getEditorBottom().getAsText() == null) { throw new WizardValidationException(null, " Texture Bottom: Missing texture!", null); }
|
||||||
|
|
||||||
|
/* Prevent Null-Pointer Exception. If this is triggered, the Texture has no Image or the AssetKey is invalid (which should never happen) */
|
||||||
|
if (sky.getEditorNorth().getValue() == null || ((Texture)sky.getEditorNorth().getValue()).getImage() == null) { throw new WizardValidationException(null, " Texture North: Cannot load texture!", null); }
|
||||||
|
if (sky.getEditorSouth().getValue() == null || ((Texture)sky.getEditorSouth().getValue()).getImage() == null) { throw new WizardValidationException(null, " Texture South: Cannot load texture!", null); }
|
||||||
|
if (sky.getEditorWest().getValue() == null || ((Texture)sky.getEditorWest().getValue()).getImage() == null) { throw new WizardValidationException(null, " Texture West: Cannot load texture!", null); }
|
||||||
|
if (sky.getEditorEast().getValue() == null || ((Texture)sky.getEditorEast().getValue()).getImage() == null) { throw new WizardValidationException(null, " Texture East: Cannot load texture!", null); }
|
||||||
|
if (sky.getEditorTop().getValue() == null || ((Texture)sky.getEditorTop().getValue()).getImage() == null) { throw new WizardValidationException(null, " Texture Top: Cannot load texture!", null); }
|
||||||
|
if (sky.getEditorBottom().getValue() == null || ((Texture)sky.getEditorBottom().getValue()).getImage() == null) { throw new WizardValidationException(null, " Texture Bottom: Cannot load texture!", null); }
|
||||||
|
|
||||||
|
/* Check for squares */
|
||||||
|
Image I = ((Texture)sky.getEditorNorth().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Texture North: Image has to be a square (width == height)!", null); }
|
||||||
|
I = ((Texture)sky.getEditorSouth().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Texture South: Image has to be a square (width == height)!", null); }
|
||||||
|
I = ((Texture)sky.getEditorWest().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Texture West: Image has to be a square (width == height)!", null); }
|
||||||
|
I = ((Texture)sky.getEditorEast().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Texture East: Image has to be a square (width == height)!", null); }
|
||||||
|
I = ((Texture)sky.getEditorTop().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Texture Top: Image has to be a square (width == height)!", null); }
|
||||||
|
I = ((Texture)sky.getEditorBottom().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Texture Bottom: Image has to be a square (width == height)!", null); }
|
||||||
|
} else {
|
||||||
|
if (sky.getEditorSingle().getAsText() == null){ throw new WizardValidationException(null, " Single Texture: Missing texture!", null); }
|
||||||
|
if (sky.getEditorSingle().getValue() == null || ((Texture)sky.getEditorSingle().getValue()).getImage() == null){ throw new WizardValidationException(null, " Single Texture: Cannot load texture!", null); }
|
||||||
|
Image I = ((Texture)sky.getEditorSingle().getValue()).getImage();
|
||||||
|
if (I.getWidth() != I.getHeight()) { throw new WizardValidationException(null, " Single Texture: Image has to be a square (width == height)!", null); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// You can use a settings object to keep track of state. Normally the
|
// You can use a settings object to keep track of state. Normally the
|
||||||
// settings object will be the WizardDescriptor, so you can use
|
// settings object will be the WizardDescriptor, so you can use
|
||||||
// WizardDescriptor.getProperty & putProperty to store information entered
|
// WizardDescriptor.getProperty & putProperty to store information entered
|
||||||
// by the user.
|
// by the user.
|
||||||
public void readSettings(Object settings) {
|
@Override
|
||||||
WizardDescriptor wiz = (WizardDescriptor) settings;
|
public void readSettings(WizardDescriptor settings) {
|
||||||
multipleTextures = (Boolean)wiz.getProperty("multipleTextures");
|
multipleTextures = (Boolean)settings.getProperty("multipleTextures");
|
||||||
SkyboxVisualPanel2 comp = (SkyboxVisualPanel2) getComponent();
|
SkyboxVisualPanel2 comp = (SkyboxVisualPanel2) getComponent();
|
||||||
if (multipleTextures) {
|
if (multipleTextures) {
|
||||||
comp.getMultipleTexturePanel().setVisible(true);
|
comp.getMultipleTexturePanel().setVisible(true);
|
||||||
@ -124,28 +170,27 @@ public class SkyboxWizardPanel2 implements WizardDescriptor.Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void storeSettings(Object settings) {
|
public void storeSettings(WizardDescriptor settings) {
|
||||||
WizardDescriptor wiz = (WizardDescriptor) settings;
|
|
||||||
SkyboxVisualPanel2 comp = (SkyboxVisualPanel2) getComponent();
|
SkyboxVisualPanel2 comp = (SkyboxVisualPanel2) getComponent();
|
||||||
if (multipleTextures) {
|
if (multipleTextures) {
|
||||||
wiz.putProperty("textureSouth", (Texture)comp.getEditorSouth().getValue());
|
settings.putProperty("textureSouth", (Texture)comp.getEditorSouth().getValue());
|
||||||
wiz.putProperty("textureNorth", (Texture)comp.getEditorNorth().getValue());
|
settings.putProperty("textureNorth", (Texture)comp.getEditorNorth().getValue());
|
||||||
wiz.putProperty("textureEast", (Texture)comp.getEditorEast().getValue());
|
settings.putProperty("textureEast", (Texture)comp.getEditorEast().getValue());
|
||||||
wiz.putProperty("textureWest", (Texture)comp.getEditorWest().getValue());
|
settings.putProperty("textureWest", (Texture)comp.getEditorWest().getValue());
|
||||||
wiz.putProperty("textureTop", (Texture)comp.getEditorTop().getValue());
|
settings.putProperty("textureTop", (Texture)comp.getEditorTop().getValue());
|
||||||
wiz.putProperty("textureBottom", (Texture)comp.getEditorBottom().getValue());
|
settings.putProperty("textureBottom", (Texture)comp.getEditorBottom().getValue());
|
||||||
float x = new Float(comp.getNormal1X().getText());
|
float x = new Float(comp.getNormal1X().getText());
|
||||||
float y = new Float(comp.getNormal1Y().getText());
|
float y = new Float(comp.getNormal1Y().getText());
|
||||||
float z = new Float(comp.getNormal1Z().getText());
|
float z = new Float(comp.getNormal1Z().getText());
|
||||||
wiz.putProperty("normalScale", new Vector3f(x,y,z) );
|
settings.putProperty("normalScale", new Vector3f(x,y,z) );
|
||||||
} else {
|
} else {
|
||||||
wiz.putProperty("textureSingle", (Texture)comp.getEditorSingle().getValue());
|
settings.putProperty("textureSingle", (Texture)comp.getEditorSingle().getValue());
|
||||||
float x = new Float(comp.getNormal2X().getText());
|
float x = new Float(comp.getNormal2X().getText());
|
||||||
float y = new Float(comp.getNormal2Y().getText());
|
float y = new Float(comp.getNormal2Y().getText());
|
||||||
float z = new Float(comp.getNormal2Z().getText());
|
float z = new Float(comp.getNormal2Z().getText());
|
||||||
wiz.putProperty("normalScale", new Vector3f(x,y,z) );
|
settings.putProperty("normalScale", new Vector3f(x,y,z) );
|
||||||
wiz.putProperty("envMapType", comp.getEnvMapType());
|
settings.putProperty("envMapType", comp.getEnvMapType());
|
||||||
wiz.putProperty("flipY", comp.getFlipYCheckBox().isSelected());
|
settings.putProperty("flipY", comp.getFlipYCheckBox().isSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user