diff --git a/.gitignore b/.gitignore index aa848af79..dc6d9aec8 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ !/jme3-vr/src/main/resources/**/*.so.dbg !/jme3-vr/src/main/resources/**/*.dll !/jme3-vr/src/main/resources/**/*.pdb +/buildMaven.bat diff --git a/jme3-core/src/main/java/com/jme3/material/Material.java b/jme3-core/src/main/java/com/jme3/material/Material.java index 72a85f760..a14bc357d 100644 --- a/jme3-core/src/main/java/com/jme3/material/Material.java +++ b/jme3-core/src/main/java/com/jme3/material/Material.java @@ -529,24 +529,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { checkSetParam(type, name); MatParamTexture val = getTextureParam(name); if (val == null) { - MatParamTexture paramDef = (MatParamTexture) def.getMaterialParam(name); - if (paramDef.getColorSpace() != null && paramDef.getColorSpace() != value.getImage().getColorSpace()) { - value.getImage().setColorSpace(paramDef.getColorSpace()); - logger.log(Level.FINE, "Material parameter {0} needs a {1} texture, " - + "texture {2} was switched to {3} color space.", - new Object[]{name, paramDef.getColorSpace().toString(), - value.getName(), - value.getImage().getColorSpace().name()}); - } else if (paramDef.getColorSpace() == null && value.getName() != null && value.getImage().getColorSpace() == ColorSpace.Linear) { - logger.log(Level.WARNING, - "The texture {0} has linear color space, but the material " - + "parameter {2} specifies no color space requirement, this may " - + "lead to unexpected behavior.\nCheck if the image " - + "was not set to another material parameter with a linear " - + "color space, or that you did not set the ColorSpace to " - + "Linear using texture.getImage.setColorSpace().", - new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); - } + checkTextureParamColorSpace(name, value); paramValues.put(name, new MatParamTexture(type, name, value, null)); } else { val.setTextureValue(value); @@ -560,6 +543,27 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { sortingId = -1; } + private void checkTextureParamColorSpace(String name, Texture value) { + MatParamTexture paramDef = (MatParamTexture) def.getMaterialParam(name); + if (paramDef.getColorSpace() != null && paramDef.getColorSpace() != value.getImage().getColorSpace()) { + value.getImage().setColorSpace(paramDef.getColorSpace()); + logger.log(Level.FINE, "Material parameter {0} needs a {1} texture, " + + "texture {2} was switched to {3} color space.", + new Object[]{name, paramDef.getColorSpace().toString(), + value.getName(), + value.getImage().getColorSpace().name()}); + } else if (paramDef.getColorSpace() == null && value.getName() != null && value.getImage().getColorSpace() == ColorSpace.Linear) { + logger.log(Level.WARNING, + "The texture {0} has linear color space, but the material " + + "parameter {2} specifies no color space requirement, this may " + + "lead to unexpected behavior.\nCheck if the image " + + "was not set to another material parameter with a linear " + + "color space, or that you did not set the ColorSpace to " + + "Linear using texture.getImage.setColorSpace().", + new Object[]{value.getName(), value.getImage().getColorSpace().name(), name}); + } + } + /** * Pass a texture to the material shader. * @@ -1062,6 +1066,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { if (texVal.getTextureValue() == null || texVal.getTextureValue().getImage() == null) { continue; } + checkTextureParamColorSpace(texVal.getName(), texVal.getTextureValue()); } if (im.getFormatVersion() == 0 && param.getName().startsWith("m_")) { diff --git a/jme3-core/src/main/java/com/jme3/scene/Geometry.java b/jme3-core/src/main/java/com/jme3/scene/Geometry.java index fe65adf74..1e1bbcf50 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Geometry.java +++ b/jme3-core/src/main/java/com/jme3/scene/Geometry.java @@ -506,6 +506,7 @@ public class Geometry extends Spatial { /** * The old clone() method that did not use the new Cloner utility. */ + @Override public Geometry oldClone(boolean cloneMaterial) { Geometry geomClone = (Geometry) super.clone(cloneMaterial); diff --git a/jme3-core/src/main/java/com/jme3/scene/Mesh.java b/jme3-core/src/main/java/com/jme3/scene/Mesh.java index 68b153633..f115f8121 100644 --- a/jme3-core/src/main/java/com/jme3/scene/Mesh.java +++ b/jme3-core/src/main/java/com/jme3/scene/Mesh.java @@ -63,8 +63,7 @@ import java.util.ArrayList; * All visible elements in a scene are represented by meshes. * Meshes may contain three types of geometric primitives: *
gl_PointSize
output.
*/
Points(true),
diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java
index f6b657842..eac48db4e 100644
--- a/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java
+++ b/jme3-core/src/main/java/com/jme3/scene/control/LodControl.java
@@ -121,17 +121,23 @@ public class LodControl extends AbstractControl implements Cloneable, JmeCloneab
@Override
public void setSpatial(Spatial spatial) {
- if (!(spatial instanceof Geometry)) {
+ if (spatial != null && !(spatial instanceof Geometry)) {
throw new IllegalArgumentException("LodControl can only be attached to Geometry!");
}
super.setSpatial(spatial);
- Geometry geom = (Geometry) spatial;
- Mesh mesh = geom.getMesh();
- numLevels = mesh.getNumLodLevels();
- numTris = new int[numLevels];
- for (int i = numLevels - 1; i >= 0; i--) {
- numTris[i] = mesh.getTriangleCount(i);
+
+ if(spatial != null) {
+ Geometry geom = (Geometry) spatial;
+ Mesh mesh = geom.getMesh();
+ numLevels = mesh.getNumLodLevels();
+ numTris = new int[numLevels];
+ for (int i = numLevels - 1; i >= 0; i--) {
+ numTris[i] = mesh.getTriangleCount(i);
+ }
+ } else {
+ numLevels = 0;
+ numTris = null;
}
}
diff --git a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonDebugger.java b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonDebugger.java
index b633ab5b8..f764304c7 100644
--- a/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonDebugger.java
+++ b/jme3-core/src/main/java/com/jme3/scene/debug/SkeletonDebugger.java
@@ -31,12 +31,13 @@
*/
package com.jme3.scene.debug;
-import java.util.Map;
-
import com.jme3.animation.Skeleton;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
+import com.jme3.util.clone.Cloner;
+
+import java.util.Map;
/**
* The class that creates a mesh to display how bones behave.
@@ -122,4 +123,13 @@ public class SkeletonDebugger extends Node {
public SkeletonInterBoneWire getInterBoneWires() {
return interBoneWires;
}
+
+ @Override
+ public void cloneFields(Cloner cloner, Object original) {
+ super.cloneFields(cloner, original);
+
+ this.wires = cloner.clone(wires);
+ this.points = cloner.clone(points);
+ this.interBoneWires = cloner.clone(interBoneWires);
+ }
}
\ No newline at end of file
diff --git a/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java b/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java
index 1e0b1cae2..97dd70f30 100644
--- a/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java
+++ b/jme3-core/src/main/java/com/jme3/scene/shape/Cylinder.java
@@ -40,11 +40,8 @@ import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
-import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.util.BufferUtils;
-import static com.jme3.util.BufferUtils.*;
import java.io.IOException;
-import java.nio.FloatBuffer;
/**
* A simple cylinder, defined by it's height and radius.
@@ -127,10 +124,10 @@ public class Cylinder extends Mesh {
* mapped to texture coordinates (0.5, 1), bottom to (0.5, 0). Thus you need
* a suited distorted texture.
*
- * @param axisSamples
- * Number of triangle samples along the axis.
- * @param radialSamples
- * Number of triangle samples along the radial.
+ * @param axisSamples The number of vertices samples along the axis. It is equal to the number of segments + 1; so
+ * that, for instance, 4 samples mean the cylinder will be made of 3 segments.
+ * @param radialSamples The number of triangle samples along the radius. For instance, 4 means that the sides of the
+ * cylinder are made of 4 rectangles, and the top and bottom are made of 4 triangles.
* @param radius
* The radius of the cylinder.
* @param height
@@ -201,194 +198,225 @@ public class Cylinder extends Mesh {
/**
* Rebuilds the cylinder based on a new set of parameters.
*
- * @param axisSamples the number of samples along the axis.
- * @param radialSamples the number of samples around the radial.
- * @param radius the radius of the bottom of the cylinder.
- * @param radius2 the radius of the top of the cylinder.
+ * @param axisSamples The number of vertices samples along the axis. It is equal to the number of segments + 1; so
+ * that, for instance, 4 samples mean the cylinder will be made of 3 segments.
+ * @param radialSamples The number of triangle samples along the radius. For instance, 4 means that the sides of the
+ * cylinder are made of 4 rectangles, and the top and bottom are made of 4 triangles.
+ * @param topRadius the radius of the top of the cylinder.
+ * @param bottomRadius the radius of the bottom of the cylinder.
* @param height the cylinder's height.
* @param closed should the cylinder have top and bottom surfaces.
* @param inverted is the cylinder is meant to be viewed from the inside.
*/
public void updateGeometry(int axisSamples, int radialSamples,
- float radius, float radius2, float height, boolean closed, boolean inverted) {
+ float topRadius, float bottomRadius, float height, boolean closed, boolean inverted) {
+ // Ensure there's at least two axis samples and 3 radial samples, and positive dimensions.
+ if( axisSamples < 2
+ || radialSamples < 3
+ || topRadius <= 0
+ || bottomRadius <= 0
+ || height <= 0 ) {
+ throw new IllegalArgumentException("Cylinders must have at least 2 axis samples and 3 radial samples, and positive dimensions.");
+ }
+
this.axisSamples = axisSamples;
this.radialSamples = radialSamples;
- this.radius = radius;
- this.radius2 = radius2;
+ this.radius = bottomRadius;
+ this.radius2 = topRadius;
this.height = height;
this.closed = closed;
this.inverted = inverted;
-// VertexBuffer pvb = getBuffer(Type.Position);
-// VertexBuffer nvb = getBuffer(Type.Normal);
-// VertexBuffer tvb = getBuffer(Type.TexCoord);
- axisSamples += (closed ? 2 : 0);
-
- // Vertices
- int vertCount = axisSamples * (radialSamples + 1) + (closed ? 2 : 0);
-
- setBuffer(Type.Position, 3, createVector3Buffer(getFloatBuffer(Type.Position), vertCount));
-
- // Normals
- setBuffer(Type.Normal, 3, createVector3Buffer(getFloatBuffer(Type.Normal), vertCount));
-
- // Texture co-ordinates
- setBuffer(Type.TexCoord, 2, createVector2Buffer(vertCount));
+ // Vertices : One per radial sample plus one duplicate for texture closing around the sides.
+ int verticesCount = axisSamples * (radialSamples +1);
+ // Triangles: Two per side rectangle, which is the product of numbers of samples.
+ int trianglesCount = axisSamples * radialSamples * 2 ;
+ if( closed ) {
+ // If there are caps, add two additional rims and two summits.
+ verticesCount += 2 + 2 * (radialSamples +1);
+ // Add one triangle per radial sample, twice, to form the caps.
+ trianglesCount += 2 * radialSamples ;
+ }
- int triCount = ((closed ? 2 : 0) + 2 * (axisSamples - 1)) * radialSamples;
+ // Compute the points along a unit circle:
+ float[][] circlePoints = new float[radialSamples+1][2];
+ for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++) {
+ float angle = FastMath.TWO_PI / radialSamples * circlePoint;
+ circlePoints[circlePoint][0] = FastMath.cos(angle);
+ circlePoints[circlePoint][1] = FastMath.sin(angle);
+ }
+ // Add an additional point for closing the texture around the side of the cylinder.
+ circlePoints[radialSamples][0] = circlePoints[0][0];
+ circlePoints[radialSamples][1] = circlePoints[0][1];
- setBuffer(Type.Index, 3, createShortBuffer(getShortBuffer(Type.Index), 3 * triCount));
-
- // generate geometry
- float inverseRadial = 1.0f / radialSamples;
- float inverseAxisLess = 1.0f / (closed ? axisSamples - 3 : axisSamples - 1);
- float inverseAxisLessTexture = 1.0f / (axisSamples - 1);
- float halfHeight = 0.5f * height;
-
- // Generate points on the unit circle to be used in computing the mesh
- // points on a cylinder slice.
- float[] sin = new float[radialSamples + 1];
- float[] cos = new float[radialSamples + 1];
-
- for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
- float angle = FastMath.TWO_PI * inverseRadial * radialCount;
- cos[radialCount] = FastMath.cos(angle);
- sin[radialCount] = FastMath.sin(angle);
+ // Calculate normals.
+ //
+ // A---------B
+ // \ |
+ // \ |
+ // \ |
+ // D-----C
+ //
+ // Let be B and C the top and bottom points of the axis, and A and D the top and bottom edges.
+ // The normal in A and D is simply orthogonal to AD, which means we can get it once per sample.
+ //
+ Vector3f[] circleNormals = new Vector3f[radialSamples+1];
+ for (int circlePoint = 0; circlePoint < radialSamples+1; circlePoint++) {
+ // The normal is the orthogonal to the side, which can be got without trigonometry.
+ // The edge direction is oriented so that it goes up by Height, and out by the radius difference; let's use
+ // those values in reverse order.
+ Vector3f normal = new Vector3f(height * circlePoints[circlePoint][0], height * circlePoints[circlePoint][1], bottomRadius - topRadius );
+ circleNormals[circlePoint] = normal.normalizeLocal();
}
- sin[radialSamples] = sin[0];
- cos[radialSamples] = cos[0];
-
- // calculate normals
- Vector3f[] vNormals = null;
- Vector3f vNormal = Vector3f.UNIT_Z;
-
- if ((height != 0.0f) && (radius != radius2)) {
- vNormals = new Vector3f[radialSamples];
- Vector3f vHeight = Vector3f.UNIT_Z.mult(height);
- Vector3f vRadial = new Vector3f();
-
- for (int radialCount = 0; radialCount < radialSamples; radialCount++) {
- vRadial.set(cos[radialCount], sin[radialCount], 0.0f);
- Vector3f vRadius = vRadial.mult(radius);
- Vector3f vRadius2 = vRadial.mult(radius2);
- Vector3f vMantle = vHeight.subtract(vRadius2.subtract(vRadius));
- Vector3f vTangent = vRadial.cross(Vector3f.UNIT_Z);
- vNormals[radialCount] = vMantle.cross(vTangent).normalize();
+
+ float[] vertices = new float[verticesCount * 3];
+ float[] normals = new float[verticesCount * 3];
+ float[] textureCoords = new float[verticesCount * 2];
+ int currentIndex = 0;
+
+ // Add a circle of points for each axis sample.
+ for(int axisSample = 0; axisSample < axisSamples; axisSample++ ) {
+ float currentHeight = -height / 2 + height * axisSample / (axisSamples-1);
+ float currentRadius = bottomRadius + (topRadius - bottomRadius) * axisSample / (axisSamples-1);
+
+ for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++) {
+ // Position, by multipliying the position on a unit circle with the current radius.
+ vertices[currentIndex*3] = circlePoints[circlePoint][0] * currentRadius;
+ vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * currentRadius;
+ vertices[currentIndex*3 +2] = currentHeight;
+
+ // Normal
+ Vector3f currentNormal = circleNormals[circlePoint];
+ normals[currentIndex*3] = currentNormal.x;
+ normals[currentIndex*3+1] = currentNormal.y;
+ normals[currentIndex*3+2] = currentNormal.z;
+
+ // Texture
+ // The X is the angular position of the point.
+ textureCoords[currentIndex *2] = (float) circlePoint / radialSamples;
+ // Depending on whether there is a cap, the Y is either the height scaled to [0,1], or the radii of
+ // the cap count as well.
+ if (closed)
+ textureCoords[currentIndex *2 +1] = (bottomRadius + height / 2 + currentHeight) / (bottomRadius + height + topRadius);
+ else
+ textureCoords[currentIndex *2 +1] = height / 2 + currentHeight;
+
+ currentIndex++;
}
}
+
+ // If closed, add duplicate rims on top and bottom, with normals facing up and down.
+ if (closed) {
+ // Bottom
+ for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++) {
+ vertices[currentIndex*3] = circlePoints[circlePoint][0] * bottomRadius;
+ vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * bottomRadius;
+ vertices[currentIndex*3 +2] = -height/2;
- FloatBuffer nb = getFloatBuffer(Type.Normal);
- FloatBuffer pb = getFloatBuffer(Type.Position);
- FloatBuffer tb = getFloatBuffer(Type.TexCoord);
-
- // generate the cylinder itself
- Vector3f tempNormal = new Vector3f();
- for (int axisCount = 0, i = 0; axisCount < axisSamples; axisCount++, i++) {
- float axisFraction;
- float axisFractionTexture;
- int topBottom = 0;
- if (!closed) {
- axisFraction = axisCount * inverseAxisLess; // in [0,1]
- axisFractionTexture = axisFraction;
- } else {
- if (axisCount == 0) {
- topBottom = -1; // bottom
- axisFraction = 0;
- axisFractionTexture = inverseAxisLessTexture;
- } else if (axisCount == axisSamples - 1) {
- topBottom = 1; // top
- axisFraction = 1;
- axisFractionTexture = 1 - inverseAxisLessTexture;
- } else {
- axisFraction = (axisCount - 1) * inverseAxisLess;
- axisFractionTexture = axisCount * inverseAxisLessTexture;
- }
- }
+ normals[currentIndex*3] = 0;
+ normals[currentIndex*3+1] = 0;
+ normals[currentIndex*3+2] = -1;
- // compute center of slice
- float z = -halfHeight + height * axisFraction;
- Vector3f sliceCenter = new Vector3f(0, 0, z);
-
- // compute slice vertices with duplication at end point
- int save = i;
- for (int radialCount = 0; radialCount < radialSamples; radialCount++, i++) {
- float radialFraction = radialCount * inverseRadial; // in [0,1)
- tempNormal.set(cos[radialCount], sin[radialCount], 0.0f);
-
- if (vNormals != null) {
- vNormal = vNormals[radialCount];
- } else if (radius == radius2) {
- vNormal = tempNormal;
- }
-
- if (topBottom == 0) {
- if (!inverted)
- nb.put(vNormal.x).put(vNormal.y).put(vNormal.z);
- else
- nb.put(-vNormal.x).put(-vNormal.y).put(-vNormal.z);
- } else {
- nb.put(0).put(0).put(topBottom * (inverted ? -1 : 1));
- }
-
- tempNormal.multLocal((radius - radius2) * axisFraction + radius2)
- .addLocal(sliceCenter);
- pb.put(tempNormal.x).put(tempNormal.y).put(tempNormal.z);
-
- tb.put((inverted ? 1 - radialFraction : radialFraction))
- .put(axisFractionTexture);
+ textureCoords[currentIndex *2] = (float) circlePoint / radialSamples;
+ textureCoords[currentIndex *2 +1] = bottomRadius / (bottomRadius + height + topRadius);
+
+ currentIndex++;
}
+ // Top
+ for (int circlePoint = 0; circlePoint < radialSamples + 1; circlePoint++) {
+ vertices[currentIndex*3] = circlePoints[circlePoint][0] * topRadius;
+ vertices[currentIndex*3 +1] = circlePoints[circlePoint][1] * topRadius;
+ vertices[currentIndex*3 +2] = height/2;
- BufferUtils.copyInternalVector3(pb, save, i);
- BufferUtils.copyInternalVector3(nb, save, i);
+ normals[currentIndex*3] = 0;
+ normals[currentIndex*3+1] = 0;
+ normals[currentIndex*3+2] = 1;
- tb.put((inverted ? 0.0f : 1.0f))
- .put(axisFractionTexture);
- }
+ textureCoords[currentIndex *2] = (float) circlePoint / radialSamples;
+ textureCoords[currentIndex *2 +1] = (bottomRadius + height) / (bottomRadius + height + topRadius);
- if (closed) {
- pb.put(0).put(0).put(-halfHeight); // bottom center
- nb.put(0).put(0).put(-1 * (inverted ? -1 : 1));
- tb.put(0.5f).put(0);
- pb.put(0).put(0).put(halfHeight); // top center
- nb.put(0).put(0).put(1 * (inverted ? -1 : 1));
- tb.put(0.5f).put(1);
+ currentIndex++;
+ }
+
+ // Add the centers of the caps.
+ vertices[currentIndex*3] = 0;
+ vertices[currentIndex*3 +1] = 0;
+ vertices[currentIndex*3 +2] = -height/2;
+
+ normals[currentIndex*3] = 0;
+ normals[currentIndex*3+1] = 0;
+ normals[currentIndex*3+2] = -1;
+
+ textureCoords[currentIndex *2] = 0.5f;
+ textureCoords[currentIndex *2+1] = 0f;
+
+ currentIndex++;
+
+ vertices[currentIndex*3] = 0;
+ vertices[currentIndex*3 +1] = 0;
+ vertices[currentIndex*3 +2] = height/2;
+
+ normals[currentIndex*3] = 0;
+ normals[currentIndex*3+1] = 0;
+ normals[currentIndex*3+2] = 1;
+
+ textureCoords[currentIndex *2] = 0.5f;
+ textureCoords[currentIndex *2+1] = 1f;
}
- IndexBuffer ib = getIndexBuffer();
- int index = 0;
- // Connectivity
- for (int axisCount = 0, axisStart = 0; axisCount < axisSamples - 1; axisCount++) {
- int i0 = axisStart;
- int i1 = i0 + 1;
- axisStart += radialSamples + 1;
- int i2 = axisStart;
- int i3 = i2 + 1;
- for (int i = 0; i < radialSamples; i++) {
- if (closed && axisCount == 0) {
- if (!inverted) {
- ib.put(index++, i0++);
- ib.put(index++, vertCount - 2);
- ib.put(index++, i1++);
- } else {
- ib.put(index++, i0++);
- ib.put(index++, i1++);
- ib.put(index++, vertCount - 2);
- }
- } else if (closed && axisCount == axisSamples - 2) {
- ib.put(index++, i2++);
- ib.put(index++, inverted ? vertCount - 1 : i3++);
- ib.put(index++, inverted ? i3++ : vertCount - 1);
- } else {
- ib.put(index++, i0++);
- ib.put(index++, inverted ? i2 : i1);
- ib.put(index++, inverted ? i1 : i2);
- ib.put(index++, i1++);
- ib.put(index++, inverted ? i2++ : i3++);
- ib.put(index++, inverted ? i3++ : i2++);
- }
+ // Add the triangles indexes.
+ short[] indices = new short[trianglesCount * 3];
+ currentIndex = 0;
+ for (short axisSample = 0; axisSample < axisSamples - 1; axisSample++) {
+ for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++) {
+ indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint);
+ indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint + 1);
+ indices[currentIndex++] = (short) ((axisSample + 1) * (radialSamples + 1) + circlePoint);
+
+ indices[currentIndex++] = (short) ((axisSample + 1) * (radialSamples + 1) + circlePoint);
+ indices[currentIndex++] = (short) (axisSample * (radialSamples + 1) + circlePoint + 1);
+ indices[currentIndex++] = (short) ((axisSample + 1) * (radialSamples + 1) + circlePoint + 1);
+ }
+ }
+ // Add caps if needed.
+ if(closed) {
+ short bottomCapIndex = (short) (verticesCount - 2);
+ short topCapIndex = (short) (verticesCount - 1);
+
+ int bottomRowOffset = (axisSamples) * (radialSamples +1 );
+ int topRowOffset = (axisSamples+1) * (radialSamples +1 );
+
+ for (int circlePoint = 0; circlePoint < radialSamples; circlePoint++) {
+ indices[currentIndex++] = (short) (bottomRowOffset + circlePoint +1);
+ indices[currentIndex++] = (short) (bottomRowOffset + circlePoint);
+ indices[currentIndex++] = bottomCapIndex;
+
+
+ indices[currentIndex++] = (short) (topRowOffset + circlePoint);
+ indices[currentIndex++] = (short) (topRowOffset + circlePoint +1);
+ indices[currentIndex++] = topCapIndex;
}
}
+ // If inverted, the triangles and normals are all reverted.
+ if (inverted) {
+ for (int i = 0; i < indices.length / 2; i++) {
+ short temp = indices[i];
+ indices[i] = indices[indices.length - 1 - i];
+ indices[indices.length - 1 - i] = temp;
+ }
+
+ for(int i = 0; i< normals.length; i++) {
+ normals[i] = -normals[i];
+ }
+ }
+
+ // Fill in the buffers.
+ setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
+ setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(normals));
+ setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(textureCoords));
+ setBuffer(Type.Index, 3, BufferUtils.createShortBuffer(indices));
+
updateBound();
setStatic();
}
@@ -418,6 +446,4 @@ public class Cylinder extends Mesh {
capsule.write(closed, "closed", false);
capsule.write(inverted, "inverted", false);
}
-
-
}
diff --git a/jme3-core/src/main/java/com/jme3/shader/Glsl100ShaderGenerator.java b/jme3-core/src/main/java/com/jme3/shader/Glsl100ShaderGenerator.java
index 9edcd505a..4a85a9197 100644
--- a/jme3-core/src/main/java/com/jme3/shader/Glsl100ShaderGenerator.java
+++ b/jme3-core/src/main/java/com/jme3/shader/Glsl100ShaderGenerator.java
@@ -243,7 +243,7 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
//all variables fed with a matparam or world param are replaced but the matparam itself
//it avoids issue with samplers that have to be uniforms, and it optimize a but the shader code.
if (isWorldOrMaterialParam(mapping.getRightVariable())) {
- nodeSource = replace(nodeSource, mapping.getLeftVariable(), mapping.getRightVariable().getName());
+ nodeSource = replace(nodeSource, mapping.getLeftVariable(), mapping.getRightVariable().getPrefix() + mapping.getRightVariable().getName());
} else {
if (mapping.getLeftVariable().getType().startsWith("sampler")) {
throw new IllegalArgumentException("a Sampler must be a uniform");
@@ -338,6 +338,7 @@ public class Glsl100ShaderGenerator extends ShaderGenerator {
source.append(var.getNameSpace());
source.append("_");
}
+ source.append(var.getPrefix());
source.append(var.getName());
if (var.getMultiplicity() != null) {
source.append("[");
diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderNodeVariable.java b/jme3-core/src/main/java/com/jme3/shader/ShaderNodeVariable.java
index 22811de6f..a1363ead1 100644
--- a/jme3-core/src/main/java/com/jme3/shader/ShaderNodeVariable.java
+++ b/jme3-core/src/main/java/com/jme3/shader/ShaderNodeVariable.java
@@ -45,6 +45,7 @@ import java.io.IOException;
*/
public class ShaderNodeVariable implements Savable, Cloneable {
+ private String prefix = "";
private String name;
private String type;
private String nameSpace;
@@ -62,8 +63,7 @@ public class ShaderNodeVariable implements Savable, Cloneable {
this.name = name;
this.type = type;
}
-
-
+
/**
* creates a ShaderNodeVariable
*
@@ -80,6 +80,22 @@ public class ShaderNodeVariable implements Savable, Cloneable {
this.multiplicity = multiplicity;
}
+
+ /**
+ * creates a ShaderNodeVariable
+ *
+ * @param type the glsl type of the variable
+ * @param nameSpace the nameSpace (can be the name of the shaderNode or
+ * Global,Attr,MatParam,WorldParam)
+ * @param name the name of the variable
+ * @param multiplicity the number of element if this variable is an array. Can be an Int of a declared material parameter
+ * @param prefix the variable prefix to append at generation times. This is mostly to add the g_ and m_ for uniforms
+ */
+ public ShaderNodeVariable(String type, String nameSpace, String name, String multiplicity, String prefix) {
+ this(type, nameSpace, name, multiplicity);
+ this.prefix = prefix;
+ }
+
/**
* creates a ShaderNodeVariable
*
@@ -138,6 +154,22 @@ public class ShaderNodeVariable implements Savable, Cloneable {
return nameSpace;
}
+ /**
+ * @return the variable prefix
+ */
+ public String getPrefix() {
+ return prefix;
+ }
+
+ /**
+ * Sets the variable prefix (m_ or g_)
+ *
+ * @param prefix
+ */
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
/**
* sets the nameSpace (can be the name of the shaderNode or
* Global,Attr,MatParam,WorldParam)
@@ -153,6 +185,7 @@ public class ShaderNodeVariable implements Savable, Cloneable {
int hash = 7;
hash = 29 * hash + (name != null?name.hashCode():0);
hash = 29 * hash + (type != null?type.hashCode():0);
+ hash = 29 * hash + (prefix != null ? prefix.hashCode() : 0);
hash = 29 * hash + (nameSpace != null?nameSpace.hashCode():0);
hash = 29 * hash + (condition != null?condition.hashCode():0);
hash = 29 * hash + (multiplicity != null?multiplicity.hashCode():0);
@@ -174,6 +207,9 @@ public class ShaderNodeVariable implements Savable, Cloneable {
if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
return false;
}
+ if ((this.prefix == null) ? (other.prefix != null) : !this.prefix.equals(other.prefix)) {
+ return false;
+ }
if ((this.nameSpace == null) ? (other.nameSpace != null) : !this.nameSpace.equals(other.nameSpace)) {
return false;
}
@@ -197,6 +233,7 @@ public class ShaderNodeVariable implements Savable, Cloneable {
OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);
oc.write(name, "name", "");
oc.write(type, "type", "");
+ oc.write(prefix, "prefix", "");
oc.write(nameSpace, "nameSpace", "");
oc.write(condition, "condition", null);
oc.write(shaderOutput, "shaderOutput", false);
@@ -215,6 +252,7 @@ public class ShaderNodeVariable implements Savable, Cloneable {
InputCapsule ic = (InputCapsule) im.getCapsule(this);
name = ic.readString("name", "");
type = ic.readString("type", "");
+ prefix = ic.readString("pefix", "");
nameSpace = ic.readString("nameSpace", "");
condition = ic.readString("condition", null);
shaderOutput = ic.readBoolean("shaderOutput", false);
diff --git a/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java b/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java
index 9c6fb7c31..6fcdf2eda 100644
--- a/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java
+++ b/jme3-core/src/plugins/java/com/jme3/material/plugins/ShaderNodeLoaderDelegate.java
@@ -193,6 +193,7 @@ public class ShaderNodeLoaderDelegate {
shaderNodeDefinition = new ShaderNodeDefinition();
getNodeDefinitions().put(name, shaderNodeDefinition);
shaderNodeDefinition.setName(name);
+ shaderNodeDefinition.setPath(key.getName());
readShaderNodeDefinition(statement.getContents(), key);
}
@@ -231,40 +232,52 @@ public class ShaderNodeLoaderDelegate {
protected void readShaderNodeDefinition(Listtrue
if the initialization is a success and false
otherwise.
*/
- public static boolean init() {
+ public boolean init(OpenVR api) {
logger.config("Initialize VR bounds...");
if( vrChaperone == null ) {
- vrChaperone = new VR_IVRChaperone_FnTable(JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRChaperone_Version, OpenVR.hmdErrorStore).getPointer());
+ vrChaperone = new VR_IVRChaperone_FnTable(JOpenVRLibrary.VR_GetGenericInterface(JOpenVRLibrary.IVRChaperone_Version, api.hmdErrorStore).getPointer());
if( vrChaperone != null ) {
vrChaperone.setAutoSynch(false);
vrChaperone.read();
@@ -53,7 +53,7 @@ public class VRBounds {
* Get the size of the VR world.
* @return the size of the VR world.
*/
- public static Vector2f getPlaySize() {
+ public Vector2f getPlaySize() {
return playSize;
}
diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/VRTrackedController.java b/jme3-vr/src/main/java/com/jme3/input/vr/VRTrackedController.java
index 5fb2572a0..3ce20e5c0 100644
--- a/jme3-vr/src/main/java/com/jme3/input/vr/VRTrackedController.java
+++ b/jme3-vr/src/main/java/com/jme3/input/vr/VRTrackedController.java
@@ -1,5 +1,9 @@
package com.jme3.input.vr;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+
/**
* TODO
* @author Julien Seinturier - (c) 2016 - JOrigin project - http:/www.jorigin.org
@@ -7,4 +11,40 @@ package com.jme3.input.vr;
*/
public interface VRTrackedController {
+ /**
+ * Get the controller name.
+ * @return the controller name.
+ */
+ public String getControllerName();
+
+ /**
+ * Get the controller manufacturer.
+ * @return the controller manufacturer.
+ */
+ public String getControllerManufacturer();
+
+ /**
+ * Get the position of the tracked device. This value is the translation component of the device {@link #getPose() pose}.
+ * @return the position of the tracked device.
+ * @see #getOrientation()
+ * @see #getPose()
+ */
+ public Vector3f getPosition();
+
+ /**
+ * Get the orientation of the tracked device. This value is the rotation component of the device {@link #getPose() pose}.
+ * @return the orientation of the tracked device.
+ * @see #getPosition()
+ * @see #getPose()
+ */
+ public Quaternion getOrientation();
+
+ /**
+ * Get the pose of the tracked device.
+ * The pose is a 4x4 matrix than combine the {@link #getPosition() position} and the {@link #getOrientation() orientation} of the device.
+ * @return the pose of the tracked device.
+ * @see #getPosition()
+ * @see #getOrientation()
+ */
+ public Matrix4f getPose();
}
diff --git a/jme3-vr/src/main/java/com/jme3/util/AbstractVRViewManager.java b/jme3-vr/src/main/java/com/jme3/util/AbstractVRViewManager.java
index 7a9b5ea56..f4f7e7f91 100644
--- a/jme3-vr/src/main/java/com/jme3/util/AbstractVRViewManager.java
+++ b/jme3-vr/src/main/java/com/jme3/util/AbstractVRViewManager.java
@@ -28,18 +28,20 @@ public abstract class AbstractVRViewManager implements VRViewManager {
protected VREnvironment environment = null;
protected Camera leftCamera;
- protected ViewPort leftViewport;
+ protected ViewPort leftViewPort;
protected FilterPostProcessor leftPostProcessor;
protected Texture2D leftEyeTexture;
protected Texture2D leftEyeDepth;
protected Camera rightCamera;
- protected ViewPort rightViewport;
+ protected ViewPort rightViewPort;
protected FilterPostProcessor rightPostProcessor;
protected Texture2D rightEyeTexture;
protected Texture2D rightEyeDepth;
- private float resMult = 1f;
+ protected ViewPort mirrorViewPort;
+
+ private float resMult = 1f;
private float heightAdjustment;
@@ -54,15 +56,24 @@ public abstract class AbstractVRViewManager implements VRViewManager {
}
@Override
- public ViewPort getLeftViewport() {
- return leftViewport;
+ public ViewPort getLeftViewPort() {
+ return leftViewPort;
}
@Override
- public ViewPort getRightViewport() {
- return rightViewport;
+ public ViewPort getRightViewPort() {
+ return rightViewPort;
}
+ /**
+ * Get the {@link ViewPort view port} attached to the mirror display.
+ * @return the view port attached to the mirror display.
+ */
+ public ViewPort getMirrorViewPort() {
+ return mirrorViewPort;
+ }
+
+
@Override
public Texture2D getLeftTexture(){
return leftEyeTexture;
@@ -124,7 +135,7 @@ public abstract class AbstractVRViewManager implements VRViewManager {
public void moveScreenProcessingToEyes() {
if (environment != null){
- if( getRightViewport() == null ){
+ if( getRightViewPort() == null ){
return;
}
@@ -150,7 +161,7 @@ public abstract class AbstractVRViewManager implements VRViewManager {
public void syncScreenProcessing(ViewPort sourceViewport) {
if (environment != null){
- if( getRightViewport() == null ){
+ if( getRightViewPort() == null ){
return;
}
@@ -163,13 +174,13 @@ public abstract class AbstractVRViewManager implements VRViewManager {
// clear out all filters & processors, to start from scratch
getRightPostProcessor().removeAllFilters();
getLeftPostProcessor().removeAllFilters();
- getLeftViewport().clearProcessors();
- getRightViewport().clearProcessors();
+ getLeftViewPort().clearProcessors();
+ getRightViewPort().clearProcessors();
// if we have no processors to sync, don't add the FilterPostProcessor
if( sourceViewport.getProcessors().isEmpty() ) return;
// add post processors we just made, which are empty
- getLeftViewport().addProcessor(getLeftPostProcessor());
- getRightViewport().addProcessor(getRightPostProcessor());
+ getLeftViewPort().addProcessor(getLeftPostProcessor());
+ getRightViewPort().addProcessor(getRightPostProcessor());
// go through all of the filters in the processors list
// add them to the left viewport processor & clone them to the right
for(SceneProcessor sceneProcessor : sourceViewport.getProcessors()) {
@@ -202,8 +213,8 @@ public abstract class AbstractVRViewManager implements VRViewManager {
VRDirectionalLightShadowRenderer dlsr = (VRDirectionalLightShadowRenderer) sceneProcessor;
VRDirectionalLightShadowRenderer dlsrRight = dlsr.clone();
dlsrRight.setLight(dlsr.getLight());
- getRightViewport().getProcessors().add(0, dlsrRight);
- getLeftViewport().getProcessors().add(0, sceneProcessor);
+ getRightViewPort().getProcessors().add(0, dlsrRight);
+ getLeftViewPort().getProcessors().add(0, sceneProcessor);
}
}
// make sure each has a translucent filter renderer
diff --git a/jme3-vr/src/main/java/com/jme3/util/VRViewManager.java b/jme3-vr/src/main/java/com/jme3/util/VRViewManager.java
index e2c503006..58a6c166e 100644
--- a/jme3-vr/src/main/java/com/jme3/util/VRViewManager.java
+++ b/jme3-vr/src/main/java/com/jme3/util/VRViewManager.java
@@ -42,17 +42,25 @@ public interface VRViewManager {
/**
* Get the {@link ViewPort viewport} attached to the left eye.
* @return the {@link ViewPort viewport} attached to the left eye.
- * @see #getRightViewport()
+ * @see #getRightViewPort()
*/
- public ViewPort getLeftViewport();
+ public ViewPort getLeftViewPort();
/**
* Get the {@link ViewPort viewport} attached to the right eye.
* @return the {@link ViewPort viewport} attached to the right eye.
- * @see #getLeftViewport()
+ * @see #getLeftViewPort()
*/
- public ViewPort getRightViewport();
+ public ViewPort getRightViewPort();
+
+ /**
+ * Get the {@link ViewPort view port} attached to the mirror display.
+ * @return the view port attached to the mirror display.
+ * @see #getLeftViewPort()
+ * @see #getRightViewPort()
+ */
+ public ViewPort getMirrorViewPort();
/**
* Get the texture attached to the left eye.
diff --git a/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOSVR.java b/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOSVR.java
index 9b78396e5..e3d85406e 100644
--- a/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOSVR.java
+++ b/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOSVR.java
@@ -117,18 +117,18 @@ public class VRViewManagerOSVR extends AbstractVRViewManager{
/**
* Get the {@link ViewPort viewport} attached to the left eye.
* @return the {@link ViewPort viewport} attached to the left eye.
- * @see #getRightViewport()
+ * @see #getRightViewPort()
*/
- public ViewPort getLeftViewport() {
+ public ViewPort getLeftViewPort() {
return leftViewport;
}
/**
* Get the {@link ViewPort viewport} attached to the right eye.
* @return the {@link ViewPort viewport} attached to the right eye.
- * @see #getLeftViewport()
+ * @see #getLeftViewPort()
*/
- public ViewPort getRightViewport() {
+ public ViewPort getRightViewPort() {
return rightViewport;
}
diff --git a/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOpenVR.java b/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOpenVR.java
index 49d08578b..545754a59 100644
--- a/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOpenVR.java
+++ b/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOpenVR.java
@@ -7,6 +7,7 @@ package com.jme3.util;
import com.jme3.app.VREnvironment;
import com.jme3.input.vr.OpenVR;
import com.jme3.input.vr.VRAPI;
+import com.jme3.input.vr.VRTrackedController;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
@@ -346,10 +347,10 @@ public class VRViewManagerOpenVR extends AbstractVRViewManager {
return;
}
- leftEyeTexture = (Texture2D) getLeftViewport().getOutputFrameBuffer().getColorBuffer().getTexture();
- rightEyeTexture = (Texture2D)getRightViewport().getOutputFrameBuffer().getColorBuffer().getTexture();
- leftEyeDepth = (Texture2D) getLeftViewport().getOutputFrameBuffer().getDepthBuffer().getTexture();
- rightEyeDepth = (Texture2D)getRightViewport().getOutputFrameBuffer().getDepthBuffer().getTexture();
+ leftEyeTexture = (Texture2D) getLeftViewPort().getOutputFrameBuffer().getColorBuffer().getTexture();
+ rightEyeTexture = (Texture2D)getRightViewPort().getOutputFrameBuffer().getColorBuffer().getTexture();
+ leftEyeDepth = (Texture2D) getLeftViewPort().getOutputFrameBuffer().getDepthBuffer().getTexture();
+ rightEyeDepth = (Texture2D)getRightViewPort().getOutputFrameBuffer().getDepthBuffer().getTexture();
// main viewport is either going to be a distortion scene or nothing
// mirroring is handled by copying framebuffers
@@ -387,6 +388,7 @@ public class VRViewManagerOpenVR extends AbstractVRViewManager {
if( environment.getApplication().getContext().getSettings().isSwapBuffers() ) {
setupMirrorBuffers(environment.getCamera(), leftEyeTexture, false);
+
}
} else {
throw new IllegalStateException("This VR environment is not attached to any application.");
@@ -414,9 +416,35 @@ public class VRViewManagerOpenVR extends AbstractVRViewManager {
// grab the hardware handle
VRAPI dev = environment.getVRHardware();
if( dev != null ) {
+
+
// update the HMD's position & orientation
dev.updatePose();
dev.getPositionAndOrientation(hmdPos, hmdRot);
+/*
+ // TOREMOVE
+ Vector3f v = dev.getVRinput().getTrackedController(0).getPosition();
+ Quaternion q = dev.getVRinput().getTrackedController(0).getOrientation();
+ if ((v != null)&&(q != null)){
+ hmdPos.set(v);
+ hmdRot.set(q);
+ }
+
+ logger.severe("HMD controller ");
+ logger.severe(" Position "+hmdPos);
+ logger.severe(" Orientation "+hmdRot);
+
+ VRTrackedController tc = null;
+ for(int i = 0; i < dev.getVRinput().getTrackedControllerCount(); i++){
+ tc = dev.getVRinput().getTrackedController(i);
+ logger.severe("Tracked controller "+i+": "+tc.getControllerName());
+ logger.severe(" Position "+tc.getPosition());
+ logger.severe(" Orientation "+tc.getOrientation());
+ logger.severe("");
+ }
+*/
+ // TOREMOVE
+
if( obs != null ) {
// update hmdPos based on obs rotation
finalRotation.set(objRot);
@@ -490,18 +518,18 @@ public class VRViewManagerOpenVR extends AbstractVRViewManager {
//org.lwjgl.opengl.GL11.glEnable(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_SRGB);
if( !environment.isInstanceRendering()) {
- leftViewport = setupViewBuffers(getLeftCamera(), LEFT_VIEW_NAME);
+ leftViewPort = setupViewBuffers(getLeftCamera(), LEFT_VIEW_NAME);
rightCamera = getLeftCamera().clone();
if( environment.getVRHardware() != null ){
getRightCamera().setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionRightEye(getRightCamera()));
}
- rightViewport = setupViewBuffers(getRightCamera(), RIGHT_VIEW_NAME);
+ rightViewPort = setupViewBuffers(getRightCamera(), RIGHT_VIEW_NAME);
} else {
if (environment.getApplication() != null){
logger.severe("THIS CODE NEED CHANGES !!!");
- leftViewport = environment.getApplication().getViewPort();
+ leftViewPort = environment.getApplication().getViewPort();
//leftViewport.attachScene(app.getRootNode());
rightCamera = getLeftCamera().clone();
if( environment.getVRHardware() != null ){
@@ -520,7 +548,7 @@ public class VRViewManagerOpenVR extends AbstractVRViewManager {
}
// setup gui
- environment.getVRGUIManager().setupGui(getLeftCamera(), getRightCamera(), getLeftViewport(), getRightViewport());
+ environment.getVRGUIManager().setupGui(getLeftCamera(), getRightCamera(), getLeftViewPort(), getRightViewPort());
if( environment.getVRHardware() != null ) {
// call these to cache the results internally