Merge branch 'master' into PBRisComing
This commit is contained in:
		
						commit
						570c714c25
					
				| @ -25,7 +25,6 @@ install: | ||||
| script: | ||||
|   - ./gradlew check | ||||
|   - ./gradlew createZipDistribution | ||||
|   - "[ $TRAVIS_BRANCH == 'master' ] && [ $TRAVIS_PULL_REQUEST == 'false' ] && ./gradlew uploadArchives || :" | ||||
| 
 | ||||
| before_deploy: | ||||
|   - export RELEASE_DIST=$(ls build/distributions/*.zip) | ||||
| @ -54,3 +53,7 @@ before_install: | ||||
|   # wget http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin -O ndk.bin | ||||
|   # 7z x ndk.bin -y > /dev/null | ||||
|   # export ANDROID_NDK=`pwd`/android-ndk-r10c | ||||
| 
 | ||||
| after_success: | ||||
|   - '[ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && ./gradlew uploadArchives || :' | ||||
|   - '[ -n "$TRAVIS_TAG" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && ./gradlew uploadArchives bintrayUpload || :' | ||||
|  | ||||
							
								
								
									
										29
									
								
								bintray.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								bintray.gradle
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| // | ||||
| // This file is to be applied to some subproject. | ||||
| // | ||||
| 
 | ||||
| apply plugin: 'com.jfrog.bintray' | ||||
| 
 | ||||
| bintray { | ||||
|     user = bintray_user | ||||
|     key = bintray_api_key | ||||
|     configurations = ['archives'] | ||||
|     dryRun = false  | ||||
|     pkg { | ||||
|         repo = 'org.jmonkeyengine' | ||||
|         userOrg = 'jmonkeyengine' | ||||
|         name = project.name | ||||
|         desc = POM_DESCRIPTION | ||||
|         websiteUrl = POM_URL | ||||
|         licenses = ['BSD New'] | ||||
|         vcsUrl = POM_SCM_URL | ||||
|         labels = ['jmonkeyengine'] | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bintrayUpload.dependsOn(writeFullPom) | ||||
| 
 | ||||
| bintrayUpload.onlyIf { | ||||
|     (bintray_api_key.length() > 0) && | ||||
|     !(version ==~ /.*SNAPSHOT/) | ||||
| } | ||||
							
								
								
									
										10
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								build.gradle
									
									
									
									
									
								
							| @ -2,10 +2,11 @@ import org.gradle.api.artifacts.* | ||||
| 
 | ||||
| buildscript { | ||||
|     repositories { | ||||
|         mavenCentral() | ||||
|         jcenter() | ||||
|     } | ||||
|     dependencies { | ||||
|         classpath 'com.android.tools.build:gradle:1.1.0' | ||||
|         classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.5' | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -17,6 +18,9 @@ apply from: file('upload.gradle') | ||||
| subprojects { | ||||
|     if(!project.name.equals('jme3-android-examples')) { | ||||
|         apply from: rootProject.file('common.gradle') | ||||
|         if (!['jme3-testdata', 'sdk'].contains(project.name)) { | ||||
|             apply from: rootProject.file('bintray.gradle') | ||||
|         } | ||||
|     } else { | ||||
|         apply from: rootProject.file('common-android-app.gradle') | ||||
|     } | ||||
| @ -86,6 +90,8 @@ task dist(dependsOn: [':jme3-examples:dist', 'mergedJavadoc']){ | ||||
| task mergedJavadoc(type: Javadoc, description: 'Creates Javadoc from all the projects.') { | ||||
|     title = 'jMonkeyEngine3' | ||||
|     destinationDir = mkdir("dist/javadoc") | ||||
|      | ||||
|     options.encoding = 'UTF-8' | ||||
| 
 | ||||
|     // Allows Javadoc to be generated on Java 8 despite doclint errors. | ||||
|     if (JavaVersion.current().isJava8Compatible()) { | ||||
| @ -174,4 +180,4 @@ task configureAndroidNDK { | ||||
| //    tasks.withType(Test) { | ||||
| //        enableAssertions = true // true by default | ||||
| //    } | ||||
| //} | ||||
| //} | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| apply plugin: 'java' | ||||
| apply plugin: 'maven' | ||||
| 
 | ||||
| group = 'com.jme3' | ||||
| group = 'org.jmonkeyengine' | ||||
| version = jmePomVersion | ||||
| 
 | ||||
| sourceCompatibility = '1.6' | ||||
| @ -61,12 +61,53 @@ task javadocJar(type: Jar, dependsOn: javadoc, description: 'Creates a jar from | ||||
|     from javadoc.destinationDir | ||||
| } | ||||
| 
 | ||||
| def pomConfig = { | ||||
|     name POM_NAME | ||||
|     description POM_DESCRIPTION | ||||
|     url POM_URL | ||||
|     inceptionYear '2016' | ||||
|     scm { | ||||
|         url POM_SCM_URL | ||||
|         connection POM_SCM_CONNECTION | ||||
|         developerConnection POM_SCM_DEVELOPER_CONNECTION | ||||
|     } | ||||
|     licenses { | ||||
|         license { | ||||
|             name POM_LICENSE_NAME | ||||
|             url POM_LICENSE_URL | ||||
|             distribution POM_LICENSE_DISTRIBUTION | ||||
|         } | ||||
|     } | ||||
|     // from http://hub.jmonkeyengine.org/introduction/team/ | ||||
|     developers { | ||||
|         developer { | ||||
|             name 'jMonkeyEngine Team' | ||||
|             id 'jMonkeyEngine' | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // workaround to be able to use same custom pom with 'maven' and 'bintray' plugin | ||||
| task writeFullPom { | ||||
|     ext.pomFile = "$mavenPomDir/${project.name}-${project.version}.pom" | ||||
|     outputs.file pomFile | ||||
|     doLast { | ||||
|         pom { | ||||
|             project pomConfig | ||||
|         }.writeTo(pomFile) | ||||
|     } | ||||
| } | ||||
| assemble.dependsOn(writeFullPom) | ||||
| install.dependsOn(writeFullPom) | ||||
| uploadArchives.dependsOn(writeFullPom) | ||||
| 
 | ||||
| artifacts { | ||||
|     archives jar | ||||
|     archives sourcesJar | ||||
|     if(buildJavaDoc == "true"){ | ||||
|         archives javadocJar | ||||
|     } | ||||
|     archives writeFullPom.outputs.files[0] | ||||
| } | ||||
| 
 | ||||
| uploadArchives { | ||||
| @ -80,23 +121,7 @@ uploadArchives { | ||||
|              authentication(userName: "www-updater", privateKey: "private/www-updater.key") | ||||
|         } | ||||
|          | ||||
|         pom.project { | ||||
|             name POM_NAME | ||||
|             description POM_DESCRIPTION | ||||
|             url POM_URL | ||||
|             scm { | ||||
|                 url POM_SCM_URL | ||||
|                 connection POM_SCM_CONNECTION | ||||
|                 developerConnection POM_SCM_DEVELOPER_CONNECTION | ||||
|             } | ||||
|             licenses { | ||||
|                 license { | ||||
|                     name POM_LICENSE_NAME | ||||
|                     url POM_LICENSE_URL | ||||
|                     distribution POM_LICENSE_DISTRIBUTION | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         pom.project pomConfig | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -37,3 +37,7 @@ POM_SCM_DEVELOPER_CONNECTION=scm:git:git@github.com:jMonkeyEngine/jmonkeyengine. | ||||
| POM_LICENSE_NAME=New BSD (3-clause) License | ||||
| POM_LICENSE_URL=http://opensource.org/licenses/BSD-3-Clause | ||||
| POM_LICENSE_DISTRIBUTION=repo | ||||
| 
 | ||||
| # Bintray settings to override in $HOME/.gradle/gradle.properties or ENV or commandline | ||||
| bintray_user= | ||||
| bintray_api_key= | ||||
|  | ||||
| @ -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.Structure; | ||||
| import com.jme3.scene.plugins.blender.materials.MaterialContext; | ||||
| import com.jme3.scene.plugins.blender.meshes.TemporalMesh; | ||||
| import com.jme3.texture.Texture; | ||||
| 
 | ||||
| /** | ||||
| @ -389,11 +390,11 @@ public class BlenderContext { | ||||
|                     } | ||||
|                 } | ||||
|             } else if("ME".equals(namePrefix)) { | ||||
|                 List<Node> features = (List<Node>) linkedFeatures.get("meshes"); | ||||
|                 if(features != null) { | ||||
|                     for(Node feature : features) { | ||||
|                         if(featureName.equals(feature.getName())) { | ||||
|                             return feature; | ||||
|                 List<TemporalMesh> temporalMeshes = (List<TemporalMesh>) linkedFeatures.get("meshes"); | ||||
|                 if(temporalMeshes != null) { | ||||
|                     for(TemporalMesh temporalMesh : temporalMeshes) { | ||||
|                         if(featureName.equals(temporalMesh.getName())) { | ||||
|                             return temporalMesh; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
| @ -174,7 +174,7 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { | ||||
|     private static class BonesChain extends ArrayList<BoneContext> { | ||||
|         private static final long serialVersionUID = -1850524345643600718L; | ||||
| 
 | ||||
|         private List<Matrix> bonesMatrices = new ArrayList<Matrix>(); | ||||
|         private List<Matrix> localBonesMatrices = new ArrayList<Matrix>(); | ||||
| 
 | ||||
|         public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection<Long> alteredOmas, BlenderContext blenderContext) { | ||||
|             if (bone != null) { | ||||
| @ -187,12 +187,21 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { | ||||
|                     this.add(boneContext); | ||||
|                     alteredOmas.add(boneContext.getBoneOma()); | ||||
| 
 | ||||
|                     Space space = this.size() < bonesAffected ? Space.CONSTRAINT_SPACE_LOCAL : Space.CONSTRAINT_SPACE_WORLD; | ||||
|                     Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), space); | ||||
|                     bonesMatrices.add(new DTransform(transform).toMatrix()); | ||||
|                     Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); | ||||
|                     localBonesMatrices.add(new DTransform(transform).toMatrix()); | ||||
| 
 | ||||
|                     bone = bone.getParent(); | ||||
|                 } | ||||
|                  | ||||
|                 if(localBonesMatrices.size() > 0) { | ||||
|                 	// making the matrices describe the local transformation | ||||
|                     Matrix parentWorldMatrix = localBonesMatrices.get(localBonesMatrices.size() - 1); | ||||
|                     for(int i=localBonesMatrices.size() - 2;i>=0;--i) { | ||||
|                     	SimpleMatrix m = parentWorldMatrix.invert().mult(localBonesMatrices.get(i)); | ||||
|                     	parentWorldMatrix = localBonesMatrices.get(i); | ||||
|                     	localBonesMatrices.set(i, new Matrix(m)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -211,16 +220,16 @@ public class ConstraintDefinitionIK extends ConstraintDefinition { | ||||
|                 SimpleMatrix m = parentWorldMatrix.invert().mult(boneMatrix); | ||||
|                 boneMatrix = new Matrix(m); | ||||
|             } | ||||
|             bonesMatrices.set(index, boneMatrix); | ||||
|             localBonesMatrices.set(index, boneMatrix); | ||||
|         } | ||||
| 
 | ||||
|         public Matrix getWorldMatrix(int index) { | ||||
|             if (index == this.size() - 1) { | ||||
|                 return new Matrix(bonesMatrices.get(this.size() - 1)); | ||||
|                 return new Matrix(localBonesMatrices.get(this.size() - 1)); | ||||
|             } | ||||
| 
 | ||||
|             SimpleMatrix result = this.getWorldMatrix(index + 1); | ||||
|             result = result.mult(bonesMatrices.get(index)); | ||||
|             result = result.mult(localBonesMatrices.get(index)); | ||||
|             return new Matrix(result); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -180,8 +180,8 @@ public class CurvesTemporalMesh extends TemporalMesh { | ||||
|         if (bevelObject != null && beziers.size() > 0) { | ||||
|             this.append(this.applyBevelAndTaper(this, bevelObject, taperObject, blenderContext)); | ||||
|         } else { | ||||
|             int originalVerticesAmount = vertices.size(); | ||||
|             for (BezierLine bezierLine : beziers) { | ||||
|             	int originalVerticesAmount = vertices.size(); | ||||
|                 vertices.add(bezierLine.vertices[0]); | ||||
|                 Vector3f v = bezierLine.vertices[1].subtract(bezierLine.vertices[0]).normalizeLocal(); | ||||
|                 float temp = v.x; | ||||
|  | ||||
| @ -10,6 +10,7 @@ import com.jme3.math.Vector3f; | ||||
| import com.jme3.scene.plugins.blender.file.BlenderFileException; | ||||
| import com.jme3.scene.plugins.blender.file.Pointer; | ||||
| 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; | ||||
| 
 | ||||
| /** | ||||
| @ -24,6 +25,8 @@ public class Edge { | ||||
| 
 | ||||
|     /** The vertices indexes. */ | ||||
|     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. */ | ||||
|     private float               crease; | ||||
|     /** 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. */ | ||||
|     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 | ||||
|      * outside this class. | ||||
| @ -74,14 +84,14 @@ public class Edge { | ||||
|      * @return the first vertex of the edge | ||||
|      */ | ||||
|     public Vector3f getFirstVertex() { | ||||
|         return temporalMesh.getVertices().get(index1); | ||||
|         return temporalMesh == null ? v1 : temporalMesh.getVertices().get(index1); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return the second vertex of the edge | ||||
|      */ | ||||
|     public Vector3f getSecondVertex() { | ||||
|         return temporalMesh.getVertices().get(index2); | ||||
|         return temporalMesh == null ? v2 : temporalMesh.getVertices().get(index2); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -188,28 +198,82 @@ public class Edge { | ||||
|      * @return <b>true</b> if the edges cross and false otherwise | ||||
|      */ | ||||
|     public boolean cross(Edge edge) { | ||||
|         Vector3f P1 = this.getFirstVertex(); | ||||
|         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); | ||||
|         float t1 = (P2.x - P1.x + v.x * t2) / u.x; | ||||
|         Vector3f p1 = P1.add(u.mult(t1)); | ||||
|         Vector3f p2 = P2.add(v.mult(t2)); | ||||
|         return this.getCrossPoint(edge) != null; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| 	 * The method computes the crossing pint of this edge and another edge. If | ||||
| 	 * there is no crossing then null is returned. | ||||
| 	 *  | ||||
| 	 * @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) { | ||||
|             // the lines cross, check if p1 and p2 are within the edges | ||||
|             Vector3f p = p1.subtract(P1); | ||||
|             float cos = p.dot(u) / (p.length() * u.length()); | ||||
|             if (cos > 0 && p.length() <= u.length()) { | ||||
| 		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 | ||||
|             Vector3d p = p1.subtract(P1); | ||||
|             double cos = p.dot(u) / p.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 | ||||
|                 p = p2.subtract(P2); | ||||
|                 cos = p.dot(v) / (p.length() * v.length()); | ||||
|                 return cos > 0 && p.length() <= u.length(); | ||||
|                 cos = p.dot(v) / p.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 | ||||
|     public String toString() { | ||||
|  | ||||
| @ -276,30 +276,45 @@ public class Face implements Comparator<Integer> { | ||||
|             List<Face> facesToTriangulate = new ArrayList<Face>(Arrays.asList(this.clone())); | ||||
|             while (facesToTriangulate.size() > 0) { | ||||
|                 Face face = facesToTriangulate.remove(0); | ||||
|                 int previousIndex1 = -1, previousIndex2 = -1, previousIndex3 = -1; | ||||
|                 while (face.vertexCount() > 0) { | ||||
|                     indexes[0] = face.getIndex(0); | ||||
|                     indexes[1] = face.findClosestVertex(indexes[0], -1); | ||||
|                     indexes[2] = face.findClosestVertex(indexes[0], indexes[1]); | ||||
|                 // 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; | ||||
|                     while (face.vertexCount() > 0) { | ||||
|                         indexes[0] = face.getIndex(0); | ||||
|                         indexes[1] = face.findClosestVertex(indexes[0], -1); | ||||
|                         indexes[2] = face.findClosestVertex(indexes[0], indexes[1]); | ||||
| 
 | ||||
|                     LOGGER.finer("Veryfying improper triangulation of the temporal mesh."); | ||||
|                     if (indexes[0] < 0 || indexes[1] < 0 || indexes[2] < 0) { | ||||
|                         throw new BlenderFileException("Unable to find two closest vertices while triangulating face in mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!"); | ||||
|                     } | ||||
|                     if (previousIndex1 == indexes[0] && previousIndex2 == indexes[1] && previousIndex3 == indexes[2]) { | ||||
|                         throw new BlenderFileException("Infinite loop detected during triangulation of mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!"); | ||||
|                     } | ||||
|                     previousIndex1 = indexes[0]; | ||||
|                     previousIndex2 = indexes[1]; | ||||
|                     previousIndex3 = indexes[2]; | ||||
|                         LOGGER.finer("Veryfying improper triangulation of the temporal mesh."); | ||||
|                         if (indexes[0] < 0 || indexes[1] < 0 || indexes[2] < 0) { | ||||
|                             throw new BlenderFileException("Unable to find two closest vertices while triangulating face in mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!"); | ||||
|                         } | ||||
|                         if (previousIndex1 == indexes[0] && previousIndex2 == indexes[1] && previousIndex3 == indexes[2]) { | ||||
|                             throw new BlenderFileException("Infinite loop detected during triangulation of mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!"); | ||||
|                         } | ||||
|                         previousIndex1 = indexes[0]; | ||||
|                         previousIndex2 = indexes[1]; | ||||
|                         previousIndex3 = indexes[2]; | ||||
| 
 | ||||
|                     Arrays.sort(indexes, this); | ||||
|                     facesToTriangulate.addAll(face.detachTriangle(indexes)); | ||||
|                     triangulatedFaces.add(new IndexesLoop(indexes)); | ||||
|                         Arrays.sort(indexes, this); | ||||
|                         facesToTriangulate.addAll(face.detachTriangle(indexes)); | ||||
|                         triangulatedFaces.add(new IndexesLoop(indexes)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } 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); | ||||
|             for (int i = 1; i < this.vertexCount() - 1; ++i) { | ||||
|                 indexes[1] = this.getIndex(i); | ||||
| @ -308,7 +323,7 @@ public class Face implements Comparator<Integer> { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     /** | ||||
|      * @return <b>true</b> if the face is smooth and <b>false</b> otherwise | ||||
|      */ | ||||
| @ -335,17 +350,23 @@ public class Face implements Comparator<Integer> { | ||||
|         return "Face " + indexes; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 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. | ||||
|      * The closes vertex must be able to create an edge that is fully contained within the face and does not cross | ||||
|      * any other edges. | ||||
|      * @param index | ||||
|      *            the index of the vertex that needs to have found the nearest neighbour | ||||
|      * @param indexToIgnore | ||||
|      *            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 | ||||
|      */ | ||||
| 	/** | ||||
| 	 * 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. | ||||
| 	 * The closest vertex must be able to create an edge that is fully contained | ||||
| 	 * 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 | ||||
| 	 *            the index of the vertex that needs to have found the nearest | ||||
| 	 *            neighbour | ||||
| 	 * @param indexToIgnore | ||||
| 	 *            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 | ||||
| 	 */ | ||||
|     private int findClosestVertex(int index, int indexToIgnore) { | ||||
|         int result = -1; | ||||
|         List<Vector3f> vertices = temporalMesh.getVertices(); | ||||
| @ -355,7 +376,7 @@ public class Face implements Comparator<Integer> { | ||||
|             if (i != index && i != indexToIgnore) { | ||||
|                 Vector3f v2 = vertices.get(i); | ||||
|                 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; | ||||
|                     distance = d; | ||||
|                 } | ||||
| @ -376,11 +397,9 @@ public class Face implements Comparator<Integer> { | ||||
|         int index2 = edge.getSecondIndex(); | ||||
|         // check if the line between the vertices is not a border edge of the face | ||||
|         if (!indexes.areNeighbours(index1, index2)) { | ||||
|             List<Vector3f> vertices = temporalMesh.getVertices(); | ||||
| 
 | ||||
|             for (int i = 0; i < indexes.size(); ++i) { | ||||
|                 int i1 = this.getIndex(i); | ||||
|                 int i2 = this.getIndex(i + 1); | ||||
|                 int i1 = this.getIndex(i - 1); | ||||
|                 int i2 = this.getIndex(i); | ||||
|                 // 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 (edge.cross(new Edge(i1, i2, 0, false, temporalMesh))) { | ||||
| @ -389,35 +408,53 @@ 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 | ||||
|             // we check it by comparing the angle that is created by vertices: [index1 - 1, index1, index1 + 1] | ||||
|             // with the one creaded by vertices: [index1 - 1, index1, index2] | ||||
|             // if the latter is greater than it means that the edge is outside the face | ||||
|             // IMPORTANT: we assume that all vertices are in one plane (this should be ensured before creating the Face) | ||||
|             int indexOfIndex1 = indexes.indexOf(index1); | ||||
|             int indexMinus1 = this.getIndex(indexOfIndex1 - 1);// indexOfIndex1 == 0 ? indexes.get(indexes.size() - 1) : indexes.get(indexOfIndex1 - 1); | ||||
|             int indexPlus1 = this.getIndex(indexOfIndex1 + 1);// indexOfIndex1 == indexes.size() - 1 ? 0 : indexes.get(indexOfIndex1 + 1); | ||||
| 
 | ||||
|             Vector3f edge1 = vertices.get(indexMinus1).subtract(vertices.get(index1)).normalizeLocal(); | ||||
|             Vector3f edge2 = vertices.get(indexPlus1).subtract(vertices.get(index1)).normalizeLocal(); | ||||
|             Vector3f newEdge = vertices.get(index2).subtract(vertices.get(index1)).normalizeLocal(); | ||||
| 
 | ||||
|             // verify f the later computed angle is inside or outside the face | ||||
|             Vector3f direction1 = edge1.cross(edge2).normalizeLocal(); | ||||
|             Vector3f direction2 = edge1.cross(newEdge).normalizeLocal(); | ||||
|             Vector3f normal = temporalMesh.getNormals().get(index1); | ||||
| 
 | ||||
|             boolean isAngle1Interior = normal.dot(direction1) < 0; | ||||
|             boolean isAngle2Interior = normal.dot(direction2) < 0; | ||||
| 
 | ||||
|             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 angle1 >= angle2; | ||||
|             // computing the edge's middle point | ||||
|             Vector3f edgeMiddlePoint = edge.computeCentroid(); | ||||
|             // computing the edge that is perpendicular to the given edge and has a length of 1 (length actually does not matter) | ||||
|             Vector3f edgeVector = edge.getSecondVertex().subtract(edge.getFirstVertex()); | ||||
|             Vector3f edgeNormal = temporalMesh.getNormals().get(index1).cross(edgeVector).normalizeLocal(); | ||||
|             Edge e = new Edge(edgeMiddlePoint, edgeNormal.add(edgeMiddlePoint)); | ||||
|             // compute the vectors from the middle point to the crossing between the extended edge 'e' and other edges of the face | ||||
|             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 | ||||
|             } | ||||
|              | ||||
|             // use only distinct vertices (doubles may appear if the crossing point is a vertex) | ||||
|             List<Vector3f> distinctCrossingVectors = new ArrayList<Vector3f>(); | ||||
|             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); | ||||
|         		} | ||||
|             } | ||||
|              | ||||
|             if(distinctCrossingVectors.size() == 0) { | ||||
|             	throw new IllegalStateException("There MUST be at least 2 crossing vertices!"); | ||||
|             } | ||||
|             // 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 | ||||
|             for(int i=1;i<distinctCrossingVectors.size();++i) { | ||||
|             	if(direction != Math.signum(distinctCrossingVectors.get(i).dot(edgeNormal))) { | ||||
|             		return true; | ||||
|             	} | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         final int prime = 31; | ||||
|  | ||||
| @ -171,6 +171,8 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph | ||||
|         } | ||||
|         TempVars vars = TempVars.get(); | ||||
| 
 | ||||
|         Vector3f currentVelocity = vars.vect2.set(velocity); | ||||
|          | ||||
|         // dampen existing x/z forces | ||||
|         float existingLeftVelocity = velocity.dot(localLeft); | ||||
|         float existingForwardVelocity = velocity.dot(localForward); | ||||
| @ -194,7 +196,7 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph | ||||
|             //add resulting vector to existing velocity | ||||
|             velocity.addLocal(localWalkDirection); | ||||
|         } | ||||
|         rigidBody.setLinearVelocity(velocity); | ||||
|         if(currentVelocity.distance(velocity) > FastMath.ZERO_TOLERANCE) rigidBody.setLinearVelocity(velocity); | ||||
|         if (jump) { | ||||
|             //TODO: precalculate jump force | ||||
|             Vector3f rotatedJumpForce = vars.vect1; | ||||
|  | ||||
| @ -82,7 +82,9 @@ public class SphereCollisionShape extends CollisionShape { | ||||
|      */ | ||||
|     @Override | ||||
|     public void setScale(Vector3f scale) { | ||||
|         Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "SphereCollisionShape cannot be scaled"); | ||||
|         if (!scale.equals(Vector3f.UNIT_XYZ)) { | ||||
|             Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "SphereCollisionShape cannot be scaled"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected void createShape() { | ||||
| @ -91,7 +93,7 @@ public class SphereCollisionShape extends CollisionShape { | ||||
| //        new SphereShape(radius); | ||||
| //        objectId.setLocalScaling(Converter.convert(getScale())); | ||||
| //        objectId.setMargin(margin); | ||||
|         setScale(scale); | ||||
|         setScale(scale); // Set the scale to 1 | ||||
|         setMargin(margin); | ||||
|     } | ||||
|      | ||||
|  | ||||
| @ -650,12 +650,28 @@ public class Application implements SystemListener { | ||||
|      * Callables 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 callable The callable to run in the main jME3 thread | ||||
|      */ | ||||
|     public <V> Future<V> enqueue(Callable<V> callable) { | ||||
|         AppTask<V> task = new AppTask<V>(callable); | ||||
|         taskQueue.add(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)} | ||||
| @ -740,4 +756,19 @@ public class Application implements SystemListener { | ||||
|         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; | ||||
|         } | ||||
|          | ||||
|     } | ||||
|      | ||||
| } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (c) 2009-2012 jMonkeyEngine | ||||
|  * Copyright (c) 2009-2012, 2016 jMonkeyEngine | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
| @ -33,6 +33,7 @@ package com.jme3.audio; | ||||
| 
 | ||||
| import com.jme3.asset.AssetManager; | ||||
| import com.jme3.asset.AssetNotFoundException; | ||||
| import com.jme3.audio.AudioData.DataType; | ||||
| import com.jme3.export.InputCapsule; | ||||
| import com.jme3.export.JmeExporter; | ||||
| import com.jme3.export.JmeImporter; | ||||
| @ -127,6 +128,17 @@ public class AudioNode extends Node implements AudioSource { | ||||
|     public AudioNode(AudioData audioData, AudioKey audioKey) { | ||||
|         setAudioData(audioData, audioKey); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Creates a new <code>AudioNode</code> with the given audio file. | ||||
|      * @param assetManager The asset manager to use to load the audio file | ||||
|      * @param name The filename of the audio file | ||||
|      * @param type The type. If <code>{@link com.jme3.audio.AudioData.DataType}.Stream</code>, the audio will be streamed gradually from disk, | ||||
|      *             otherwise it will be buffered (<code>{@link com.jme3.audio.AudioData.DataType}.Buffer</code>) | ||||
|      */ | ||||
|     public AudioNode(AssetManager assetManager, String name, DataType type) { | ||||
|         this(assetManager, name, type == DataType.Stream, true); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Creates a new <code>AudioNode</code> with the given audio file. | ||||
| @ -139,6 +151,8 @@ public class AudioNode extends Node implements AudioSource { | ||||
|      * the stream cache is used. When enabled, the audio stream will | ||||
|      * be read entirely but not decoded, allowing features such as  | ||||
|      * seeking, looping and determining duration. | ||||
|      *  | ||||
|      * @deprecated Use {@link AudioNode#AudioNode(com.jme3.asset.AssetManager, java.lang.String, com.jme3.audio.AudioData.DataType)} instead | ||||
|      */ | ||||
|     public AudioNode(AssetManager assetManager, String name, boolean stream, boolean streamCache) { | ||||
|         this.audioKey = new AudioKey(name, stream, streamCache); | ||||
| @ -152,9 +166,11 @@ public class AudioNode extends Node implements AudioSource { | ||||
|      * @param name The filename of the audio file | ||||
|      * @param stream If true, the audio will be streamed gradually from disk,  | ||||
|      *               otherwise, it will be buffered. | ||||
|      *  | ||||
|      * @deprecated Use {@link AudioNode#AudioNode(com.jme3.asset.AssetManager, java.lang.String, com.jme3.audio.AudioData.DataType)} instead | ||||
|      */ | ||||
|     public AudioNode(AssetManager assetManager, String name, boolean stream) { | ||||
|         this(assetManager, name, stream, false); | ||||
|         this(assetManager, name, stream, true); // Always streamCached | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -167,7 +183,7 @@ public class AudioNode extends Node implements AudioSource { | ||||
|      * @deprecated AudioRenderer parameter is ignored. | ||||
|      */ | ||||
|     public AudioNode(AudioRenderer audioRenderer, AssetManager assetManager, String name) { | ||||
|         this(assetManager, name, false); | ||||
|         this(assetManager, name, DataType.Buffer); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
| @ -175,9 +191,10 @@ public class AudioNode extends Node implements AudioSource { | ||||
|      *  | ||||
|      * @param assetManager The asset manager to use to load the audio file | ||||
|      * @param name The filename of the audio file | ||||
|      * @deprecated Use {@link AudioNode#AudioNode(com.jme3.asset.AssetManager, java.lang.String, com.jme3.audio.AudioData.DataType) } instead | ||||
|      */ | ||||
|     public AudioNode(AssetManager assetManager, String name) { | ||||
|         this(assetManager, name, false); | ||||
|         this(assetManager, name, DataType.Buffer); | ||||
|     } | ||||
|      | ||||
|     protected AudioRenderer getRenderer() { | ||||
| @ -310,6 +327,19 @@ public class AudioNode extends Node implements AudioSource { | ||||
|         this.status = status; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the Type of the underlying AudioData to see if it's streamed or buffered. | ||||
|      * This is a shortcut to getAudioData().getType() | ||||
|      * <b>Warning</b>: Can return null! | ||||
|      * @return The {@link com.jme3.audio.AudioData.DataType} of the audio node. | ||||
|      */ | ||||
|     public DataType getType() { | ||||
|         if (data == null) | ||||
|             return null; | ||||
|         else | ||||
|             return data.getDataType(); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * @return True if the audio will keep looping after it is done playing, | ||||
|      * otherwise, false. | ||||
|  | ||||
| @ -109,8 +109,11 @@ public class BIHTree implements CollisionData { | ||||
|         this.mesh = mesh; | ||||
|         this.maxTrisPerNode = maxTrisPerNode; | ||||
| 
 | ||||
|         if (maxTrisPerNode < 1 || mesh == null) { | ||||
|             throw new IllegalArgumentException(); | ||||
|         if (maxTrisPerNode < 1) { | ||||
|             throw new IllegalArgumentException("maxTrisPerNode cannot be less than 1"); | ||||
|         } | ||||
|         if (mesh == null) { | ||||
|             throw new IllegalArgumentException("Mesh cannot be null"); | ||||
|         } | ||||
| 
 | ||||
|         bihSwapTmp = new float[9]; | ||||
| @ -451,7 +454,7 @@ public class BIHTree implements CollisionData { | ||||
|         } else if (bv instanceof BoundingBox) { | ||||
|             bbox = new BoundingBox((BoundingBox) bv); | ||||
|         } else { | ||||
|             throw new UnsupportedCollisionException(); | ||||
|             throw new UnsupportedCollisionException("BoundingVolume:" + bv); | ||||
|         } | ||||
| 
 | ||||
|         bbox.transform(worldMatrix.invert(), bbox); | ||||
| @ -470,7 +473,7 @@ public class BIHTree implements CollisionData { | ||||
|             BoundingVolume bv = (BoundingVolume) other; | ||||
|             return collideWithBoundingVolume(bv, worldMatrix, results); | ||||
|         } else { | ||||
|             throw new UnsupportedCollisionException(); | ||||
|             throw new UnsupportedCollisionException("Collidable:" + other); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -106,6 +106,7 @@ public class ParticleEmitter extends Geometry { | ||||
|     private boolean worldSpace = true; | ||||
|     //variable that helps with computations | ||||
|     private transient Vector3f temp = new Vector3f(); | ||||
|     private transient Vector3f lastPos; | ||||
| 
 | ||||
|     public static class ParticleEmitterControl implements Control { | ||||
| 
 | ||||
| @ -1013,12 +1014,16 @@ public class ParticleEmitter extends Geometry { | ||||
|          | ||||
|         // Spawns particles within the tpf timeslot with proper age | ||||
|         float interval = 1f / particlesPerSec; | ||||
|         float originalTpf = tpf; | ||||
|         tpf += timeDifference; | ||||
|         while (tpf > interval){ | ||||
|             tpf -= interval; | ||||
|             Particle p = emitParticle(min, max); | ||||
|             if (p != null){ | ||||
|                 p.life -= tpf; | ||||
|                 if (lastPos != null && isInWorldSpace()) { | ||||
|                     p.position.interpolateLocal(lastPos, 1 - tpf / originalTpf); | ||||
|                 } | ||||
|                 if (p.life <= 0){ | ||||
|                     freeParticle(lastUsed); | ||||
|                 }else{ | ||||
| @ -1028,6 +1033,12 @@ public class ParticleEmitter extends Geometry { | ||||
|         } | ||||
|         timeDifference = tpf; | ||||
| 
 | ||||
|         if (lastPos == null) { | ||||
|             lastPos = new Vector3f(); | ||||
|         } | ||||
| 
 | ||||
|         lastPos.set(getWorldTranslation()); | ||||
| 
 | ||||
|         BoundingBox bbox = (BoundingBox) this.getMesh().getBound(); | ||||
|         bbox.setMinMax(min, max); | ||||
|         this.setBoundRefresh(); | ||||
|  | ||||
| @ -135,6 +135,14 @@ public class DefaultJoystickAxis implements JoystickAxis { | ||||
|         return deadZone; | ||||
|     }         | ||||
| 
 | ||||
|     /** | ||||
|      *  Sets/overrides the dead zone for this axis.  This indicates that values | ||||
|      *  within +/- deadZone should be ignored. | ||||
|      */ | ||||
|     public void setDeadZone( float f ) { | ||||
|         this.deadZone = f; | ||||
|     }      | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString(){ | ||||
|         return "JoystickAxis[name=" + name + ", parent=" + parent.getName() + ", id=" + axisIndex  | ||||
|  | ||||
| @ -39,6 +39,7 @@ import com.jme3.math.FastMath; | ||||
| import com.jme3.math.Vector2f; | ||||
| import com.jme3.util.IntMap; | ||||
| import com.jme3.util.IntMap.Entry; | ||||
| import com.jme3.util.SafeArrayList; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.logging.Level; | ||||
| @ -96,16 +97,15 @@ public class InputManager implements RawInputListener { | ||||
|     private boolean eventsPermitted = false; | ||||
|     private boolean mouseVisible = true; | ||||
|     private boolean safeMode = false; | ||||
|     private float axisDeadZone = 0.05f; | ||||
|     private Vector2f cursorPos = new Vector2f(); | ||||
|     private float globalAxisDeadZone = 0.05f; | ||||
|     private final Vector2f cursorPos = new Vector2f(); | ||||
|     private Joystick[] joysticks; | ||||
|     private final IntMap<ArrayList<Mapping>> bindings = new IntMap<ArrayList<Mapping>>(); | ||||
|     private final HashMap<String, Mapping> mappings = new HashMap<String, Mapping>(); | ||||
|     private final IntMap<Long> pressedButtons = new IntMap<Long>(); | ||||
|     private final IntMap<Float> axisValues = new IntMap<Float>(); | ||||
|     private ArrayList<RawInputListener> rawListeners = new ArrayList<RawInputListener>(); | ||||
|     private RawInputListener[] rawListenerArray = null; | ||||
|     private ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>(); | ||||
|     private final SafeArrayList<RawInputListener> rawListeners = new SafeArrayList<RawInputListener>(RawInputListener.class); | ||||
|     private final ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>(); | ||||
| 
 | ||||
|     private static class Mapping { | ||||
| 
 | ||||
| @ -248,8 +248,8 @@ public class InputManager implements RawInputListener { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void invokeAnalogsAndActions(int hash, float value, boolean applyTpf) { | ||||
|         if (value < axisDeadZone) { | ||||
|     private void invokeAnalogsAndActions(int hash, float value, float effectiveDeadZone, boolean applyTpf) { | ||||
|         if (value < effectiveDeadZone) { | ||||
|             invokeAnalogs(hash, value, !applyTpf); | ||||
|             return; | ||||
|         } | ||||
| @ -287,12 +287,14 @@ public class InputManager implements RawInputListener { | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void beginInput() { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void endInput() { | ||||
|     } | ||||
| 
 | ||||
| @ -304,17 +306,18 @@ public class InputManager implements RawInputListener { | ||||
|         int joyId = evt.getJoyIndex(); | ||||
|         int axis = evt.getAxisIndex(); | ||||
|         float value = evt.getValue(); | ||||
|         if (value < axisDeadZone && value > -axisDeadZone) { | ||||
|         float effectiveDeadZone = Math.max(globalAxisDeadZone, evt.getAxis().getDeadZone());  | ||||
|         if (value < effectiveDeadZone && value > -effectiveDeadZone) { | ||||
|             int hash1 = JoyAxisTrigger.joyAxisHash(joyId, axis, true); | ||||
|             int hash2 = JoyAxisTrigger.joyAxisHash(joyId, axis, false); | ||||
| 
 | ||||
|             Float val1 = axisValues.get(hash1); | ||||
|             Float val2 = axisValues.get(hash2); | ||||
| 
 | ||||
|             if (val1 != null && val1.floatValue() > axisDeadZone) { | ||||
|             if (val1 != null && val1 > effectiveDeadZone) { | ||||
|                 invokeActions(hash1, false); | ||||
|             } | ||||
|             if (val2 != null && val2.floatValue() > axisDeadZone) { | ||||
|             if (val2 != null && val2 > effectiveDeadZone) { | ||||
|                 invokeActions(hash2, false); | ||||
|             } | ||||
| 
 | ||||
| @ -328,11 +331,11 @@ public class InputManager implements RawInputListener { | ||||
|             // Clear the reverse direction's actions in case we | ||||
|             // crossed center too quickly | ||||
|             Float otherVal = axisValues.get(otherHash); | ||||
|             if (otherVal != null && otherVal.floatValue() > axisDeadZone) { | ||||
|             if (otherVal != null && otherVal > effectiveDeadZone) { | ||||
|                 invokeActions(otherHash, false); | ||||
|             } | ||||
| 
 | ||||
|             invokeAnalogsAndActions(hash, -value, true); | ||||
|             invokeAnalogsAndActions(hash, -value, effectiveDeadZone, true); | ||||
|             axisValues.put(hash, -value); | ||||
|             axisValues.remove(otherHash); | ||||
|         } else { | ||||
| @ -342,11 +345,11 @@ public class InputManager implements RawInputListener { | ||||
|             // Clear the reverse direction's actions in case we | ||||
|             // crossed center too quickly | ||||
|             Float otherVal = axisValues.get(otherHash); | ||||
|             if (otherVal != null && otherVal.floatValue() > axisDeadZone) { | ||||
|             if (otherVal != null && otherVal > effectiveDeadZone) { | ||||
|                 invokeActions(otherHash, false); | ||||
|             } | ||||
| 
 | ||||
|             invokeAnalogsAndActions(hash, value, true); | ||||
|             invokeAnalogsAndActions(hash, value, effectiveDeadZone, true); | ||||
|             axisValues.put(hash, value); | ||||
|             axisValues.remove(otherHash); | ||||
|         } | ||||
| @ -355,6 +358,7 @@ public class InputManager implements RawInputListener { | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void onJoyAxisEvent(JoyAxisEvent evt) { | ||||
|         if (!eventsPermitted) { | ||||
|             throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); | ||||
| @ -376,6 +380,7 @@ public class InputManager implements RawInputListener { | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void onJoyButtonEvent(JoyButtonEvent evt) { | ||||
|         if (!eventsPermitted) { | ||||
|             throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); | ||||
| @ -391,15 +396,15 @@ public class InputManager implements RawInputListener { | ||||
| 
 | ||||
|         if (evt.getDX() != 0) { | ||||
|             float val = Math.abs(evt.getDX()) / 1024f; | ||||
|             invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_X, evt.getDX() < 0), val, false); | ||||
|             invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_X, evt.getDX() < 0), val, globalAxisDeadZone, false); | ||||
|         } | ||||
|         if (evt.getDY() != 0) { | ||||
|             float val = Math.abs(evt.getDY()) / 1024f; | ||||
|             invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_Y, evt.getDY() < 0), val, false); | ||||
|             invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_Y, evt.getDY() < 0), val, globalAxisDeadZone, false); | ||||
|         } | ||||
|         if (evt.getDeltaWheel() != 0) { | ||||
|             float val = Math.abs(evt.getDeltaWheel()) / 100f; | ||||
|             invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_WHEEL, evt.getDeltaWheel() < 0), val, false); | ||||
|             invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_WHEEL, evt.getDeltaWheel() < 0), val, globalAxisDeadZone, false); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -419,6 +424,7 @@ public class InputManager implements RawInputListener { | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void onMouseMotionEvent(MouseMotionEvent evt) { | ||||
|         if (!eventsPermitted) { | ||||
|             throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); | ||||
| @ -437,6 +443,7 @@ public class InputManager implements RawInputListener { | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void onMouseButtonEvent(MouseButtonEvent evt) { | ||||
|         if (!eventsPermitted) { | ||||
|             throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); | ||||
| @ -459,6 +466,7 @@ public class InputManager implements RawInputListener { | ||||
|     /** | ||||
|      * Callback from RawInputListener. Do not use. | ||||
|      */ | ||||
|     @Override | ||||
|     public void onKeyEvent(KeyInputEvent evt) { | ||||
|         if (!eventsPermitted) { | ||||
|             throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time."); | ||||
| @ -477,7 +485,7 @@ public class InputManager implements RawInputListener { | ||||
|      * @param deadZone the deadzone for joystick axes. | ||||
|      */ | ||||
|     public void setAxisDeadZone(float deadZone) { | ||||
|         this.axisDeadZone = deadZone; | ||||
|         this.globalAxisDeadZone = deadZone; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -486,7 +494,7 @@ public class InputManager implements RawInputListener { | ||||
|      * @return the deadzone for joystick axes. | ||||
|      */ | ||||
|     public float getAxisDeadZone() { | ||||
|         return axisDeadZone; | ||||
|         return globalAxisDeadZone; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -721,7 +729,6 @@ public class InputManager implements RawInputListener { | ||||
|      */ | ||||
|     public void addRawInputListener(RawInputListener listener) { | ||||
|         rawListeners.add(listener); | ||||
|         rawListenerArray = null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -734,7 +741,6 @@ public class InputManager implements RawInputListener { | ||||
|      */ | ||||
|     public void removeRawInputListener(RawInputListener listener) { | ||||
|         rawListeners.remove(listener); | ||||
|         rawListenerArray = null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -744,13 +750,6 @@ public class InputManager implements RawInputListener { | ||||
|      */ | ||||
|     public void clearRawInputListeners() { | ||||
|         rawListeners.clear(); | ||||
|         rawListenerArray = null; | ||||
|     } | ||||
| 
 | ||||
|     private RawInputListener[] getRawListenerArray() { | ||||
|         if (rawListenerArray == null) | ||||
|             rawListenerArray = rawListeners.toArray(new RawInputListener[rawListeners.size()]); | ||||
|         return rawListenerArray; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -813,7 +812,7 @@ public class InputManager implements RawInputListener { | ||||
| 
 | ||||
|     private void processQueue() { | ||||
|         int queueSize = inputQueue.size(); | ||||
|         RawInputListener[] array = getRawListenerArray(); | ||||
|         RawInputListener[] array = rawListeners.getArray();  | ||||
| 
 | ||||
|         for (RawInputListener listener : array) { | ||||
|             listener.beginInput(); | ||||
|  | ||||
| @ -36,6 +36,11 @@ package com.jme3.input; | ||||
|  */ | ||||
| public interface KeyInput extends Input { | ||||
| 
 | ||||
|     /** | ||||
|      * unmapped key. | ||||
|      */ | ||||
|     public static final int KEY_UNKNOWN = 0x00; | ||||
| 
 | ||||
|     /** | ||||
|      * escape key. | ||||
|      */ | ||||
| @ -518,17 +523,17 @@ public interface KeyInput extends Input { | ||||
|      * delete key. | ||||
|      */ | ||||
|     public static final int KEY_DELETE = 0xD3; | ||||
|      | ||||
| 
 | ||||
|     /** | ||||
|      * Left "Windows" key on PC keyboards, left "Option" key on Mac keyboards. | ||||
|      */ | ||||
|     public static final int KEY_LMETA  = 0xDB; | ||||
|      | ||||
| 
 | ||||
|     /** | ||||
|      * Right "Windows" key on PC keyboards, right "Option" key on Mac keyboards. | ||||
|      */ | ||||
|     public static final int KEY_RMETA = 0xDC; | ||||
|      | ||||
| 
 | ||||
|     public static final int KEY_APPS = 0xDD; | ||||
|     /** | ||||
|      * power key. | ||||
| @ -539,4 +544,8 @@ public interface KeyInput extends Input { | ||||
|      */ | ||||
|     public static final int KEY_SLEEP = 0xDF; | ||||
| 
 | ||||
|     /** | ||||
|      * the last key. | ||||
|      */ | ||||
|     public static final int KEY_LAST = 0xE0; | ||||
| } | ||||
|  | ||||
| @ -34,10 +34,11 @@ package com.jme3.input; | ||||
| import static com.jme3.input.KeyInput.*; | ||||
| 
 | ||||
| public class KeyNames { | ||||
|      | ||||
| 
 | ||||
|     private static final String[] KEY_NAMES = new String[0xFF]; | ||||
|      | ||||
| 
 | ||||
|     static { | ||||
|         KEY_NAMES[KEY_UNKNOWN] = "Unknown"; | ||||
|         KEY_NAMES[KEY_0] = "0"; | ||||
|         KEY_NAMES[KEY_1] = "1"; | ||||
|         KEY_NAMES[KEY_2] = "2"; | ||||
| @ -48,7 +49,7 @@ public class KeyNames { | ||||
|         KEY_NAMES[KEY_7] = "7"; | ||||
|         KEY_NAMES[KEY_8] = "8"; | ||||
|         KEY_NAMES[KEY_9] = "9"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_Q] = "Q"; | ||||
|         KEY_NAMES[KEY_W] = "W"; | ||||
|         KEY_NAMES[KEY_E] = "E"; | ||||
| @ -75,7 +76,7 @@ public class KeyNames { | ||||
|         KEY_NAMES[KEY_B] = "B"; | ||||
|         KEY_NAMES[KEY_N] = "N"; | ||||
|         KEY_NAMES[KEY_M] = "M"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_F1] = "F1"; | ||||
|         KEY_NAMES[KEY_F2] = "F2"; | ||||
|         KEY_NAMES[KEY_F3] = "F3"; | ||||
| @ -91,7 +92,7 @@ public class KeyNames { | ||||
|         KEY_NAMES[KEY_F13] = "F13"; | ||||
|         KEY_NAMES[KEY_F14] = "F14"; | ||||
|         KEY_NAMES[KEY_F15] = "F15"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_NUMPAD0] = "Numpad 0"; | ||||
|         KEY_NAMES[KEY_NUMPAD1] = "Numpad 1"; | ||||
|         KEY_NAMES[KEY_NUMPAD2] = "Numpad 2"; | ||||
| @ -102,25 +103,26 @@ public class KeyNames { | ||||
|         KEY_NAMES[KEY_NUMPAD7] = "Numpad 7"; | ||||
|         KEY_NAMES[KEY_NUMPAD8] = "Numpad 8"; | ||||
|         KEY_NAMES[KEY_NUMPAD9] = "Numpad 9"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_NUMPADEQUALS] = "Numpad ="; | ||||
|         KEY_NAMES[KEY_NUMPADENTER] = "Numpad Enter"; | ||||
|         KEY_NAMES[KEY_NUMPADCOMMA] = "Numpad ."; | ||||
|         KEY_NAMES[KEY_NUMPADCOMMA] = "Numpad ,"; | ||||
|         KEY_NAMES[KEY_DIVIDE] = "Numpad /"; | ||||
|          | ||||
|          | ||||
|         KEY_NAMES[KEY_SUBTRACT] = "Numpad -"; | ||||
|         KEY_NAMES[KEY_DECIMAL] = "Numpad ."; | ||||
| 
 | ||||
|         KEY_NAMES[KEY_LMENU] = "Left Alt"; | ||||
|         KEY_NAMES[KEY_RMENU] = "Right Alt"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_LCONTROL] = "Left Ctrl"; | ||||
|         KEY_NAMES[KEY_RCONTROL] = "Right Ctrl"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_LSHIFT] = "Left Shift"; | ||||
|         KEY_NAMES[KEY_RSHIFT] = "Right Shift"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_LMETA] = "Left Option"; | ||||
|         KEY_NAMES[KEY_RMETA] = "Right Option"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_MINUS] = "-"; | ||||
|         KEY_NAMES[KEY_EQUALS] = "="; | ||||
|         KEY_NAMES[KEY_LBRACKET] = "["; | ||||
| @ -137,37 +139,37 @@ public class KeyNames { | ||||
|         KEY_NAMES[KEY_COLON] = ":"; | ||||
|         KEY_NAMES[KEY_UNDERLINE] = "_"; | ||||
|         KEY_NAMES[KEY_AT] = "@"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_APPS] = "Apps"; | ||||
|         KEY_NAMES[KEY_POWER] = "Power"; | ||||
|         KEY_NAMES[KEY_SLEEP] = "Sleep"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_STOP] = "Stop"; | ||||
|         KEY_NAMES[KEY_ESCAPE] = "Esc"; | ||||
|         KEY_NAMES[KEY_RETURN] = "Enter"; | ||||
|         KEY_NAMES[KEY_SPACE] = "Space"; | ||||
|         KEY_NAMES[KEY_BACK] = "Backspace"; | ||||
|         KEY_NAMES[KEY_TAB] = "Tab"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_SYSRQ] = "SysRq"; | ||||
|         KEY_NAMES[KEY_PAUSE] = "Pause"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_HOME] = "Home"; | ||||
|         KEY_NAMES[KEY_PGUP] = "Page Up"; | ||||
|         KEY_NAMES[KEY_PGDN] = "Page Down"; | ||||
|         KEY_NAMES[KEY_END] = "End"; | ||||
|         KEY_NAMES[KEY_INSERT] = "Insert"; | ||||
|         KEY_NAMES[KEY_DELETE] = "Delete"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_UP] = "Up"; | ||||
|         KEY_NAMES[KEY_LEFT] = "Left"; | ||||
|         KEY_NAMES[KEY_RIGHT] = "Right"; | ||||
|         KEY_NAMES[KEY_DOWN] = "Down"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_NUMLOCK] = "Num Lock"; | ||||
|         KEY_NAMES[KEY_CAPITAL] = "Caps Lock"; | ||||
|         KEY_NAMES[KEY_SCROLL] = "Scroll Lock"; | ||||
|          | ||||
| 
 | ||||
|         KEY_NAMES[KEY_KANA] = "Kana"; | ||||
|         KEY_NAMES[KEY_CONVERT] = "Convert"; | ||||
|         KEY_NAMES[KEY_NOCONVERT] = "No Convert"; | ||||
| @ -177,8 +179,8 @@ public class KeyNames { | ||||
|         KEY_NAMES[KEY_AX] = "Ax"; | ||||
|         KEY_NAMES[KEY_UNLABELED] = "Unlabeled"; | ||||
|     } | ||||
|      | ||||
|     public String getName(int keyId){ | ||||
| 
 | ||||
|     public static String getName(int keyId) { | ||||
|         return KEY_NAMES[keyId]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -70,6 +70,11 @@ public final class DefaultLightFilter implements LightFilter { | ||||
|             for (int i = 0; i < worldLights.size(); i++) { | ||||
|                 Light light = worldLights.get(i); | ||||
| 
 | ||||
|                 // If this light is not enabled it will be ignored. | ||||
|                 if (!light.isEnabled()) { | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 if (light.frustumCheckNeeded) { | ||||
|                     processedLights.add(light); | ||||
|                     light.frustumCheckNeeded = false; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (c) 2009-2012, 2015 jMonkeyEngine | ||||
|  * Copyright (c) 2009-2012, 2015-2016 jMonkeyEngine | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * 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); | ||||
|     } | ||||
| 
 | ||||
|     @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. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
| @ -110,9 +110,6 @@ public abstract class Light implements Savable, Cloneable { | ||||
|      */ | ||||
|     protected transient float lastDistance = -1; | ||||
| 
 | ||||
|     /** | ||||
|      * If light is disabled, it will not have any  | ||||
|      */ | ||||
|     protected boolean enabled = true; | ||||
| 
 | ||||
|     /**  | ||||
| @ -176,20 +173,24 @@ public abstract class Light implements Savable, Cloneable { | ||||
|         this.color.set(color); | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     /* | ||||
|      * Returns true if the light is enabled | ||||
|      *  | ||||
|      * @return true if the light is enabled | ||||
|      *  | ||||
|      * @see Light#setEnabled(boolean) | ||||
| 
 | ||||
|     /** | ||||
|      * Returns true if this light is enabled. | ||||
|      * @return true if enabled, otherwise false. | ||||
|      */ | ||||
|     /* | ||||
|     public boolean isEnabled() { | ||||
|         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. | ||||
|      * <p> | ||||
| @ -234,7 +235,9 @@ public abstract class Light implements Savable, Cloneable { | ||||
|     @Override | ||||
|     public Light clone(){ | ||||
|         try { | ||||
|             return (Light) super.clone(); | ||||
|             Light l = (Light) super.clone(); | ||||
|             l.color = color.clone(); | ||||
|             return l; | ||||
|         } catch (CloneNotSupportedException ex) { | ||||
|             throw new AssertionError(); | ||||
|         } | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright (c) 2009-2012, 2015 jMonkeyEngine | ||||
|  * Copyright (c) 2009-2012, 2015-2016 jMonkeyEngine | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
| @ -241,4 +241,11 @@ public class PointLight extends Light { | ||||
|             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. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
| @ -448,5 +448,13 @@ public class SpotLight extends Light { | ||||
|             this.invSpotRange = 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SpotLight clone() { | ||||
|         SpotLight s = (SpotLight)super.clone(); | ||||
|         s.direction = direction.clone(); | ||||
|         s.position = position.clone(); | ||||
|         return s; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1295,12 +1295,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable { | ||||
|         oc.write(def.getAssetName(), "material_def", null); | ||||
|         oc.write(additionalState, "render_state", null); | ||||
|         oc.write(transparent, "is_transparent", false); | ||||
|         oc.write(name, "name", null); | ||||
|         oc.writeStringSavableMap(paramValues, "parameters", null); | ||||
|     } | ||||
| 
 | ||||
|     public void read(JmeImporter im) throws IOException { | ||||
|         InputCapsule ic = im.getCapsule(this); | ||||
| 
 | ||||
|         name = ic.readString("name", null); | ||||
|         additionalState = (RenderState) ic.readSavable("render_state", null); | ||||
|         transparent = ic.readBoolean("is_transparent", false); | ||||
| 
 | ||||
|  | ||||
| @ -34,12 +34,8 @@ package com.jme3.renderer; | ||||
| import com.jme3.light.DefaultLightFilter; | ||||
| import com.jme3.light.LightFilter; | ||||
| import com.jme3.light.LightList; | ||||
| import com.jme3.material.Material; | ||||
| import com.jme3.material.MaterialDef; | ||||
| import com.jme3.material.RenderState; | ||||
| import com.jme3.material.Technique; | ||||
| import com.jme3.material.TechniqueDef; | ||||
| import com.jme3.math.*; | ||||
| import com.jme3.material.*; | ||||
| import com.jme3.math.Matrix4f; | ||||
| import com.jme3.post.SceneProcessor; | ||||
| import com.jme3.profile.AppProfiler; | ||||
| import com.jme3.profile.AppStep; | ||||
| @ -55,6 +51,7 @@ import com.jme3.shader.UniformBindingManager; | ||||
| import com.jme3.system.NullRenderer; | ||||
| import com.jme3.system.Timer; | ||||
| import com.jme3.util.SafeArrayList; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| @ -533,7 +530,6 @@ public class RenderManager { | ||||
|             lightFilter.filterLights(g, filteredLightList); | ||||
|             lightList = filteredLightList; | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         //if forcedTechnique we try to force it for render, | ||||
|         //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null | ||||
| @ -556,7 +552,7 @@ public class RenderManager { | ||||
|                 forcedRenderState = tmpRs; | ||||
| 
 | ||||
|                 //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) { | ||||
|                 // use forced material | ||||
|                 forcedMaterial.render(g, lightList, this); | ||||
| @ -641,10 +637,8 @@ public class RenderManager { | ||||
|      * <p> | ||||
|      * In addition to enqueuing the visible geometries, this method | ||||
|      * also scenes which cast or receive shadows, by putting them into the | ||||
|      * RenderQueue's  | ||||
|      * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)  | ||||
|      * shadow queue}. Each Spatial which has its  | ||||
|      * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode} | ||||
|      * RenderQueue's {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) 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 | ||||
|      * this process does not check for frustum culling on any  | ||||
|      * {@link ShadowMode#Cast shadow casters}, as they don't have to be | ||||
| @ -793,7 +787,8 @@ public class RenderManager { | ||||
|      * @param singlePassLightBatchSize the number of lights. | ||||
|      */ | ||||
|     public void setSinglePassLightBatchSize(int singlePassLightBatchSize) { | ||||
|         this.singlePassLightBatchSize = singlePassLightBatchSize; | ||||
|         // Ensure the batch size is no less than 1 | ||||
|         this.singlePassLightBatchSize = singlePassLightBatchSize < 1 ? 1 : singlePassLightBatchSize; | ||||
|     } | ||||
|      | ||||
|      | ||||
| @ -999,13 +994,12 @@ public class RenderManager { | ||||
|      * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li> | ||||
|      * <li>If any objects remained in the render queue, they are removed | ||||
|      * 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)  | ||||
|      * shadow queue} | ||||
|      * {@link RenderQueue#renderShadowQueue(GeometryList, RenderManager, Camera, boolean) shadow queue} | ||||
|      * which were not rendered because of a missing shadow renderer.</li> | ||||
|      * </ul> | ||||
|      *  | ||||
|      * @param vp | ||||
|      * @param tpf  | ||||
|      * @param vp View port to render | ||||
|      * @param tpf Time per frame value | ||||
|      */ | ||||
|     public void renderViewPort(ViewPort vp, float tpf) { | ||||
|         if (!vp.isEnabled()) { | ||||
|  | ||||
| @ -36,7 +36,6 @@ import com.jme3.shader.Shader; | ||||
| import com.jme3.texture.FrameBuffer; | ||||
| import com.jme3.texture.Image; | ||||
| import com.jme3.util.IntMap; | ||||
| import java.util.HashSet; | ||||
| 
 | ||||
| /** | ||||
|  * The statistics class allows tracking of real-time rendering statistics. | ||||
|  | ||||
| @ -31,14 +31,6 @@ | ||||
|  */ | ||||
| package com.jme3.scene; | ||||
| 
 | ||||
| import com.jme3.export.*; | ||||
| import com.jme3.material.Material; | ||||
| import com.jme3.math.Matrix4f; | ||||
| import com.jme3.math.Vector3f; | ||||
| import com.jme3.scene.mesh.IndexBuffer; | ||||
| import com.jme3.util.SafeArrayList; | ||||
| import com.jme3.util.TempVars; | ||||
| import java.io.IOException; | ||||
| import java.nio.Buffer; | ||||
| import java.nio.FloatBuffer; | ||||
| import java.util.ArrayList; | ||||
| @ -48,13 +40,22 @@ import java.util.Map; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| import com.jme3.collision.Collidable; | ||||
| import com.jme3.collision.CollisionResults; | ||||
| import com.jme3.material.Material; | ||||
| import com.jme3.math.Matrix4f; | ||||
| import com.jme3.math.Vector3f; | ||||
| import com.jme3.scene.mesh.IndexBuffer; | ||||
| import com.jme3.util.SafeArrayList; | ||||
| import com.jme3.util.TempVars; | ||||
| 
 | ||||
| /** | ||||
|  * BatchNode holds geometries that are a batched version of all the geometries that are in its sub scenegraph. | ||||
|  * There is one geometry per different material in the sub tree. | ||||
|  * The geometries are directly attached to the node in the scene graph. | ||||
|  * Usage is like any other node except you have to call the {@link #batch()} method once all the geometries have been attached to the sub scene graph and their material set | ||||
|  * (see todo more automagic for further enhancements) | ||||
|  * All the geometries that have been batched are set to {@link CullHint#Always} to not render them. | ||||
|  * All the geometries that have been batched are set to not be rendered - {@link CullHint} is left intact. | ||||
|  * The sub geometries can be transformed as usual, their transforms are used to update the mesh of the geometryBatch. | ||||
|  * Sub geoms can be removed but it may be slower than the normal spatial removing | ||||
|  * Sub geoms can be added after the batch() method has been called but won't be batched and will just be rendered as normal geometries. | ||||
| @ -72,7 +73,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|      */ | ||||
|     protected SafeArrayList<Batch> batches = new SafeArrayList<Batch>(Batch.class); | ||||
|     /** | ||||
|      * a map storing he batches by geometry to quickly acces the batch when updating | ||||
|      * a map for storing the batches by geometry to quickly access the batch when updating | ||||
|      */ | ||||
|     protected Map<Geometry, Batch> batchesByGeom = new HashMap<Geometry, Batch>(); | ||||
|     /** | ||||
| @ -118,7 +119,6 @@ public class BatchNode extends GeometryGroupNode { | ||||
|     public void onGeoemtryUnassociated(Geometry geom) { | ||||
|         setNeedsFullRebatch(true); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     protected Matrix4f getTransformMatrix(Geometry g){ | ||||
|         return g.cachedWorldMat; | ||||
| @ -166,7 +166,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|      */ | ||||
|     public void batch() { | ||||
|         doBatch(); | ||||
|         //we set the batch geometries to ignore transforms to avoid transforms of parent nodes to be applied twice         | ||||
|         //we set the batch geometries to ignore transforms to avoid transforms of parent nodes to be applied twice | ||||
|         for (Batch batch : batches.getArray()) { | ||||
|             batch.geometry.setIgnoreTransform(true); | ||||
|             batch.geometry.setUserData(UserData.JME_PHYSICSIGNORE, true); | ||||
| @ -174,10 +174,10 @@ public class BatchNode extends GeometryGroupNode { | ||||
|     } | ||||
| 
 | ||||
|     protected void doBatch() { | ||||
|         Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>();     | ||||
|         Map<Material, List<Geometry>> matMap = new HashMap<Material, List<Geometry>>(); | ||||
|         int nbGeoms = 0; | ||||
| 
 | ||||
|         gatherGeomerties(matMap, this, needsFullRebatch); | ||||
|         gatherGeometries(matMap, this, needsFullRebatch); | ||||
|         if (needsFullRebatch) { | ||||
|             for (Batch batch : batches.getArray()) { | ||||
|                 batch.geometry.removeFromParent(); | ||||
| @ -221,7 +221,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
| 
 | ||||
|             batch.geometry.setMesh(m); | ||||
|             batch.geometry.getMesh().updateCounts(); | ||||
|             batch.geometry.updateModelBound();             | ||||
|             batch.geometry.updateModelBound(); | ||||
|             batches.add(batch); | ||||
|         } | ||||
|         if (batches.size() > 0) { | ||||
| @ -271,7 +271,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|     } | ||||
|      | ||||
|      | ||||
|     private void gatherGeomerties(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) { | ||||
|     private void gatherGeometries(Map<Material, List<Geometry>> map, Spatial n, boolean rebatch) { | ||||
| 
 | ||||
|         if (n instanceof Geometry) { | ||||
| 
 | ||||
| @ -304,7 +304,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|                 if (child instanceof BatchNode) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 gatherGeomerties(map, child, rebatch); | ||||
|                 gatherGeometries(map, child, rebatch); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -319,7 +319,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     private boolean isBatch(Spatial s) { | ||||
|     public final boolean isBatch(Spatial s) { | ||||
|         for (Batch batch : batches.getArray()) { | ||||
|             if (batch.geometry == s) { | ||||
|                 return true; | ||||
| @ -336,9 +336,6 @@ public class BatchNode extends GeometryGroupNode { | ||||
|      */ | ||||
|     @Override | ||||
|     public void setMaterial(Material material) { | ||||
| //        for (Batch batch : batches.values()) { | ||||
| //            batch.geometry.setMaterial(material); | ||||
| //        } | ||||
|         throw new UnsupportedOperationException("Unsupported for now, please set the material on the geoms before batching"); | ||||
|     } | ||||
| 
 | ||||
| @ -356,74 +353,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|             Batch b = batches.iterator().next(); | ||||
|             return b.geometry.getMaterial(); | ||||
|         } | ||||
|         return null;//material; | ||||
|     } | ||||
| 
 | ||||
| //    /** | ||||
| //     * Sets the material to the a specific batch of this BatchNode | ||||
| //     *  | ||||
| //     *  | ||||
| //     * @param material the material to use for this geometry | ||||
| //     */    | ||||
| //    public void setMaterial(Material material,int batchIndex) { | ||||
| //        if (!batches.isEmpty()) { | ||||
| //             | ||||
| //        } | ||||
| //         | ||||
| //    } | ||||
| // | ||||
| //    /** | ||||
| //     * Returns the material that is used for the first batch of this BatchNode | ||||
| //     *  | ||||
| //     * use getMaterial(Material material,int batchIndex) to get a material from a specific batch | ||||
| //     *  | ||||
| //     * @return the material that is used for the first batch of this BatchNode | ||||
| //     *  | ||||
| //     * @see #setMaterial(com.jme3.material.Material)  | ||||
| //     */ | ||||
| //    public Material getMaterial(int batchIndex) { | ||||
| //        if (!batches.isEmpty()) { | ||||
| //            Batch b = batches.get(batches.keySet().iterator().next()); | ||||
| //            return b.geometry.getMaterial(); | ||||
| //        } | ||||
| //        return null;//material; | ||||
| //    } | ||||
|     @Override | ||||
|     public void write(JmeExporter ex) throws IOException { | ||||
|         super.write(ex); | ||||
|         OutputCapsule oc = ex.getCapsule(this); | ||||
| // | ||||
| //        if (material != null) { | ||||
| //            oc.write(material.getAssetName(), "materialName", null); | ||||
| //        } | ||||
| //        oc.write(material, "material", null); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void read(JmeImporter im) throws IOException { | ||||
|         super.read(im); | ||||
|         InputCapsule ic = im.getCapsule(this); | ||||
| 
 | ||||
| 
 | ||||
| //        material = null; | ||||
| //        String matName = ic.readString("materialName", null); | ||||
| //        if (matName != null) { | ||||
| //            // Material name is set, | ||||
| //            // Attempt to load material via J3M | ||||
| //            try { | ||||
| //                material = im.getAssetManager().loadMaterial(matName); | ||||
| //            } catch (AssetNotFoundException ex) { | ||||
| //                // Cannot find J3M file. | ||||
| //                logger.log(Level.FINE, "Could not load J3M file {0} for Geometry.", | ||||
| //                        matName); | ||||
| //            } | ||||
| //        } | ||||
| //        // If material is NULL, try to load it from the geometry | ||||
| //        if (material == null) { | ||||
| //            material = (Material) ic.readSavable("material", null); | ||||
| //        } | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -494,7 +424,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|             if (mode != null && mode != listMode) { | ||||
|                 throw new UnsupportedOperationException("Cannot combine different" | ||||
|                         + " primitive types: " + mode + " != " + listMode); | ||||
|             }             | ||||
|             } | ||||
|             mode = listMode; | ||||
|             if (mode == Mesh.Mode.Lines) { | ||||
|                 if (lineWidth != 1f && listLineWidth != lineWidth) { | ||||
| @ -510,8 +440,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|         outMesh.setMode(mode); | ||||
|         outMesh.setLineWidth(lineWidth); | ||||
|         if (totalVerts >= 65536) { | ||||
|             // make sure we create an UnsignedInt buffer so | ||||
|             // we can fit all of the meshes | ||||
|             // make sure we create an UnsignedInt buffer so we can fit all of the meshes | ||||
|             formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedInt; | ||||
|         } else { | ||||
|             formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedShort; | ||||
| @ -733,7 +662,6 @@ public class BatchNode extends GeometryGroupNode { | ||||
|     } | ||||
| 
 | ||||
|     protected class Batch { | ||||
| 
 | ||||
|         /** | ||||
|          * update the batchesByGeom map for this batch with the given List of geometries | ||||
|          * @param list  | ||||
| @ -745,7 +673,7 @@ public class BatchNode extends GeometryGroupNode { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Geometry geometry;         | ||||
|         Geometry geometry; | ||||
|     } | ||||
| 
 | ||||
|     protected void setNeedsFullRebatch(boolean needsFullRebatch) { | ||||
| @ -771,4 +699,15 @@ public class BatchNode extends GeometryGroupNode { | ||||
|         } | ||||
|         return clone; | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public int collideWith(Collidable other, CollisionResults results) { | ||||
|         int total = 0; | ||||
|         for (Spatial child : children.getArray()){ | ||||
|             if (!isBatch(child)) { | ||||
|                 total += child.collideWith(other, results); | ||||
|             } | ||||
|         } | ||||
|         return total; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -687,6 +687,11 @@ public class Node extends Spatial { | ||||
| //            childClone.parent = nodeClone; | ||||
| //            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; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -198,35 +198,42 @@ public class Curve extends Mesh { | ||||
|      * points | ||||
|      */ | ||||
|     private void createNurbMesh(int nbSubSegments) { | ||||
|         float minKnot = spline.getMinNurbKnot(); | ||||
|         float maxKnot = spline.getMaxNurbKnot(); | ||||
|         float deltaU = (maxKnot - minKnot) / nbSubSegments; | ||||
|     	if(spline.getControlPoints() != null && spline.getControlPoints().size() > 0) { | ||||
|     		if(nbSubSegments == 0) { | ||||
|         		nbSubSegments = spline.getControlPoints().size() + 1; | ||||
|         	} else { | ||||
|         		nbSubSegments = spline.getControlPoints().size() * nbSubSegments + 1; | ||||
|         	} | ||||
|             float minKnot = spline.getMinNurbKnot(); | ||||
|             float maxKnot = spline.getMaxNurbKnot(); | ||||
|             float deltaU = (maxKnot - minKnot) / nbSubSegments; | ||||
| 
 | ||||
|         float[] array = new float[(nbSubSegments + 1) * 3]; | ||||
|             float[] array = new float[(nbSubSegments + 1) * 3]; | ||||
| 
 | ||||
|         float u = minKnot; | ||||
|         Vector3f interpolationResult = new Vector3f(); | ||||
|         for (int i = 0; i < array.length; i += 3) { | ||||
|             spline.interpolate(u, 0, interpolationResult); | ||||
|             array[i] = interpolationResult.x; | ||||
|             array[i + 1] = interpolationResult.y; | ||||
|             array[i + 2] = interpolationResult.z; | ||||
|             u += deltaU; | ||||
|         } | ||||
|             float u = minKnot; | ||||
|             Vector3f interpolationResult = new Vector3f(); | ||||
|             for (int i = 0; i < array.length; i += 3) { | ||||
|                 spline.interpolate(u, 0, interpolationResult); | ||||
|                 array[i] = interpolationResult.x; | ||||
|                 array[i + 1] = interpolationResult.y; | ||||
|                 array[i + 2] = interpolationResult.z; | ||||
|                 u += deltaU; | ||||
|             } | ||||
| 
 | ||||
|         //calculating indexes | ||||
|         int i = 0; | ||||
|         short[] indices = new short[nbSubSegments << 1]; | ||||
|         for (int j = 0; j < nbSubSegments; ++j) { | ||||
|             indices[i++] = (short) j; | ||||
|             indices[i++] = (short) (j + 1); | ||||
|         } | ||||
|             //calculating indexes | ||||
|             int i = 0; | ||||
|             short[] indices = new short[nbSubSegments << 1]; | ||||
|             for (int j = 0; j < nbSubSegments; ++j) { | ||||
|                 indices[i++] = (short) j; | ||||
|                 indices[i++] = (short) (j + 1); | ||||
|             } | ||||
| 
 | ||||
|         this.setMode(Mesh.Mode.Lines); | ||||
|         this.setBuffer(VertexBuffer.Type.Position, 3, array); | ||||
|         this.setBuffer(VertexBuffer.Type.Index, 2, indices); | ||||
|         this.updateBound(); | ||||
|         this.updateCounts(); | ||||
|             this.setMode(Mesh.Mode.Lines); | ||||
|             this.setBuffer(VertexBuffer.Type.Position, 3, array); | ||||
|             this.setBuffer(VertexBuffer.Type.Index, 2, indices); | ||||
|             this.updateBound(); | ||||
|             this.updateCounts(); | ||||
|     	} | ||||
|     } | ||||
| 
 | ||||
|     private void createLinearMesh() { | ||||
|  | ||||
| @ -963,7 +963,7 @@ public final class AppSettings extends HashMap<String, Object> { | ||||
|         return getString("SettingsDialogImage"); | ||||
|     } | ||||
| 
 | ||||
|     public boolean getGammaCorrection() { | ||||
|     public boolean isGammaCorrection() { | ||||
|         return getBoolean("GammaCorrection"); | ||||
|     } | ||||
|      | ||||
|  | ||||
| @ -51,7 +51,8 @@ public class DefaultImageRaster extends ImageRaster { | ||||
|      | ||||
|     private void rangeCheck(int x, int y) { | ||||
|         if (x < 0 || y < 0 || x >= width || y >= height) { | ||||
|             throw new IllegalArgumentException("x and y must be inside the image dimensions"); | ||||
|             throw new IllegalArgumentException("x and y must be inside the image dimensions:"  | ||||
|                                                 + x + ", " + y + " in:" + width + ", " + height); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | ||||
| @ -401,6 +401,25 @@ public final class BufferUtils { | ||||
|         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. | ||||
|      *  | ||||
|  | ||||
| @ -32,11 +32,12 @@ void main(){ | ||||
|     #ifdef POINT_SPRITE | ||||
|         vec4 worldPos = g_WorldMatrix * pos; | ||||
|         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; | ||||
|         //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 | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -95,6 +95,25 @@ Gamepad\ F310\ (Controller).ry=rz | ||||
| # keeps it from confusing the .rx mapping. | ||||
| 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 | ||||
| XBOX\ 360\ For\ Windows\ (Controller).0=2 | ||||
| XBOX\ 360\ For\ Windows\ (Controller).1=1 | ||||
|  | ||||
| @ -155,7 +155,7 @@ public class TextureAtlas { | ||||
|                 return false; | ||||
|             } else { | ||||
|                 if (normal != null && normal.getKey() != null) { | ||||
|                     addTexture(diffuse, "NormalMap", keyName); | ||||
|                     addTexture(normal, "NormalMap", keyName); | ||||
|                 } | ||||
|                 if (specular != null && specular.getKey() != null) { | ||||
|                     addTexture(specular, "SpecularMap", keyName); | ||||
|  | ||||
| @ -360,7 +360,7 @@ public final class SettingsDialog extends JFrame { | ||||
|         vsyncBox.setSelected(source.isVSync()); | ||||
|          | ||||
|         gammaBox = new JCheckBox(resourceBundle.getString("checkbox.gamma")); | ||||
|         gammaBox.setSelected(source.getGammaCorrection()); | ||||
|         gammaBox.setSelected(source.isGammaCorrection()); | ||||
|          | ||||
|         gbc = new GridBagConstraints(); | ||||
|         gbc.weightx = 0.5; | ||||
|  | ||||
| @ -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(); | ||||
|         } | ||||
|          | ||||
|     } | ||||
|      | ||||
| } | ||||
| @ -65,25 +65,23 @@ public class TestManyLightsSingle extends SimpleApplication { | ||||
|         TestManyLightsSingle app = new TestManyLightsSingle(); | ||||
|         app.start(); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     /** | ||||
|      * Switch mode with space bar at run time | ||||
|      */ | ||||
|     TechniqueDef.LightMode lm = TechniqueDef.LightMode.SinglePass; | ||||
|     int lightNum = 6; | ||||
| 
 | ||||
|     @Override | ||||
|     public void simpleInitApp() { | ||||
|         renderManager.setPreferredLightMode(lm); | ||||
|         renderManager.setSinglePassLightBatchSize(lightNum); | ||||
| 
 | ||||
|         renderManager.setSinglePassLightBatchSize(6); | ||||
| 
 | ||||
|         flyCam.setMoveSpeed(10); | ||||
| 
 | ||||
|         Node scene = (Node) assetManager.loadModel("Scenes/ManyLights/Main.scene"); | ||||
|         rootNode.attachChild(scene); | ||||
|         Node n = (Node) rootNode.getChild(0); | ||||
|         LightList lightList = n.getWorldLightList(); | ||||
|         final LightList lightList = n.getWorldLightList(); | ||||
|         final Geometry g = (Geometry) n.getChild("Grid-geom-1"); | ||||
| 
 | ||||
|         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); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         flyCam.setDragToRotate(true); | ||||
|         flyCam.setMoveSpeed(50); | ||||
| 
 | ||||
| @ -168,27 +164,35 @@ public class TestManyLightsSingle extends SimpleApplication { | ||||
|                         helloText.setText("(Multi pass)"); | ||||
|                     } else { | ||||
|                         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); | ||||
|                     reloadScene(g,boxGeo,cubeNodes); | ||||
|                     reloadScene(g, boxGeo, cubeNodes); | ||||
|                 } | ||||
|                 if (name.equals("lightsUp") && isPressed) { | ||||
|                     lightNum++; | ||||
|                     renderManager.setSinglePassLightBatchSize(lightNum); | ||||
|                     helloText.setText("(Single pass) nb lights per batch : " + lightNum); | ||||
|                     renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() + 1); | ||||
|                     helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize()); | ||||
|                 } | ||||
|                 if (name.equals("lightsDown") && isPressed) { | ||||
|                     lightNum--; | ||||
|                     renderManager.setSinglePassLightBatchSize(lightNum); | ||||
|                     helloText.setText("(Single pass) nb lights per batch : " + lightNum); | ||||
|                     renderManager.setSinglePassLightBatchSize(renderManager.getSinglePassLightBatchSize() - 1); | ||||
|                     helloText.setText("(Single pass) nb lights per batch : " + renderManager.getSinglePassLightBatchSize()); | ||||
|                 } | ||||
|                 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("lightsUp", new KeyTrigger(KeyInput.KEY_UP)); | ||||
|         inputManager.addMapping("lightsDown", new KeyTrigger(KeyInput.KEY_DOWN)); | ||||
|         inputManager.addMapping("toggleOnOff", new KeyTrigger(KeyInput.KEY_L)); | ||||
| 
 | ||||
| 
 | ||||
|         SpotLight spot = new SpotLight(); | ||||
| @ -215,12 +219,9 @@ public class TestManyLightsSingle extends SimpleApplication { | ||||
|         guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); | ||||
|         helloText = new BitmapText(guiFont, false); | ||||
|         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); | ||||
|         guiNode.attachChild(helloText); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     protected void reloadScene(Geometry g, Geometry boxGeo, Node cubeNodes) { | ||||
| @ -234,7 +235,7 @@ public class TestManyLightsSingle extends SimpleApplication { | ||||
|             cubeNodes.setMaterial(m); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     BitmapText helloText; | ||||
|     long time; | ||||
|     long nbFrames; | ||||
|  | ||||
| @ -456,7 +456,7 @@ public class PhysicsVehicle extends PhysicsRigidBody { | ||||
|     /** | ||||
|      * Get the current forward vector of the vehicle in world coordinates | ||||
|      * @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 | ||||
|      */ | ||||
|     public Vector3f getForwardVector(Vector3f vector) { | ||||
|  | ||||
| @ -54,6 +54,7 @@ import com.jme3.system.AppSettings; | ||||
| import com.jme3.system.JmeContext; | ||||
| import com.jme3.system.NanoTimer; | ||||
| import com.jme3.system.NativeLibraryLoader; | ||||
| import com.jme3.system.NullRenderer; | ||||
| import com.jme3.system.SystemListener; | ||||
| import com.jme3.system.Timer; | ||||
| 
 | ||||
| @ -69,9 +70,9 @@ import com.jogamp.opengl.GLContext; | ||||
| public abstract class JoglContext implements JmeContext { | ||||
| 
 | ||||
|     private static final Logger logger = Logger.getLogger(JoglContext.class.getName()); | ||||
|      | ||||
| 
 | ||||
|     protected static final String THREAD_NAME = "jME3 Main"; | ||||
|      | ||||
| 
 | ||||
|     protected AtomicBoolean created = new AtomicBoolean(false); | ||||
|     protected AtomicBoolean renderable = new AtomicBoolean(false); | ||||
|     protected final Object createdLock = new Object(); | ||||
| @ -91,7 +92,7 @@ public abstract class JoglContext implements JmeContext { | ||||
|             NativeLibraryLoader.loadNativeLibrary("bulletjme", true); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     @Override | ||||
| 	public void setSystemListener(SystemListener listener){ | ||||
|         this.listener = listener; | ||||
| @ -101,7 +102,7 @@ public abstract class JoglContext implements JmeContext { | ||||
| 	public void setSettings(AppSettings settings) { | ||||
|         this.settings.copyFrom(settings); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     @Override | ||||
| 	public boolean isRenderable(){ | ||||
|         return renderable.get(); | ||||
| @ -160,50 +161,50 @@ public abstract class JoglContext implements JmeContext { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     protected void initContextFirstTime(){ | ||||
|         if (GLContext.getCurrent().getGLVersionNumber().getMajor() < 2) { | ||||
|             throw new RendererException("OpenGL 2.0 or higher is " +  | ||||
|             throw new RendererException("OpenGL 2.0 or higher is " + | ||||
|                                         "required for jMonkeyEngine"); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         if (settings.getRenderer().startsWith("JOGL")) { | ||||
|         	com.jme3.renderer.opengl.GL gl = new JoglGL(); | ||||
|         	GLExt glext = new JoglGLExt(); | ||||
|         	GLFbo glfbo = new JoglGLFbo(); | ||||
|              | ||||
| 
 | ||||
|             if (settings.getBoolean("GraphicsDebug")) { | ||||
|                 gl    = new GLDebugDesktop(gl, glext, glfbo); | ||||
|                 glext = (GLExt) gl; | ||||
|                 glfbo = (GLFbo) gl; | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             if (settings.getBoolean("GraphicsTiming")) { | ||||
|                 GLTimingState timingState = new GLTimingState(); | ||||
|                 gl    = (com.jme3.renderer.opengl.GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); | ||||
|                 glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); | ||||
|                 glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); | ||||
|             } | ||||
|                    | ||||
| 
 | ||||
|             if (settings.getBoolean("GraphicsTrace")) { | ||||
|                 gl    = (com.jme3.renderer.opengl.GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); | ||||
|                 glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); | ||||
|                 glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             renderer = new GLRenderer(gl, glext, glfbo); | ||||
|             renderer.initialize(); | ||||
|         } else { | ||||
|             throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer()); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         if (GLContext.getCurrentGL().isExtensionAvailable("GL_ARB_debug_output") && settings.getBoolean("GraphicsDebug")) { | ||||
|         	GLContext.getCurrent().enableGLDebugMessage(true); | ||||
|         	GLContext.getCurrent().addGLDebugListener(new JoglGLDebugOutputHandler()); | ||||
|         } | ||||
|          | ||||
|         renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); | ||||
|         renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); | ||||
| 
 | ||||
|         renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); | ||||
|         renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); | ||||
| 
 | ||||
|         // Init input | ||||
|         if (keyInput != null) { | ||||
| @ -241,7 +242,7 @@ public abstract class JoglContext implements JmeContext { | ||||
|             createdLock.notifyAll(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     protected int determineMaxSamples(int requestedSamples) { | ||||
|         GL gl = GLContext.getCurrentGL(); | ||||
|         if (gl.hasFullFBOSupport()) { | ||||
| @ -257,7 +258,7 @@ public abstract class JoglContext implements JmeContext { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     protected int getNumSamplesToUse() { | ||||
|         int samples = 0; | ||||
|         if (settings.getSamples() > 1){ | ||||
| @ -268,7 +269,7 @@ public abstract class JoglContext implements JmeContext { | ||||
|                         "Couldn''t satisfy antialiasing samples requirement: x{0}. " | ||||
|                         + "Video hardware only supports: x{1}", | ||||
|                         new Object[]{samples, supportedSamples}); | ||||
|                  | ||||
| 
 | ||||
|                 samples = supportedSamples; | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @ -29,7 +29,6 @@ | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| package com.jme3.system.lwjgl; | ||||
| 
 | ||||
| import com.jme3.input.lwjgl.JInputJoyInput; | ||||
| @ -53,6 +52,7 @@ import com.jme3.renderer.opengl.GLTiming; | ||||
| import com.jme3.renderer.opengl.GLTimingState; | ||||
| import com.jme3.renderer.opengl.GLTracer; | ||||
| import com.jme3.system.*; | ||||
| import java.io.File; | ||||
| 
 | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| import java.util.logging.Level; | ||||
| @ -69,7 +69,7 @@ public abstract class LwjglContext implements JmeContext { | ||||
|     private static final Logger logger = Logger.getLogger(LwjglContext.class.getName()); | ||||
| 
 | ||||
|     protected static final String THREAD_NAME = "jME3 Main"; | ||||
|      | ||||
| 
 | ||||
|     protected AtomicBoolean created = new AtomicBoolean(false); | ||||
|     protected AtomicBoolean renderable = new AtomicBoolean(false); | ||||
|     protected final Object createdLock = new Object(); | ||||
| @ -82,18 +82,18 @@ public abstract class LwjglContext implements JmeContext { | ||||
|     protected Timer timer; | ||||
|     protected SystemListener listener; | ||||
| 
 | ||||
|     public void setSystemListener(SystemListener listener){ | ||||
|     public void setSystemListener(SystemListener listener) { | ||||
|         this.listener = listener; | ||||
|     } | ||||
| 
 | ||||
|     protected void printContextInitInfo() { | ||||
|         logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" + | ||||
|                                " * Graphics Adapter: {2}\n" + | ||||
|                                " * Driver Version: {3}\n" + | ||||
|                                " * Scaling Factor: {4}", | ||||
|                                new Object[]{ Sys.getVersion(), Thread.currentThread().getName(),  | ||||
|                                              Display.getAdapter(), Display.getVersion(), | ||||
|                                              Display.getPixelScaleFactor() }); | ||||
|         logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" | ||||
|                 + " * Graphics Adapter: {2}\n" | ||||
|                 + " * Driver Version: {3}\n" | ||||
|                 + " * Scaling Factor: {4}", | ||||
|                 new Object[]{Sys.getVersion(), Thread.currentThread().getName(), | ||||
|                     Display.getAdapter(), Display.getVersion(), | ||||
|                     Display.getPixelScaleFactor()}); | ||||
|     } | ||||
| 
 | ||||
|     protected ContextAttribs createContextAttribs() { | ||||
| @ -113,7 +113,7 @@ public abstract class LwjglContext implements JmeContext { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     protected int determineMaxSamples(int requestedSamples) { | ||||
|         try { | ||||
|             // If we already have a valid context, determine samples using current | ||||
| @ -131,13 +131,13 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         } catch (LWJGLException ex) { | ||||
|             listener.handleError("Failed to check if display is current", ex); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0) { | ||||
|             // No pbuffer, assume everything is supported. | ||||
|             return Integer.MAX_VALUE; | ||||
|         } else { | ||||
|             Pbuffer pb = null; | ||||
|              | ||||
| 
 | ||||
|             // OpenGL2 method: Create pbuffer and query samples | ||||
|             // from GL_ARB_framebuffer_object or GL_EXT_framebuffer_multisample. | ||||
|             try { | ||||
| @ -155,13 +155,14 @@ public abstract class LwjglContext implements JmeContext { | ||||
|             } catch (LWJGLException ex) { | ||||
|                 // Something else failed. | ||||
|                 return Integer.MAX_VALUE; | ||||
|             } finally {  | ||||
|             } finally { | ||||
|                 if (pb != null) { | ||||
|                     pb.destroy(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected void loadNatives() { | ||||
|         if (JmeSystem.isLowPermissions()) { | ||||
|             return; | ||||
| @ -178,10 +179,10 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         } | ||||
|         NativeLibraryLoader.loadNativeLibrary("lwjgl", true); | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     protected int getNumSamplesToUse() { | ||||
|         int samples = 0; | ||||
|         if (settings.getSamples() > 1){ | ||||
|         if (settings.getSamples() > 1) { | ||||
|             samples = settings.getSamples(); | ||||
|             int supportedSamples = determineMaxSamples(samples); | ||||
|             if (supportedSamples < samples) { | ||||
| @ -189,62 +190,62 @@ public abstract class LwjglContext implements JmeContext { | ||||
|                         "Couldn''t satisfy antialiasing samples requirement: x{0}. " | ||||
|                         + "Video hardware only supports: x{1}", | ||||
|                         new Object[]{samples, supportedSamples}); | ||||
|                  | ||||
| 
 | ||||
|                 samples = supportedSamples; | ||||
|             } | ||||
|         } | ||||
|         return samples; | ||||
|     } | ||||
| 
 | ||||
|     protected void initContextFirstTime(){ | ||||
|     protected void initContextFirstTime() { | ||||
|         if (!GLContext.getCapabilities().OpenGL20) { | ||||
|             throw new RendererException("OpenGL 2.0 or higher is " +  | ||||
|                                         "required for jMonkeyEngine"); | ||||
|             throw new RendererException("OpenGL 2.0 or higher is " | ||||
|                     + "required for jMonkeyEngine"); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL2) | ||||
|          || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) { | ||||
|                 || settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) { | ||||
|             GL gl = new LwjglGL(); | ||||
|             GLExt glext = new LwjglGLExt(); | ||||
|             GLFbo glfbo; | ||||
|              | ||||
| 
 | ||||
|             if (GLContext.getCapabilities().OpenGL30) { | ||||
|                 glfbo = new LwjglGLFboGL3(); | ||||
|             } else { | ||||
|                 glfbo = new LwjglGLFboEXT(); | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             if (settings.getBoolean("GraphicsDebug")) { | ||||
|                 gl    = new GLDebugDesktop(gl, glext, glfbo); | ||||
|                 gl = new GLDebugDesktop(gl, glext, glfbo); | ||||
|                 glext = (GLExt) gl; | ||||
|                 glfbo = (GLFbo) gl; | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             if (settings.getBoolean("GraphicsTiming")) { | ||||
|                 GLTimingState timingState = new GLTimingState(); | ||||
|                 gl    = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); | ||||
|                 gl = (GL) GLTiming.createGLTiming(gl, timingState, GL.class, GL2.class, GL3.class, GL4.class); | ||||
|                 glext = (GLExt) GLTiming.createGLTiming(glext, timingState, GLExt.class); | ||||
|                 glfbo = (GLFbo) GLTiming.createGLTiming(glfbo, timingState, GLFbo.class); | ||||
|             } | ||||
|                    | ||||
| 
 | ||||
|             if (settings.getBoolean("GraphicsTrace")) { | ||||
|                 gl    = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); | ||||
|                 gl = (GL) GLTracer.createDesktopGlTracer(gl, GL.class, GL2.class, GL3.class, GL4.class); | ||||
|                 glext = (GLExt) GLTracer.createDesktopGlTracer(glext, GLExt.class); | ||||
|                 glfbo = (GLFbo) GLTracer.createDesktopGlTracer(glfbo, GLFbo.class); | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             renderer = new GLRenderer(gl, glext, glfbo); | ||||
|             renderer.initialize(); | ||||
|         } else { | ||||
|             throw new UnsupportedOperationException("Unsupported renderer: " + settings.getRenderer()); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         if (GLContext.getCapabilities().GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) { | ||||
|             ARBDebugOutput.glDebugMessageCallbackARB(new ARBDebugOutputCallback(new LwjglGLDebugOutputHandler())); | ||||
|         } | ||||
|          | ||||
|         renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); | ||||
|         renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); | ||||
| 
 | ||||
|         renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); | ||||
|         renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); | ||||
| 
 | ||||
|         // Init input | ||||
|         if (keyInput != null) { | ||||
| @ -260,42 +261,42 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void internalDestroy(){ | ||||
|     public void internalDestroy() { | ||||
|         renderer = null; | ||||
|         timer = null; | ||||
|         renderable.set(false); | ||||
|         synchronized (createdLock){ | ||||
|         synchronized (createdLock) { | ||||
|             created.set(false); | ||||
|             createdLock.notifyAll(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public void internalCreate(){ | ||||
| 
 | ||||
|     public void internalCreate() { | ||||
|         timer = new LwjglTimer(); | ||||
|          | ||||
|         synchronized (createdLock){ | ||||
| 
 | ||||
|         synchronized (createdLock) { | ||||
|             created.set(true); | ||||
|             createdLock.notifyAll(); | ||||
|         } | ||||
|          | ||||
|         if (renderable.get()){ | ||||
| 
 | ||||
|         if (renderable.get()) { | ||||
|             initContextFirstTime(); | ||||
|         }else{ | ||||
|         } else { | ||||
|             assert getType() == Type.Canvas; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void create(){ | ||||
|     public void create() { | ||||
|         create(false); | ||||
|     } | ||||
| 
 | ||||
|     public void destroy(){ | ||||
|     public void destroy() { | ||||
|         destroy(false); | ||||
|     } | ||||
| 
 | ||||
|     protected void waitFor(boolean createdVal){ | ||||
|         synchronized (createdLock){ | ||||
|             while (created.get() != createdVal){ | ||||
|     protected void waitFor(boolean createdVal) { | ||||
|         synchronized (createdLock) { | ||||
|             while (created.get() != createdVal) { | ||||
|                 try { | ||||
|                     createdLock.wait(); | ||||
|                 } catch (InterruptedException ex) { | ||||
| @ -304,11 +305,11 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public boolean isCreated(){ | ||||
|     public boolean isCreated() { | ||||
|         return created.get(); | ||||
|     } | ||||
|      | ||||
|     public boolean isRenderable(){ | ||||
| 
 | ||||
|     public boolean isRenderable() { | ||||
|         return renderable.get(); | ||||
|     } | ||||
| 
 | ||||
| @ -316,7 +317,7 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         this.settings.copyFrom(settings); | ||||
|     } | ||||
| 
 | ||||
|     public AppSettings getSettings(){ | ||||
|     public AppSettings getSettings() { | ||||
|         return settings; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -2,14 +2,14 @@ if (!hasProperty('mainClass')) { | ||||
|     ext.mainClass = '' | ||||
| } | ||||
| 
 | ||||
| repositories { | ||||
|     maven { | ||||
|         url "https://oss.sonatype.org/content/repositories/snapshots" | ||||
|     } | ||||
| } | ||||
| def lwjglVersion = '3.0.0b' | ||||
| 
 | ||||
| dependencies { | ||||
|     compile project(':jme3-core') | ||||
|     compile project(':jme3-desktop') | ||||
|     compile files('lib/lwjgl-3.0.0b-35.jar', 'lib/lwjgl-3.0.0b-35-natives.jar') | ||||
| } | ||||
| 
 | ||||
|     compile "org.lwjgl:lwjgl:${lwjglVersion}" | ||||
|     compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-windows" | ||||
|     compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-linux" | ||||
|     compile "org.lwjgl:lwjgl-platform:${lwjglVersion}:natives-osx" | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -32,32 +32,38 @@ | ||||
| package com.jme3.audio.lwjgl; | ||||
| 
 | ||||
| import com.jme3.audio.openal.ALC; | ||||
| import java.nio.IntBuffer; | ||||
| import org.lwjgl.openal.ALC10; | ||||
| import org.lwjgl.openal.ALContext; | ||||
| import org.lwjgl.openal.ALDevice; | ||||
| 
 | ||||
| import java.nio.IntBuffer; | ||||
| 
 | ||||
| import static org.lwjgl.openal.ALC10.alcGetContextsDevice; | ||||
| import static org.lwjgl.openal.ALC10.alcGetCurrentContext; | ||||
| import org.lwjgl.openal.SOFTPauseDevice; | ||||
| 
 | ||||
| public class LwjglALC implements ALC { | ||||
| 
 | ||||
|     private ALDevice device; | ||||
|     private ALContext context; | ||||
| 
 | ||||
|     private long contextId; | ||||
|     private long deviceId; | ||||
| 
 | ||||
|     public void createALC() { | ||||
|         device = ALDevice.create(); | ||||
|         context = ALContext.create(device); | ||||
|         context.makeCurrent(); | ||||
| 
 | ||||
|         contextId = ALC10.alcGetCurrentContext(); | ||||
|         deviceId = ALC10.alcGetContextsDevice(contextId); | ||||
|     } | ||||
| 
 | ||||
|     public void destroyALC() { | ||||
|         if (context != null) { | ||||
|             context.destroy(); | ||||
|             context = null; | ||||
|         } | ||||
| 
 | ||||
|         if (device != null) { | ||||
|             device.destroy(); | ||||
|             device = null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -66,31 +72,29 @@ public class LwjglALC implements ALC { | ||||
|     } | ||||
| 
 | ||||
|     public String alcGetString(final int parameter) { | ||||
|         final long context = alcGetCurrentContext(); | ||||
|         final long device = alcGetContextsDevice(context); | ||||
|         return ALC10.alcGetString(device, parameter); | ||||
|         return ALC10.alcGetString(deviceId, parameter); | ||||
|     } | ||||
| 
 | ||||
|     public boolean alcIsExtensionPresent(final String extension) { | ||||
|         final long context = alcGetCurrentContext(); | ||||
|         final long device = alcGetContextsDevice(context); | ||||
|         return ALC10.alcIsExtensionPresent(device, extension); | ||||
|         return ALC10.alcIsExtensionPresent(deviceId, extension); | ||||
|     } | ||||
| 
 | ||||
|     public void alcGetInteger(final int param, final IntBuffer buffer, final int size) { | ||||
|         if (buffer.position() != 0) throw new AssertionError(); | ||||
|         if (buffer.limit() != size) throw new AssertionError(); | ||||
| 
 | ||||
|         final long context = alcGetCurrentContext(); | ||||
|         final long device = alcGetContextsDevice(context); | ||||
|         final int value = ALC10.alcGetInteger(device, param); | ||||
|         //buffer.put(value); | ||||
|         if (buffer.position() != 0) { | ||||
|             throw new AssertionError(); | ||||
|         } | ||||
|         if (buffer.limit() != size) { | ||||
|             throw new AssertionError(); | ||||
|         } | ||||
|         ALC10.alcGetIntegerv(deviceId, param, buffer); | ||||
|     } | ||||
| 
 | ||||
|     public void alcDevicePauseSOFT() { | ||||
|         SOFTPauseDevice.alcDevicePauseSOFT(deviceId); | ||||
|     } | ||||
| 
 | ||||
|     public void alcDeviceResumeSOFT() { | ||||
|         SOFTPauseDevice.alcDeviceResumeSOFT(deviceId); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -66,7 +66,8 @@ public class GlfwKeyInput implements KeyInput { | ||||
|         glfwSetKeyCallback(context.getWindowHandle(), keyCallback = new GLFWKeyCallback() { | ||||
|             @Override | ||||
|             public void invoke(long window, int key, int scancode, int action, int mods) { | ||||
|                 final KeyInputEvent evt = new KeyInputEvent(scancode, (char) key, GLFW_PRESS == action, GLFW_REPEAT == action); | ||||
|                 int jmeKey = GlfwKeyMap.toJmeKeyCode(key); | ||||
|                 final KeyInputEvent evt = new KeyInputEvent(jmeKey, (char) key, GLFW_PRESS == action, GLFW_REPEAT == action); | ||||
|                 evt.setTime(getInputTimeNanos()); | ||||
|                 keyInputEvents.add(evt); | ||||
|             } | ||||
|  | ||||
							
								
								
									
										171
									
								
								jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								jme3-lwjgl3/src/main/java/com/jme3/input/lwjgl/GlfwKeyMap.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,171 @@ | ||||
| /* | ||||
|  * Copyright (c) 2009-2015 jMonkeyEngine | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are | ||||
|  * met: | ||||
|  * | ||||
|  * * Redistributions of source code must retain the above copyright | ||||
|  *   notice, this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * * Redistributions in binary form must reproduce the above copyright | ||||
|  *   notice, this list of conditions and the following disclaimer in the | ||||
|  *   documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors | ||||
|  *   may be used to endorse or promote products derived from this software | ||||
|  *   without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||||
|  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
|  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||||
|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||||
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||||
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| package com.jme3.input.lwjgl; | ||||
| 
 | ||||
| import static org.lwjgl.glfw.GLFW.*; | ||||
| import static com.jme3.input.KeyInput.*; | ||||
| 
 | ||||
| public class GlfwKeyMap { | ||||
| 
 | ||||
|     private static final int[] glfwToJmeKeyMap = new int[GLFW_KEY_LAST + 1]; | ||||
| 
 | ||||
|     private static void reg(int jmeKey, int glfwKey) { | ||||
|         glfwToJmeKeyMap[glfwKey] = jmeKey; | ||||
|     } | ||||
| 
 | ||||
|     static { | ||||
|         reg(KEY_ESCAPE, GLFW_KEY_ESCAPE); | ||||
|         reg(KEY_1, GLFW_KEY_1); | ||||
|         reg(KEY_2, GLFW_KEY_2); | ||||
|         reg(KEY_3, GLFW_KEY_3); | ||||
|         reg(KEY_4, GLFW_KEY_4); | ||||
|         reg(KEY_5, GLFW_KEY_5); | ||||
|         reg(KEY_6, GLFW_KEY_6); | ||||
|         reg(KEY_7, GLFW_KEY_7); | ||||
|         reg(KEY_8, GLFW_KEY_8); | ||||
|         reg(KEY_9, GLFW_KEY_9); | ||||
|         reg(KEY_0, GLFW_KEY_0); | ||||
|         reg(KEY_MINUS, GLFW_KEY_MINUS); | ||||
|         reg(KEY_EQUALS, GLFW_KEY_EQUAL); | ||||
|         reg(KEY_BACK, GLFW_KEY_BACKSPACE); | ||||
|         reg(KEY_TAB, GLFW_KEY_TAB); | ||||
|         reg(KEY_Q, GLFW_KEY_Q); | ||||
|         reg(KEY_W, GLFW_KEY_W); | ||||
|         reg(KEY_E, GLFW_KEY_E); | ||||
|         reg(KEY_R, GLFW_KEY_R); | ||||
|         reg(KEY_T, GLFW_KEY_T); | ||||
|         reg(KEY_Y, GLFW_KEY_Y); | ||||
|         reg(KEY_U, GLFW_KEY_U); | ||||
|         reg(KEY_I, GLFW_KEY_I); | ||||
|         reg(KEY_O, GLFW_KEY_O); | ||||
|         reg(KEY_P, GLFW_KEY_P); | ||||
|         reg(KEY_LBRACKET, GLFW_KEY_LEFT_BRACKET); | ||||
|         reg(KEY_RBRACKET, GLFW_KEY_RIGHT_BRACKET); | ||||
|         reg(KEY_RETURN, GLFW_KEY_ENTER); | ||||
|         reg(KEY_LCONTROL, GLFW_KEY_LEFT_CONTROL); | ||||
|         reg(KEY_A, GLFW_KEY_A); | ||||
|         reg(KEY_S, GLFW_KEY_S); | ||||
|         reg(KEY_D, GLFW_KEY_D); | ||||
|         reg(KEY_F, GLFW_KEY_F); | ||||
|         reg(KEY_G, GLFW_KEY_G); | ||||
|         reg(KEY_H, GLFW_KEY_H); | ||||
|         reg(KEY_J, GLFW_KEY_J); | ||||
|         reg(KEY_K, GLFW_KEY_K); | ||||
|         reg(KEY_L, GLFW_KEY_L); | ||||
|         reg(KEY_SEMICOLON, GLFW_KEY_SEMICOLON); | ||||
|         reg(KEY_APOSTROPHE, GLFW_KEY_APOSTROPHE); | ||||
|         reg(KEY_GRAVE, GLFW_KEY_GRAVE_ACCENT); | ||||
|         reg(KEY_LSHIFT, GLFW_KEY_LEFT_SHIFT); | ||||
|         reg(KEY_BACKSLASH, GLFW_KEY_BACKSLASH); | ||||
|         reg(KEY_Z, GLFW_KEY_Z); | ||||
|         reg(KEY_X, GLFW_KEY_X); | ||||
|         reg(KEY_C, GLFW_KEY_C); | ||||
|         reg(KEY_V, GLFW_KEY_V); | ||||
|         reg(KEY_B, GLFW_KEY_B); | ||||
|         reg(KEY_N, GLFW_KEY_N); | ||||
|         reg(KEY_M, GLFW_KEY_M); | ||||
|         reg(KEY_COMMA, GLFW_KEY_COMMA); | ||||
|         reg(KEY_PERIOD, GLFW_KEY_PERIOD); | ||||
|         reg(KEY_SLASH, GLFW_KEY_SLASH); | ||||
|         reg(KEY_RSHIFT, GLFW_KEY_RIGHT_SHIFT); | ||||
|         reg(KEY_MULTIPLY, GLFW_KEY_KP_MULTIPLY); | ||||
|         reg(KEY_LMENU, GLFW_KEY_LEFT_ALT); | ||||
|         reg(KEY_SPACE, GLFW_KEY_SPACE); | ||||
|         reg(KEY_CAPITAL, GLFW_KEY_CAPS_LOCK); | ||||
|         reg(KEY_F1, GLFW_KEY_F1); | ||||
|         reg(KEY_F2, GLFW_KEY_F2); | ||||
|         reg(KEY_F3, GLFW_KEY_F3); | ||||
|         reg(KEY_F4, GLFW_KEY_F4); | ||||
|         reg(KEY_F5, GLFW_KEY_F5); | ||||
|         reg(KEY_F6, GLFW_KEY_F6); | ||||
|         reg(KEY_F7, GLFW_KEY_F7); | ||||
|         reg(KEY_F8, GLFW_KEY_F8); | ||||
|         reg(KEY_F9, GLFW_KEY_F9); | ||||
|         reg(KEY_F10, GLFW_KEY_F10); | ||||
|         reg(KEY_NUMLOCK, GLFW_KEY_NUM_LOCK); | ||||
|         reg(KEY_SCROLL, GLFW_KEY_SCROLL_LOCK); | ||||
|         reg(KEY_NUMPAD7, GLFW_KEY_KP_7); | ||||
|         reg(KEY_NUMPAD8, GLFW_KEY_KP_8); | ||||
|         reg(KEY_NUMPAD9, GLFW_KEY_KP_9); | ||||
|         reg(KEY_SUBTRACT, GLFW_KEY_KP_SUBTRACT); | ||||
|         reg(KEY_NUMPAD4, GLFW_KEY_KP_4); | ||||
|         reg(KEY_NUMPAD5, GLFW_KEY_KP_5); | ||||
|         reg(KEY_NUMPAD6, GLFW_KEY_KP_6); | ||||
|         reg(KEY_ADD, GLFW_KEY_KP_ADD); | ||||
|         reg(KEY_NUMPAD1, GLFW_KEY_KP_1); | ||||
|         reg(KEY_NUMPAD2, GLFW_KEY_KP_2); | ||||
|         reg(KEY_NUMPAD3, GLFW_KEY_KP_3); | ||||
|         reg(KEY_NUMPAD0, GLFW_KEY_KP_0); | ||||
|         reg(KEY_DECIMAL, GLFW_KEY_KP_DECIMAL); | ||||
|         reg(KEY_F11, GLFW_KEY_F11); | ||||
|         reg(KEY_F12, GLFW_KEY_F12); | ||||
|         reg(KEY_F13, GLFW_KEY_F13); | ||||
|         reg(KEY_F14, GLFW_KEY_F14); | ||||
|         reg(KEY_F15, GLFW_KEY_F15); | ||||
|         //reg(KEY_KANA, GLFW_KEY_); | ||||
|         //reg(KEY_CONVERT, GLFW_KEY_); | ||||
|         //reg(KEY_NOCONVERT, GLFW_KEY_); | ||||
|         //reg(KEY_YEN, GLFW_KEY_); | ||||
|         //reg(KEY_NUMPADEQUALS, GLFW_KEY_); | ||||
|         //reg(KEY_CIRCUMFLEX, GLFW_KEY_); | ||||
|         //reg(KEY_AT, GLFW_KEY_); | ||||
|         //reg(KEY_COLON, GLFW_KEY_); | ||||
|         //reg(KEY_UNDERLINE, GLFW_KEY_); | ||||
|         //reg(KEY_KANJI, GLFW_KEY_); | ||||
|         //reg(KEY_STOP, GLFW_KEY_); | ||||
|         //reg(KEY_AX, GLFW_KEY_); | ||||
|         //reg(KEY_UNLABELED, GLFW_KEY_); | ||||
|         reg(KEY_NUMPADENTER, GLFW_KEY_KP_ENTER); | ||||
|         reg(KEY_RCONTROL, GLFW_KEY_RIGHT_CONTROL); | ||||
|         //reg(KEY_NUMPADCOMMA, GLFW_KEY_); | ||||
|         reg(KEY_DIVIDE, GLFW_KEY_KP_DIVIDE); | ||||
|         reg(KEY_SYSRQ, GLFW_KEY_PRINT_SCREEN); | ||||
|         reg(KEY_RMENU, GLFW_KEY_RIGHT_ALT); | ||||
|         reg(KEY_PAUSE, GLFW_KEY_PAUSE); | ||||
|         reg(KEY_HOME, GLFW_KEY_HOME); | ||||
|         reg(KEY_UP, GLFW_KEY_UP); | ||||
|         reg(KEY_PRIOR, GLFW_KEY_PAGE_UP); | ||||
|         reg(KEY_LEFT, GLFW_KEY_LEFT); | ||||
|         reg(KEY_RIGHT, GLFW_KEY_RIGHT); | ||||
|         reg(KEY_END, GLFW_KEY_END); | ||||
|         reg(KEY_DOWN, GLFW_KEY_DOWN); | ||||
|         reg(KEY_NEXT, GLFW_KEY_PAGE_DOWN); | ||||
|         reg(KEY_INSERT, GLFW_KEY_INSERT); | ||||
|         reg(KEY_DELETE, GLFW_KEY_DELETE); | ||||
|         reg(KEY_LMETA, GLFW_KEY_LEFT_SUPER); | ||||
|         reg(KEY_RMETA, GLFW_KEY_RIGHT_SUPER); | ||||
|     } | ||||
| 
 | ||||
|     public static int toJmeKeyCode(int glfwKey) { | ||||
|         return glfwToJmeKeyMap[glfwKey]; | ||||
|     } | ||||
| } | ||||
| @ -38,16 +38,22 @@ import com.jme3.input.RawInputListener; | ||||
| import com.jme3.input.event.MouseButtonEvent; | ||||
| import com.jme3.input.event.MouseMotionEvent; | ||||
| import com.jme3.system.lwjgl.LwjglWindow; | ||||
| import com.jme3.util.BufferUtils; | ||||
| import org.lwjgl.glfw.GLFWCursorPosCallback; | ||||
| import org.lwjgl.glfw.GLFWMouseButtonCallback; | ||||
| import org.lwjgl.glfw.GLFWScrollCallback; | ||||
| 
 | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.IntBuffer; | ||||
| import java.util.HashMap; | ||||
| import java.util.LinkedList; | ||||
| import java.util.Map; | ||||
| import java.util.Queue; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| import static org.lwjgl.glfw.GLFW.*; | ||||
| import org.lwjgl.glfw.GLFWImage; | ||||
| import org.lwjgl.system.MemoryUtil; | ||||
| 
 | ||||
| /** | ||||
|  * Captures mouse input using GLFW callbacks. It then temporarily stores these in event queues which are processed in the | ||||
| @ -74,57 +80,70 @@ public class GlfwMouseInput implements MouseInput { | ||||
|     private Queue<MouseMotionEvent> mouseMotionEvents = new LinkedList<MouseMotionEvent>(); | ||||
|     private Queue<MouseButtonEvent> mouseButtonEvents = new LinkedList<MouseButtonEvent>(); | ||||
| 
 | ||||
|     public GlfwMouseInput(final LwjglWindow context) { | ||||
|     private Map<JmeCursor, Long> jmeToGlfwCursorMap = new HashMap<JmeCursor, Long>(); | ||||
| 
 | ||||
|     public GlfwMouseInput(LwjglWindow context) { | ||||
|         this.context = context; | ||||
|     } | ||||
| 
 | ||||
|     private void onCursorPos(long window, double xpos, double ypos) { | ||||
|         int xDelta; | ||||
|         int yDelta; | ||||
|         int x = (int) Math.round(xpos); | ||||
|         int y = context.getSettings().getHeight() - (int) Math.round(ypos); | ||||
| 
 | ||||
|         if (mouseX == 0) { | ||||
|             mouseX = x; | ||||
|         } | ||||
| 
 | ||||
|         if (mouseY == 0) { | ||||
|             mouseY = y; | ||||
|         } | ||||
| 
 | ||||
|         xDelta = x - mouseX; | ||||
|         yDelta = y - mouseY; | ||||
|         mouseX = x; | ||||
|         mouseY = y; | ||||
| 
 | ||||
|         if (xDelta != 0 || yDelta != 0) { | ||||
|             final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y, xDelta, yDelta, mouseWheel, 0); | ||||
|             mouseMotionEvent.setTime(getInputTimeNanos()); | ||||
|             mouseMotionEvents.add(mouseMotionEvent); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void onWheelScroll(long window, double xOffset, double yOffset) { | ||||
|         mouseWheel += yOffset; | ||||
|         final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(mouseX, mouseY, 0, 0, mouseWheel, (int) Math.round(yOffset)); | ||||
|         mouseMotionEvent.setTime(getInputTimeNanos()); | ||||
|         mouseMotionEvents.add(mouseMotionEvent); | ||||
|     } | ||||
| 
 | ||||
|     private void onMouseButton(final long window, final int button, final int action, final int mods) { | ||||
|         final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(convertButton(button), action == GLFW_PRESS, mouseX, mouseY); | ||||
|         mouseButtonEvent.setTime(getInputTimeNanos()); | ||||
|         mouseButtonEvents.add(mouseButtonEvent); | ||||
|     } | ||||
| 
 | ||||
|     public void initialize() { | ||||
|         glfwSetCursorPosCallback(context.getWindowHandle(), cursorPosCallback = new GLFWCursorPosCallback() { | ||||
|             @Override | ||||
|             public void invoke(long window, double xpos, double ypos) { | ||||
|                 int xDelta; | ||||
|                 int yDelta; | ||||
|                 int x = (int) Math.round(xpos); | ||||
|                 int y = context.getSettings().getHeight() - (int) Math.round(ypos); | ||||
| 
 | ||||
|                 if (mouseX == 0) { | ||||
|                     mouseX = x; | ||||
|                 } | ||||
| 
 | ||||
|                 if (mouseY == 0) { | ||||
|                     mouseY = y; | ||||
|                 } | ||||
| 
 | ||||
|                 xDelta = x - mouseX; | ||||
|                 yDelta = y - mouseY; | ||||
|                 mouseX = x; | ||||
|                 mouseY = y; | ||||
| 
 | ||||
|                 if (xDelta != 0 || yDelta != 0) { | ||||
|                     final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(x, y, xDelta, yDelta, mouseWheel, 0); | ||||
|                     mouseMotionEvent.setTime(getInputTimeNanos()); | ||||
|                     mouseMotionEvents.add(mouseMotionEvent); | ||||
|                 } | ||||
|                 onCursorPos(window, xpos, ypos); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         glfwSetScrollCallback(context.getWindowHandle(), scrollCallback = new GLFWScrollCallback() { | ||||
|             @Override | ||||
|             public void invoke(final long window, final double xOffset, final double yOffset) { | ||||
|                 mouseWheel += yOffset; | ||||
| 
 | ||||
|                 final MouseMotionEvent mouseMotionEvent = new MouseMotionEvent(mouseX, mouseY, 0, 0, mouseWheel, (int) Math.round(yOffset)); | ||||
|                 mouseMotionEvent.setTime(getInputTimeNanos()); | ||||
|                 mouseMotionEvents.add(mouseMotionEvent); | ||||
|                 onWheelScroll(window, xOffset, yOffset); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         glfwSetMouseButtonCallback(context.getWindowHandle(), mouseButtonCallback = new GLFWMouseButtonCallback() { | ||||
|             @Override | ||||
|             public void invoke(final long window, final int button, final int action, final int mods) { | ||||
|                 final MouseButtonEvent mouseButtonEvent = new MouseButtonEvent(convertButton(button), action == GLFW_PRESS, mouseX, mouseY); | ||||
|                 mouseButtonEvent.setTime(getInputTimeNanos()); | ||||
|                 mouseButtonEvents.add(mouseButtonEvent); | ||||
|                 onMouseButton(window, button, action, mods); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
| @ -160,6 +179,10 @@ public class GlfwMouseInput implements MouseInput { | ||||
|         scrollCallback.release(); | ||||
|         mouseButtonCallback.release(); | ||||
| 
 | ||||
|         for (long glfwCursor : jmeToGlfwCursorMap.values()) { | ||||
|             glfwDestroyCursor(glfwCursor); | ||||
|         } | ||||
| 
 | ||||
|         logger.fine("Mouse destroyed."); | ||||
|     } | ||||
| 
 | ||||
| @ -185,31 +208,52 @@ public class GlfwMouseInput implements MouseInput { | ||||
|         return (long) (glfwGetTime() * 1000000000); | ||||
|     } | ||||
| 
 | ||||
|     public void setNativeCursor(final JmeCursor jmeCursor) { | ||||
|     private long createGlfwCursor(JmeCursor jmeCursor) { | ||||
|         GLFWImage glfwImage = new GLFWImage(BufferUtils.createByteBuffer(GLFWImage.SIZEOF)); | ||||
| 
 | ||||
|         // TODO: currently animated cursors are not supported | ||||
|         IntBuffer imageData = jmeCursor.getImagesData(); | ||||
|         ByteBuffer buf = BufferUtils.createByteBuffer(imageData.capacity()); | ||||
|         buf.asIntBuffer().put(imageData); | ||||
| 
 | ||||
|         glfwImage.set(jmeCursor.getWidth(), jmeCursor.getHeight(), buf); | ||||
| 
 | ||||
|         return glfwCreateCursor(glfwImage, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot()); | ||||
|     } | ||||
| 
 | ||||
|     public void setNativeCursor(JmeCursor jmeCursor) { | ||||
|         if (jmeCursor != null) { | ||||
|             final ByteBuffer byteBuffer = org.lwjgl.BufferUtils.createByteBuffer(jmeCursor.getImagesData().capacity()); | ||||
|             byteBuffer.asIntBuffer().put(jmeCursor.getImagesData().array()); | ||||
|             final long cursor = glfwCreateCursor(byteBuffer, jmeCursor.getXHotSpot(), jmeCursor.getYHotSpot()); | ||||
|             glfwSetCursor(context.getWindowHandle(), cursor); | ||||
|             Long glfwCursor = jmeToGlfwCursorMap.get(jmeCursor); | ||||
| 
 | ||||
|             if (glfwCursor == null) { | ||||
|                 glfwCursor = createGlfwCursor(jmeCursor); | ||||
|                 jmeToGlfwCursorMap.put(jmeCursor, glfwCursor); | ||||
|             } | ||||
| 
 | ||||
|             glfwSetCursor(context.getWindowHandle(), glfwCursor); | ||||
|         } else { | ||||
|             glfwSetCursor(context.getWindowHandle(), MemoryUtil.NULL); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Simply converts the GLFW button code to a JME button code. If there is no match it just returns the GLFW button | ||||
|      * code. Bare in mind GLFW supports 8 different mouse buttons. | ||||
|      * Simply converts the GLFW button code to a JME button code. If there is no | ||||
|      * match it just returns the GLFW button code. Bear in mind GLFW supports 8 | ||||
|      * different mouse buttons. | ||||
|      * | ||||
|      * @param glfwButton the raw GLFW button index. | ||||
|      * @return the mapped {@link MouseInput} button id. | ||||
|      */ | ||||
|     private int convertButton(final int glfwButton) { | ||||
|         if (glfwButton == GLFW_MOUSE_BUTTON_LEFT) { | ||||
|             return MouseInput.BUTTON_LEFT; | ||||
|         } else if(glfwButton == GLFW_MOUSE_BUTTON_MIDDLE) { | ||||
|             return MouseInput.BUTTON_MIDDLE; | ||||
|         } else if(glfwButton == GLFW_MOUSE_BUTTON_RIGHT) { | ||||
|             return MouseInput.BUTTON_RIGHT; | ||||
|         switch (glfwButton) { | ||||
|             case GLFW_MOUSE_BUTTON_LEFT: | ||||
|                 return MouseInput.BUTTON_LEFT; | ||||
|             case GLFW_MOUSE_BUTTON_MIDDLE: | ||||
|                 return MouseInput.BUTTON_MIDDLE; | ||||
|             case GLFW_MOUSE_BUTTON_RIGHT: | ||||
|                 return MouseInput.BUTTON_RIGHT; | ||||
|             default: | ||||
|                 return glfwButton; | ||||
|         } | ||||
| 
 | ||||
|         return glfwButton; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -43,9 +43,7 @@ import com.jme3.renderer.lwjgl.LwjglGLFboEXT; | ||||
| import com.jme3.renderer.lwjgl.LwjglGLFboGL3; | ||||
| import com.jme3.renderer.opengl.*; | ||||
| import com.jme3.system.*; | ||||
| import org.lwjgl.Sys; | ||||
| import org.lwjgl.glfw.GLFW; | ||||
| import org.lwjgl.opengl.ARBDebugOutput; | ||||
| import org.lwjgl.opengl.ARBFramebufferObject; | ||||
| import org.lwjgl.opengl.EXTFramebufferMultisample; | ||||
| import org.lwjgl.opengl.GLCapabilities; | ||||
| @ -53,9 +51,10 @@ import org.lwjgl.opengl.GLCapabilities; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| import static org.lwjgl.glfw.GLFW.GLFW_TRUE; | ||||
| import org.lwjgl.opengl.ARBDebugOutput; | ||||
| 
 | ||||
| import static org.lwjgl.opengl.GL.createCapabilities; | ||||
| import static org.lwjgl.opengl.GL11.GL_TRUE; | ||||
| import static org.lwjgl.opengl.GL11.glGetInteger; | ||||
| 
 | ||||
| /** | ||||
| @ -84,16 +83,16 @@ public abstract class LwjglContext implements JmeContext { | ||||
|     } | ||||
| 
 | ||||
|     protected void printContextInitInfo() { | ||||
|         logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" + | ||||
|                         " * Graphics Adapter: GLFW {2}", | ||||
|                 new Object[]{Sys.getVersion(), Thread.currentThread().getName(), GLFW.glfwGetVersionString()}); | ||||
|         logger.log(Level.INFO, "LWJGL {0} context running on thread {1}\n" | ||||
|                 + " * Graphics Adapter: GLFW {2}", | ||||
|                 new Object[]{org.lwjgl.Version.getVersion(), Thread.currentThread().getName(), GLFW.glfwGetVersionString()}); | ||||
|     } | ||||
| 
 | ||||
|     protected int determineMaxSamples() { | ||||
|         // If we already have a valid context, determine samples using current context. | ||||
|         if (GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object") == GL_TRUE) { | ||||
|         if (GLFW.glfwExtensionSupported("GL_ARB_framebuffer_object") == GLFW_TRUE) { | ||||
|             return glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES); | ||||
|         } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GL_TRUE) { | ||||
|         } else if (GLFW.glfwExtensionSupported("GL_EXT_framebuffer_multisample") == GLFW_TRUE) { | ||||
|             return glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT); | ||||
|         } | ||||
| 
 | ||||
| @ -180,11 +179,11 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         } | ||||
| 
 | ||||
|         if (capabilities.GL_ARB_debug_output && settings.getBoolean("GraphicsDebug")) { | ||||
|             ARBDebugOutput.glDebugMessageCallbackARB(new LwjglGLDebugOutputHandler(), 0); // User param is zero. Not sure what we could use that for. | ||||
|             ARBDebugOutput.glDebugMessageCallbackARB(new LwjglGLDebugOutputHandler(), 0); | ||||
|         } | ||||
| 
 | ||||
|         renderer.setMainFrameBufferSrgb(settings.getGammaCorrection()); | ||||
|         renderer.setLinearizeSrgbImages(settings.getGammaCorrection()); | ||||
|         renderer.setMainFrameBufferSrgb(settings.isGammaCorrection()); | ||||
|         renderer.setLinearizeSrgbImages(settings.isGammaCorrection()); | ||||
| 
 | ||||
|         // Init input | ||||
|         if (keyInput != null) { | ||||
| @ -198,7 +197,6 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         if (joyInput != null) { | ||||
|             joyInput.initialize(); | ||||
|         } | ||||
| 
 | ||||
|         renderable.set(true); | ||||
|     } | ||||
| 
 | ||||
| @ -240,26 +238,32 @@ public abstract class LwjglContext implements JmeContext { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isCreated() { | ||||
|         return created.get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isRenderable() { | ||||
|         return renderable.get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setSettings(AppSettings settings) { | ||||
|         this.settings.copyFrom(settings); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public AppSettings getSettings() { | ||||
|         return settings; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Renderer getRenderer() { | ||||
|         return renderer; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Timer getTimer() { | ||||
|         return timer; | ||||
|     } | ||||
|  | ||||
| @ -43,7 +43,6 @@ import com.jme3.system.AppSettings; | ||||
| import com.jme3.system.JmeContext; | ||||
| import com.jme3.system.JmeSystem; | ||||
| import com.jme3.system.NanoTimer; | ||||
| import org.lwjgl.Sys; | ||||
| import org.lwjgl.glfw.*; | ||||
| 
 | ||||
| import java.awt.*; | ||||
| @ -52,6 +51,7 @@ import java.nio.ByteBuffer; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| import org.lwjgl.Version; | ||||
| 
 | ||||
| import static org.lwjgl.glfw.GLFW.*; | ||||
| import static org.lwjgl.opengl.GL11.GL_FALSE; | ||||
| @ -72,7 +72,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|     protected boolean wasActive = false; | ||||
|     protected boolean autoFlush = true; | ||||
|     protected boolean allowSwapBuffers = false; | ||||
|     private long window = -1; | ||||
|     private long window = NULL; | ||||
|     private final JmeContext.Type type; | ||||
|     private int frameRateLimit = -1; | ||||
|     private double frameSleepTime; | ||||
| @ -102,7 +102,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|      * @param title the title to set | ||||
|      */ | ||||
|     public void setTitle(final String title) { | ||||
|         if (created.get() && window != -1) { | ||||
|         if (created.get() && window != NULL) { | ||||
|             glfwSetWindowTitle(window, title); | ||||
|         } | ||||
|     } | ||||
| @ -127,45 +127,45 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|         glfwSetErrorCallback(errorCallback = new GLFWErrorCallback() { | ||||
|             @Override | ||||
|             public void invoke(int error, long description) { | ||||
|                 final String message = Callbacks.errorCallbackDescriptionString(description); | ||||
|                 final String message = GLFWErrorCallback.getDescription(description); | ||||
|                 listener.handleError(message, new Exception(message)); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         if (glfwInit() != GL_TRUE) { | ||||
|         if (glfwInit() != GLFW_TRUE) { | ||||
|             throw new IllegalStateException("Unable to initialize GLFW"); | ||||
|         } | ||||
| 
 | ||||
|         glfwDefaultWindowHints(); | ||||
| 
 | ||||
|         if (settings.getRenderer().equals(AppSettings.LWJGL_OPENGL3)) { | ||||
|             glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | ||||
|             glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); | ||||
|             glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | ||||
|             glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); | ||||
|         } else { | ||||
|             glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); | ||||
|             glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); | ||||
|         } | ||||
| 
 | ||||
|         if (settings.getBoolean("RendererDebug")) { | ||||
|             glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); | ||||
|         } | ||||
| 
 | ||||
|         if (settings.isGammaCorrection()) { | ||||
|             glfwWindowHint(GLFW_SRGB_CAPABLE, GLFW_TRUE); | ||||
|         } | ||||
| 
 | ||||
|         glfwWindowHint(GLFW_VISIBLE, GL_FALSE); | ||||
|         glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GLFW_TRUE : GLFW_FALSE); | ||||
| 
 | ||||
|         // TODO: Add support for monitor selection | ||||
|         long monitor = NULL; | ||||
| 
 | ||||
|         if (settings.isFullscreen()) { | ||||
|             monitor = glfwGetPrimaryMonitor(); | ||||
|         } | ||||
| 
 | ||||
|         final ByteBuffer videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | ||||
| 
 | ||||
|         if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { | ||||
|             settings.setResolution(GLFWvidmode.width(videoMode), GLFWvidmode.height(videoMode)); | ||||
|         } | ||||
| 
 | ||||
|         window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); | ||||
| 
 | ||||
|         if (window == NULL) { | ||||
|             throw new RuntimeException("Failed to create the GLFW window"); | ||||
|         } | ||||
| 
 | ||||
|         glfwWindowHint(GLFW_RESIZABLE, settings.isResizable() ? GL_TRUE : GL_FALSE); | ||||
|         glfwWindowHint(GLFW_DOUBLE_BUFFER, GLFW_TRUE); | ||||
|         glfwWindowHint(GLFW_DEPTH_BITS, settings.getDepthBits()); | ||||
|         glfwWindowHint(GLFW_STENCIL_BITS, settings.getStencilBits()); | ||||
|         glfwWindowHint(GLFW_SAMPLES, settings.getSamples()); | ||||
|         glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GL_TRUE : GL_FALSE); | ||||
|         glfwWindowHint(GLFW_STEREO, settings.useStereo3D() ? GLFW_TRUE : GLFW_FALSE); | ||||
|         glfwWindowHint(GLFW_REFRESH_RATE, settings.getFrequency()); | ||||
| 
 | ||||
|         // Not sure how else to support bits per pixel | ||||
|         if (settings.getBitsPerPixel() == 24) { | ||||
|             glfwWindowHint(GLFW_RED_BITS, 8); | ||||
|             glfwWindowHint(GLFW_GREEN_BITS, 8); | ||||
| @ -178,6 +178,34 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
| 
 | ||||
|         glfwWindowHint(GLFW_ALPHA_BITS, settings.getAlphaBits()); | ||||
| 
 | ||||
|         // TODO: Add support for monitor selection | ||||
|         long monitor = NULL; | ||||
| 
 | ||||
|         if (settings.isFullscreen()) { | ||||
|             monitor = glfwGetPrimaryMonitor(); | ||||
|         } | ||||
| 
 | ||||
|         final GLFWVidMode videoMode = glfwGetVideoMode(glfwGetPrimaryMonitor()); | ||||
| 
 | ||||
|         if (settings.getWidth() <= 0 || settings.getHeight() <= 0) { | ||||
|             settings.setResolution(videoMode.width(), videoMode.height()); | ||||
|         } | ||||
| 
 | ||||
|         window = glfwCreateWindow(settings.getWidth(), settings.getHeight(), settings.getTitle(), monitor, NULL); | ||||
| 
 | ||||
|         if (window == NULL) { | ||||
|             throw new RuntimeException("Failed to create the GLFW window"); | ||||
|         } | ||||
| 
 | ||||
|         // Add a resize callback which delegates to the listener | ||||
|         glfwSetWindowSizeCallback(window, windowSizeCallback = new GLFWWindowSizeCallback() { | ||||
|             @Override | ||||
|             public void invoke(final long window, final int width, final int height) { | ||||
|                 settings.setResolution(width, height); | ||||
|                 listener.reshape(width, height); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         glfwSetWindowFocusCallback(window, windowFocusCallback = new GLFWWindowFocusCallback() { | ||||
|             @Override | ||||
|             public void invoke(final long window, final int focused) { | ||||
| @ -197,8 +225,10 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|         }); | ||||
| 
 | ||||
|         // Center the window | ||||
|         if (!settings.isFullscreen() && Type.Display.equals(type)) { | ||||
|             glfwSetWindowPos(window, (GLFWvidmode.width(videoMode) - settings.getWidth()) / 2, (GLFWvidmode.height(videoMode) - settings.getHeight()) / 2); | ||||
|         if (!settings.isFullscreen()) { | ||||
|             glfwSetWindowPos(window, | ||||
|                     (videoMode.width() - settings.getWidth()) / 2, | ||||
|                     (videoMode.height() - settings.getHeight()) / 2); | ||||
|         } | ||||
| 
 | ||||
|         // Make the OpenGL context current | ||||
| @ -216,14 +246,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|             glfwShowWindow(window); | ||||
|         } | ||||
| 
 | ||||
|         // Add a resize callback which delegates to the listener | ||||
|         glfwSetWindowSizeCallback(window, windowSizeCallback = new GLFWWindowSizeCallback() { | ||||
|             @Override | ||||
|             public void invoke(final long window, final int width, final int height) { | ||||
|                 settings.setResolution(width, height); | ||||
|                 listener.reshape(width, height); | ||||
|             } | ||||
|         }); | ||||
|         glfwShowWindow(window); | ||||
| 
 | ||||
|         allowSwapBuffers = settings.isSwapBuffers(); | ||||
| 
 | ||||
| @ -239,12 +262,24 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|                 renderer.cleanup(); | ||||
|             } | ||||
| 
 | ||||
|             errorCallback.release(); | ||||
|             windowSizeCallback.release(); | ||||
|             windowFocusCallback.release(); | ||||
|             if (errorCallback != null) { | ||||
|                 errorCallback.release(); | ||||
|                 errorCallback = null; | ||||
|             } | ||||
| 
 | ||||
|             if (window != 0) { | ||||
|             if (windowSizeCallback != null) { | ||||
|                 windowSizeCallback.release(); | ||||
|                 windowSizeCallback = null; | ||||
|             } | ||||
| 
 | ||||
|             if (windowFocusCallback != null) { | ||||
|                 windowFocusCallback.release(); | ||||
|                 windowFocusCallback = null; | ||||
|             } | ||||
| 
 | ||||
|             if (window != NULL) { | ||||
|                 glfwDestroyWindow(window); | ||||
|                 window = NULL; | ||||
|             } | ||||
|         } catch (Exception ex) { | ||||
|             listener.handleError("Failed to destroy context", ex); | ||||
| @ -296,8 +331,9 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|             super.internalCreate(); | ||||
|         } catch (Exception ex) { | ||||
|             try { | ||||
|                 if (window != -1) { | ||||
|                 if (window != NULL) { | ||||
|                     glfwDestroyWindow(window); | ||||
|                     window = NULL; | ||||
|                 } | ||||
|             } catch (Exception ex2) { | ||||
|                 LOGGER.log(Level.WARNING, null, ex2); | ||||
| @ -318,6 +354,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|         // If a restart is required, lets recreate the context. | ||||
|         if (needRestart.getAndSet(false)) { | ||||
|             try { | ||||
|                 destroyContext(); | ||||
|                 createContext(settings); | ||||
|             } catch (Exception ex) { | ||||
|                 LOGGER.log(Level.SEVERE, "Failed to set display settings!", ex); | ||||
| @ -346,8 +383,6 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         glfwPollEvents(); | ||||
| 
 | ||||
|         // Subclasses just call GLObjectManager clean up objects here | ||||
|         // it is safe .. for now. | ||||
|         if (renderer != null) { | ||||
| @ -377,6 +412,8 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         glfwPollEvents(); | ||||
|     } | ||||
| 
 | ||||
|     private void setFrameRateLimit(int frameRateLimit) { | ||||
| @ -389,11 +426,12 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|      */ | ||||
| 
 | ||||
|     protected void deinitInThread() { | ||||
|         destroyContext(); | ||||
| 
 | ||||
|         listener.destroy(); | ||||
|         LOGGER.fine("Display destroyed."); | ||||
| 
 | ||||
|         destroyContext(); | ||||
|         super.internalDestroy(); | ||||
| 
 | ||||
|         LOGGER.fine("Display destroyed."); | ||||
|     } | ||||
| 
 | ||||
|     public void run() { | ||||
| @ -403,7 +441,7 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|         } | ||||
| 
 | ||||
|         loadNatives(); | ||||
|         LOGGER.log(Level.FINE, "Using LWJGL {0}", Sys.getVersion()); | ||||
|         LOGGER.log(Level.FINE, "Using LWJGL {0}", Version.getVersion()); | ||||
| 
 | ||||
|         if (!initInThread()) { | ||||
|             LOGGER.log(Level.SEVERE, "Display initialization failed. Cannot continue."); | ||||
| @ -411,15 +449,16 @@ public abstract class LwjglWindow extends LwjglContext implements Runnable { | ||||
|         } | ||||
| 
 | ||||
|         while (true) { | ||||
|             if (glfwWindowShouldClose(window) == GL_TRUE) { | ||||
|                 listener.requestClose(false); | ||||
|             } | ||||
| 
 | ||||
|             runLoop(); | ||||
| 
 | ||||
|             if (needClose.get()) { | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if (glfwWindowShouldClose(window) == GL_TRUE) { | ||||
|                 listener.requestClose(false); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         deinitInThread(); | ||||
|  | ||||
| @ -301,35 +301,38 @@ public class DefaultClient implements Client | ||||
| 
 | ||||
|     protected void closeConnections( DisconnectInfo info ) | ||||
|     { | ||||
|         if( !isRunning ) | ||||
|             return; | ||||
|         synchronized(this) { | ||||
|             if( !isRunning ) | ||||
|                 return; | ||||
| 
 | ||||
|         if( services.isStarted() ) { | ||||
|             // Let the services get a chance to stop before we | ||||
|             // kill the connection. | ||||
|             services.stop(); | ||||
|         } | ||||
|             if( services.isStarted() ) { | ||||
|                 // Let the services get a chance to stop before we | ||||
|                 // kill the connection. | ||||
|                 services.stop(); | ||||
|             } | ||||
|          | ||||
|         // Send a close message | ||||
|             // Send a close message | ||||
|      | ||||
|         // Tell the thread it's ok to die | ||||
|         for( ConnectorAdapter ca : channels ) { | ||||
|             if( ca == null ) | ||||
|                 continue; | ||||
|             ca.close(); | ||||
|             // Tell the thread it's ok to die | ||||
|             for( ConnectorAdapter ca : channels ) { | ||||
|                 if( ca == null ) | ||||
|                     continue; | ||||
|                 ca.close(); | ||||
|             } | ||||
|          | ||||
|             // Wait for the threads? | ||||
| 
 | ||||
|             // Just in case we never fully connected | ||||
|             connecting.countDown(); | ||||
|          | ||||
|             isRunning = false; | ||||
|          | ||||
|             // Terminate the services | ||||
|             services.terminate();             | ||||
|         } | ||||
|          | ||||
|         // Wait for the threads? | ||||
| 
 | ||||
|         // Just in case we never fully connected | ||||
|         connecting.countDown(); | ||||
|          | ||||
|         fireDisconnected(info); | ||||
|          | ||||
|         isRunning = false; | ||||
|          | ||||
|         // Terminate the services | ||||
|         services.terminate();             | ||||
|         // Make sure we aren't synched while firing events | ||||
|         fireDisconnected(info);         | ||||
|     }          | ||||
| 
 | ||||
|     @Override | ||||
| @ -389,6 +392,7 @@ public class DefaultClient implements Client | ||||
| 
 | ||||
|     protected void startServices()  | ||||
|     { | ||||
|         log.fine("Starting client services."); | ||||
|         // Let the services know we are finally started | ||||
|         services.start();       | ||||
|     } | ||||
| @ -447,6 +451,10 @@ public class DefaultClient implements Client | ||||
|   | ||||
|     protected void dispatch( Message m ) | ||||
|     { | ||||
|         if( log.isLoggable(Level.FINER) ) { | ||||
|             log.log(Level.FINER, "{0} received:{1}", new Object[]{this, m}); | ||||
|         } | ||||
|          | ||||
|         // Pull off the connection management messages we're | ||||
|         // interested in and then pass on the rest. | ||||
|         if( m instanceof ClientRegistrationMessage ) { | ||||
| @ -457,11 +465,17 @@ public class DefaultClient implements Client | ||||
|                 this.id = (int)crm.getId(); | ||||
|                 log.log( Level.FINE, "Connection established, id:{0}.", this.id ); | ||||
|                 connecting.countDown(); | ||||
|                 fireConnected(); | ||||
|                 //fireConnected(); | ||||
|             } else { | ||||
|                 // Else it's a message letting us know that the  | ||||
|                 // hosted services have been started | ||||
|                 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; | ||||
|         } else if( m instanceof ChannelInfoMessage ) { | ||||
|  | ||||
| @ -326,6 +326,10 @@ public class DefaultServer implements Server | ||||
|   | ||||
|     protected void dispatch( HostedConnection source, Message m ) | ||||
|     { | ||||
|         if( log.isLoggable(Level.FINER) ) { | ||||
|             log.log(Level.FINER, "{0} received:{1}", new Object[]{source, m}); | ||||
|         } | ||||
|          | ||||
|         if( source == null ) { | ||||
|             messageListeners.messageReceived( source, m ); | ||||
|         } else { | ||||
| @ -604,7 +608,7 @@ public class DefaultServer implements Server | ||||
|             // should always already be closed through all paths that I | ||||
|             // can conceive... but it doesn't hurt to be sure.  | ||||
|             for( Endpoint p : channels ) { | ||||
|                 if( p == null )  | ||||
|                 if( p == null || !p.isConnected() )  | ||||
|                     continue; | ||||
|                 p.close(); | ||||
|             } | ||||
|  | ||||
| @ -112,6 +112,8 @@ public class KernelAdapter extends Thread | ||||
|          | ||||
|         // Kill the kernel | ||||
|         kernel.terminate(); | ||||
|          | ||||
|         join(); | ||||
|     } | ||||
| 
 | ||||
|     protected void reportError( Endpoint p, Object context, Exception e ) | ||||
| @ -119,9 +121,11 @@ public class KernelAdapter extends Thread | ||||
|         // Should really be queued up so the outer thread can | ||||
|         // retrieve them.  For now we'll just log it.  FIXME | ||||
|         log.log( Level.SEVERE, "Unhandled error, endpoint:" + p + ", context:" + context, e ); | ||||
|          | ||||
|         // In lieu of other options, at least close the endpoint | ||||
|         p.close(); | ||||
| 
 | ||||
|         if( p.isConnected() ) { | ||||
|             // In lieu of other options, at least close the endpoint | ||||
|             p.close(); | ||||
|         } | ||||
|     }                                                       | ||||
| 
 | ||||
|     protected HostedConnection getConnection( Endpoint p ) | ||||
|  | ||||
| @ -50,26 +50,34 @@ import java.util.logging.Logger; | ||||
|  */ | ||||
| public class MessageListenerRegistry<S> implements MessageListener<S> | ||||
| { | ||||
|     static Logger log = Logger.getLogger(MessageListenerRegistry.class.getName()); | ||||
|     static final Logger log = Logger.getLogger(MessageListenerRegistry.class.getName()); | ||||
|      | ||||
|     private List<MessageListener<? super S>> listeners = new CopyOnWriteArrayList<MessageListener<? super S>>(); | ||||
|     private Map<Class,List<MessageListener<? super S>>> typeListeners  | ||||
|     private final List<MessageListener<? super S>> listeners = new CopyOnWriteArrayList<MessageListener<? super S>>(); | ||||
|     private final Map<Class,List<MessageListener<? super S>>> typeListeners  | ||||
|                     = new ConcurrentHashMap<Class,List<MessageListener<? super S>>>();  | ||||
| 
 | ||||
|     public MessageListenerRegistry() | ||||
|     { | ||||
|     } | ||||
|   | ||||
|     @Override | ||||
|     public void messageReceived( S source, Message m ) | ||||
|     { | ||||
|         boolean delivered = false; | ||||
|         boolean trace = log.isLoggable(Level.FINER); | ||||
|          | ||||
|         for( MessageListener<? super S> l : listeners ) { | ||||
|             if( trace ) { | ||||
|                 log.log(Level.FINER, "Delivering {0} to:{1}", new Object[]{m, l}); | ||||
|             } | ||||
|             l.messageReceived( source, m ); | ||||
|             delivered = true; | ||||
|         } | ||||
|          | ||||
|         for( MessageListener<? super S> l : getListeners(m.getClass(),false) ) { | ||||
|             if( trace ) { | ||||
|                 log.log(Level.FINER, "Delivering {0} to:{1}", new Object[]{m, l}); | ||||
|             } | ||||
|             l.messageReceived( source, m ); | ||||
|             delivered = true; | ||||
|         } | ||||
|  | ||||
| @ -181,7 +181,7 @@ public class MessageProtocol | ||||
|             Message m = (Message)obj; | ||||
|             messages.add(m); | ||||
|         } 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 ); | ||||
|     } | ||||
| 
 | ||||
|     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() | ||||
|     { | ||||
|         return nextId.getAndIncrement(); | ||||
|  | ||||
| @ -106,6 +106,9 @@ public class SelectorKernel extends AbstractKernel | ||||
|         try { | ||||
|             thread.close(); | ||||
|             thread = null; | ||||
|              | ||||
|             // Need to let any caller waiting for a read() wakeup  | ||||
|             wakeupReader();        | ||||
|         } catch( IOException 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 | ||||
|         addEvent( EndpointEvent.createRemove( this, p ) ); | ||||
| 
 | ||||
|         // 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 ); | ||||
|         } | ||||
|         wakeupReader(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -110,6 +110,9 @@ public class UdpKernel extends AbstractKernel | ||||
|             thread.close(); | ||||
|             writer.shutdown(); | ||||
|             thread = null; | ||||
|              | ||||
|             // Need to let any caller waiting for a read() wakeup  | ||||
|             wakeupReader();        | ||||
|         } catch( IOException e ) { | ||||
|             throw new KernelException( "Error closing host connection:" + address, e ); | ||||
|         } | ||||
| @ -169,16 +172,8 @@ public class UdpKernel extends AbstractKernel | ||||
|         log.log( Level.FINE, "Socket endpoints size:{0}", socketEndpoints.size() ); | ||||
| 
 | ||||
|         addEvent( EndpointEvent.createRemove( this, p ) ); | ||||
|          | ||||
|         // 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 ); | ||||
|         } | ||||
|   | ||||
|         wakeupReader();        | ||||
|     } | ||||
| 
 | ||||
|     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 | ||||
|             // to disable the ServerSerializerRegistrationsServer anyway. | ||||
|             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; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         log.log(Level.FINE, "Registering {0} classes...", registrations.length); | ||||
|         for( Registration reg : registrations ) { | ||||
|             log.log( Level.INFO, "Registering:{0}", reg); | ||||
|             log.log(Level.INFO, "Registering:{0}", reg); | ||||
|             reg.register(); | ||||
|         } | ||||
|         log.log(Level.FINE, "Done registering serializable classes."); | ||||
|     } | ||||
|      | ||||
|     @Serializable | ||||
| @ -187,7 +189,7 @@ public class SerializerRegistrationsMessage extends AbstractMessage { | ||||
|                     serializer = (Serializer)serializerType.newInstance();                     | ||||
|                 } | ||||
|                 SerializerRegistration result = Serializer.registerClassForId(id, type, serializer); | ||||
|                 log.log( Level.FINE, "   result:{0}", result);                 | ||||
|                 log.log(Level.FINE, "   result:{0}", result);                 | ||||
|             } catch( ClassNotFoundException e ) { | ||||
|                 throw new RuntimeException( "Class not found attempting to register:" + this, e ); | ||||
|             } catch( InstantiationException e ) { | ||||
|  | ||||
| @ -130,7 +130,7 @@ public abstract class Serializer { | ||||
|         registerClass(IdentityHashMap.class,            new MapSerializer()); | ||||
|         registerClass(TreeMap.class,                    new MapSerializer()); | ||||
|         registerClass(WeakHashMap.class,                new MapSerializer()); | ||||
|          | ||||
|   | ||||
|         registerClass(Enum.class,      new EnumSerializer()); | ||||
|         registerClass(GZIPCompressedMessage.class, new GZIPSerializer()); | ||||
|         registerClass(ZIPCompressedMessage.class, new ZIPSerializer()); | ||||
| @ -331,7 +331,7 @@ public abstract class Serializer { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public static SerializerRegistration getSerializerRegistration(Class cls, boolean failOnMiss) { | ||||
|         SerializerRegistration reg = classRegistrations.get(cls); | ||||
| 
 | ||||
|          | ||||
|         if (reg != null) return reg; | ||||
| 
 | ||||
|         for (Map.Entry<Class, SerializerRegistration> entry : classRegistrations.entrySet()) { | ||||
| @ -425,6 +425,22 @@ public abstract class Serializer { | ||||
|             return; | ||||
|         } | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -48,8 +48,9 @@ public class EnumSerializer extends Serializer { | ||||
| 
 | ||||
|             if (ordinal == -1) return null; | ||||
|             T[] enumConstants = c.getEnumConstants(); | ||||
|             if (enumConstants == null) | ||||
|                 throw new SerializerException( "Class has no enum constants:" + c ); | ||||
|             if (enumConstants == null) { | ||||
|                 throw new SerializerException("Class has no enum constants:" + c + "  Ordinal:" + ordinal); | ||||
|             } | ||||
|             return enumConstants[ordinal]; | ||||
|         } catch (IndexOutOfBoundsException ex) { | ||||
|             return null; | ||||
|  | ||||
| @ -34,11 +34,14 @@ package com.jme3.network.serializing.serializers; | ||||
| import com.jme3.network.serializing.Serializer; | ||||
| import com.jme3.network.serializing.SerializerException; | ||||
| import java.io.IOException; | ||||
| import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.nio.BufferOverflowException; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.util.*; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| 
 | ||||
| /** | ||||
|  * The field serializer is the default serializer used for custom class. | ||||
| @ -46,16 +49,35 @@ import java.util.*; | ||||
|  * @author Lars Wesselius, Nathan Sweet | ||||
|  */ | ||||
| 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, Constructor> savedCtors = new HashMap<Class, Constructor>(); | ||||
| 
 | ||||
|     protected void checkClass(Class clazz) { | ||||
|      | ||||
|         // See if the class has a public no-arg constructor | ||||
|         try { | ||||
|             clazz.getConstructor(); | ||||
|             savedCtors.put(clazz, clazz.getConstructor()); | ||||
|             return; | ||||
|         } 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) { | ||||
| @ -121,7 +143,8 @@ public class FieldSerializer extends Serializer { | ||||
| 
 | ||||
|         T object; | ||||
|         try { | ||||
|             object = c.newInstance(); | ||||
|             Constructor<T> ctor = (Constructor<T>)savedCtors.get(c); | ||||
|             object = ctor.newInstance(); | ||||
|         } catch (Exception e) { | ||||
|             throw new SerializerException( "Error creating object of type:" + c, e ); | ||||
|         } | ||||
| @ -129,6 +152,9 @@ public class FieldSerializer extends Serializer { | ||||
|         for (SavedField savedField : fields) { | ||||
|             Field field = savedField.field; | ||||
|             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; | ||||
| 
 | ||||
|             if (serializer != null) { | ||||
| @ -164,9 +190,12 @@ public class FieldSerializer extends Serializer { | ||||
|             try { | ||||
|                 val = savedField.field.get(object); | ||||
|             } catch (IllegalAccessException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 throw new SerializerException("Unable to access field:" + savedField.field + " on:" + object, e); | ||||
|             } | ||||
|             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 { | ||||
|                 if (serializer != null) { | ||||
|  | ||||
| @ -89,6 +89,10 @@ public class RmiHostedService extends AbstractHostedService { | ||||
|         this((short)-1, (byte)MessageConnection.CHANNEL_DEFAULT_RELIABLE, true); | ||||
|     } | ||||
| 
 | ||||
|     public RmiHostedService( byte defaultChannel ) { | ||||
|         this((short)-1, defaultChannel, true); | ||||
|     } | ||||
| 
 | ||||
|     public RmiHostedService( short rmiId, byte defaultChannel, boolean autoHost ) { | ||||
|         this.rmiId = rmiId; | ||||
|         this.defaultChannel = defaultChannel; | ||||
|  | ||||
| @ -351,6 +351,11 @@ public class RmiRegistry { | ||||
|         } | ||||
|          | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -184,7 +184,7 @@ public class RpcConnection { | ||||
|      | ||||
|         if( log.isLoggable(Level.FINEST) ) { | ||||
|             log.log(Level.FINEST, "handleMessage({0})", msg); | ||||
|         }     | ||||
|         } | ||||
|         RpcHandler handler = handlers.get(msg.getObjectId()); | ||||
|         try { | ||||
|             if( handler == null ) { | ||||
| @ -225,6 +225,7 @@ public class RpcConnection { | ||||
|     private class ResponseHolder { | ||||
|         private Object response; | ||||
|         private String error; | ||||
|         private Throwable exception; | ||||
|         private RpcCallMessage msg; | ||||
|         boolean received = false; | ||||
|   | ||||
| @ -235,6 +236,7 @@ public class RpcConnection { | ||||
|         public synchronized void setResponse( RpcResponseMessage msg ) { | ||||
|             this.response = msg.getResult(); | ||||
|             this.error = msg.getError(); | ||||
|             this.exception = msg.getThrowable(); | ||||
|             this.received = true; | ||||
|             notifyAll(); | ||||
|         } | ||||
| @ -250,6 +252,9 @@ public class RpcConnection { | ||||
|             if( error != null ) { | ||||
|                 throw new RuntimeException("Error calling remote procedure:" + msg + "\n" + error); | ||||
|             } | ||||
|             if( exception != null ) { | ||||
|                 throw new RuntimeException("Error calling remote procedure:" + msg, exception); | ||||
|             }  | ||||
|             return response;               | ||||
|         } | ||||
|          | ||||
|  | ||||
| @ -34,6 +34,7 @@ package com.jme3.network.service.rpc.msg; | ||||
| 
 | ||||
| import com.jme3.network.AbstractMessage; | ||||
| import com.jme3.network.serializing.Serializable; | ||||
| import com.jme3.network.serializing.Serializer; | ||||
| import java.io.PrintWriter; | ||||
| import java.io.StringWriter; | ||||
| 
 | ||||
| @ -50,6 +51,7 @@ public class RpcResponseMessage extends AbstractMessage { | ||||
|     private long msgId; | ||||
|     private Object result; | ||||
|     private String error; | ||||
|     private Object exception; // if it was serializable | ||||
| 
 | ||||
|     public RpcResponseMessage() { | ||||
|     } | ||||
| @ -61,12 +63,31 @@ public class RpcResponseMessage extends AbstractMessage { | ||||
| 
 | ||||
|     public RpcResponseMessage( long msgId, Throwable t ) { | ||||
|         this.msgId = msgId; | ||||
|           | ||||
|         StringWriter sOut = new StringWriter(); | ||||
|         PrintWriter out = new PrintWriter(sOut); | ||||
|         t.printStackTrace(out); | ||||
|         out.close(); | ||||
|         this.error = sOut.toString(); | ||||
|   | ||||
|         // 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(); | ||||
|             PrintWriter out = new PrintWriter(sOut); | ||||
|             t.printStackTrace(out); | ||||
|             out.close(); | ||||
|             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() { | ||||
| @ -81,9 +102,15 @@ public class RpcResponseMessage extends AbstractMessage { | ||||
|         return error; | ||||
|     } | ||||
|      | ||||
|     public Throwable getThrowable() { | ||||
|         return (Throwable)exception; | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return getClass().getSimpleName() + "[#" + msgId + ", result=" + result | ||||
|                                           + (error != null ? ", error=" + error : "") | ||||
|                                           + (exception != null ? ", exception=" + exception : "") | ||||
|                                           + "]"; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -65,7 +65,7 @@ public class ServerSerializerRegistrationsService extends AbstractHostedService | ||||
|     public void connectionAdded(Server server, HostedConnection hc) { | ||||
|         // Just in case | ||||
|         super.connectionAdded(server, hc); | ||||
|          | ||||
|   | ||||
|         // Send the client the registration information | ||||
|         hc.send(SerializerRegistrationsMessage.INSTANCE); | ||||
|     } | ||||
|  | ||||
| @ -109,6 +109,7 @@ task createBaseXml(dependsOn: configurations.corelibs) <<{ | ||||
|         dep.dependencyProject.configurations.archives.allArtifacts.each{ artifact-> | ||||
|             if(artifact.classifier == "sources"){ | ||||
|             } else if(artifact.classifier == "javadoc"){ | ||||
|             } else if(artifact.file.name.endsWith('.pom')) { | ||||
|             } else{ | ||||
|                 if(!jmeJarFiles.contains(artifact.file)){ | ||||
|                     jmeJarFiles.add(artifact.file) | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| CTL_AssetPackBrowserAction=AssetPackBrowser | ||||
| CTL_AssetPackBrowserTopComponent=AssetPackBrowser Window | ||||
| HINT_AssetPackBrowserTopComponent=This is a AssetPackBrowser window | ||||
| CTL_AssetPackBrowserTopComponent=AssetPackBrowser | ||||
| HINT_AssetPackBrowserTopComponent=The AssetPackBrowser allows easy managing of your AssetPacks | ||||
| AssetPackBrowserTopComponent.jTextField1.text=search | ||||
| AssetPackBrowserTopComponent.jButton1.text=update | ||||
| AssetPackBrowserTopComponent.jButton2.text=online assetpacks | ||||
|  | ||||
| @ -67,8 +67,8 @@ persistenceType = TopComponent.PERSISTENCE_ALWAYS) | ||||
| preferredID = "AppStateExplorerTopComponent") | ||||
| @Messages({ | ||||
|     "CTL_AppStateExplorerAction=AppStateExplorer", | ||||
|     "CTL_AppStateExplorerTopComponent=AppStateExplorer Window", | ||||
|     "HINT_AppStateExplorerTopComponent=This is a AppStateExplorer window" | ||||
|     "CTL_AppStateExplorerTopComponent=AppStateExplorer", | ||||
|     "HINT_AppStateExplorerTopComponent=The AppStateExplorer provides an Overview over your current AppState" | ||||
| }) | ||||
| public final class AppStateExplorerTopComponent extends TopComponent implements ExplorerManager.Provider { | ||||
| 
 | ||||
|  | ||||
| @ -1,3 +1,3 @@ | ||||
| CTL_FilterExplorerAction=FilterExplorer | ||||
| CTL_FilterExplorerTopComponent=FilterExplorer Window | ||||
| HINT_FilterExplorerTopComponent=This is a FilterExplorer window | ||||
| CTL_FilterExplorerTopComponent=FilterExplorer | ||||
| HINT_FilterExplorerTopComponent=The FilterExplorer provides an Overview over your current Filter | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| CTL_SceneExplorerAction=SceneExplorer | ||||
| CTL_SceneExplorerTopComponent=SceneExplorer Window | ||||
| HINT_SceneExplorerTopComponent=This is a SceneExplorer window | ||||
| CTL_SceneExplorerTopComponent=SceneExplorer | ||||
| HINT_SceneExplorerTopComponent=The SceneExplorer provides an Overview over the SceneGraph of your Scene. | ||||
| SceneExplorerTopComponent.jButton1.text=update | ||||
|  | ||||
| @ -186,7 +186,7 @@ public class EditableMatDefFile { | ||||
|             return ""; | ||||
|         } catch (Exception e) { | ||||
|             Exceptions.printStackTrace(e); | ||||
|             return "error generating shader " + e.getMessage(); | ||||
|             return "Error generating shader: " + e.getMessage(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -142,6 +142,7 @@ public class MatDefDataObject extends MultiDataObject { | ||||
|         findAssetManager(); | ||||
|         final MatDefMetaData metaData = new MatDefMetaData(this); | ||||
|         lookupContents.add(metaData); | ||||
|         lookupContents.add(new MatDefNavigatorPanel()); | ||||
|         pf.addFileChangeListener(new FileChangeAdapter() { | ||||
|             @Override | ||||
|             public void fileChanged(FileEvent fe) { | ||||
|  | ||||
| @ -8,6 +8,8 @@ package com.jme3.gde.materialdefinition.editor; | ||||
| import com.jme3.gde.materialdefinition.fileStructure.TechniqueBlock; | ||||
| import java.awt.Component; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| import javax.swing.DefaultComboBoxModel; | ||||
| import javax.swing.DefaultListCellRenderer; | ||||
| import javax.swing.JLabel; | ||||
| @ -23,7 +25,8 @@ public class MatDefEditorToolBar extends javax.swing.JPanel { | ||||
| 
 | ||||
|     private MatDefEditorlElement parent; | ||||
|     private final DefaultComboBoxModel<TechniqueBlock> comboModel = new DefaultComboBoxModel<TechniqueBlock>(); | ||||
| 
 | ||||
|     private final static Logger logger = Logger.getLogger(MatDefEditorToolBar.class.getName()); | ||||
|      | ||||
|     /** | ||||
|      * Creates new form MatDefEditorToolBar | ||||
|      */ | ||||
| @ -130,6 +133,17 @@ public class MatDefEditorToolBar extends javax.swing.JPanel { | ||||
|     }// </editor-fold>//GEN-END:initComponents | ||||
| 
 | ||||
|     private void techniqueComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_techniqueComboBoxActionPerformed | ||||
|         if (techniqueComboBox.getSelectedItem() == null) { | ||||
|             if (techniqueComboBox.getItemCount() > 0) { | ||||
|                 if (techniqueComboBox.getItemCount() > 1) { | ||||
|                     logger.log(Level.WARNING, "No Technique selected, taking the first one!"); /* Don't be over verbose: When there's only one Element, you can't select itself again, thus null */ | ||||
|                 } | ||||
|                 techniqueComboBox.setSelectedIndex(0); /* Take the first one available */ | ||||
|             } else { | ||||
|                 logger.log(Level.WARNING, "No Techniques known for this MaterialDef. Please add one using the button to the right!"); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         parent.switchTechnique((TechniqueBlock) techniqueComboBox.getSelectedItem()); | ||||
|     }//GEN-LAST:event_techniqueComboBoxActionPerformed | ||||
| 
 | ||||
|  | ||||
| @ -15,6 +15,8 @@ import com.jme3.util.blockparser.Statement; | ||||
| import java.beans.PropertyChangeListener; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.logging.Level; | ||||
| import java.util.logging.Logger; | ||||
| import org.openide.util.WeakListeners; | ||||
| 
 | ||||
| /** | ||||
| @ -28,6 +30,8 @@ public class TechniqueBlock extends UberStatement { | ||||
|     public static final String ADD_WORLD_PARAM = "addWorldParam"; | ||||
|     public static final String REMOVE_WORLD_PARAM = "removeWorldParam"; | ||||
|     protected String name; | ||||
|      | ||||
|     private static final Logger logger = Logger.getLogger(TechniqueBlock.class.getName()); | ||||
| 
 | ||||
|     protected TechniqueBlock(int lineNumber, String line) { | ||||
|         super(lineNumber, line); | ||||
| @ -102,7 +106,13 @@ public class TechniqueBlock extends UberStatement { | ||||
|     } | ||||
| 
 | ||||
|     public List<WorldParamBlock> getWorldParams() { | ||||
|         return getWorldParameters().getWorldParams(); | ||||
|         WorldParametersBlock block = getWorldParameters(); | ||||
|         if (block != null) | ||||
|             return getWorldParameters().getWorldParams(); | ||||
|         else { | ||||
|             logger.log(Level.WARNING, "Unable to build ShaderNodes: Could not find any WorldParameters. Most likely the technique {0} is broken.", line); | ||||
|             return new ArrayList<WorldParamBlock>(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void addWorldParam(WorldParamBlock block) { | ||||
| @ -180,8 +190,19 @@ public class TechniqueBlock extends UberStatement { | ||||
| 
 | ||||
|     public List<ShaderNodeBlock> getShaderNodes() { | ||||
|         List<ShaderNodeBlock> list = new ArrayList<ShaderNodeBlock>(); | ||||
|         list.addAll(getBlock(VertexShaderNodesBlock.class).getShaderNodes()); | ||||
|         list.addAll(getBlock(FragmentShaderNodesBlock.class).getShaderNodes()); | ||||
|          | ||||
|         VertexShaderNodesBlock vert_block = getBlock(VertexShaderNodesBlock.class); | ||||
|         if (vert_block == null) | ||||
|             logger.log(Level.WARNING, "Unable to build ShaderNodes: Could not find any VertexShaderNode. Most likely the technique {0} is broken.", line); | ||||
|         else | ||||
|             list.addAll(vert_block.getShaderNodes()); | ||||
|          | ||||
|         FragmentShaderNodesBlock frag_block = getBlock(FragmentShaderNodesBlock.class); | ||||
|         if (frag_block == null) | ||||
|             logger.log(Level.WARNING, "Unable to build ShaderNodes: Could not find any FragmentShaderNode. Most likely the technique {0} is broken.", line); | ||||
|         else | ||||
|             list.addAll(frag_block.getShaderNodes()); | ||||
|          | ||||
|         return list; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -148,7 +148,7 @@ public class MaterialPreviewRenderer implements SceneListener { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     private int lastErrorHash = 0; | ||||
|     private static int lastErrorHash = 0; | ||||
| 
 | ||||
|     private void smartLog(String expText, String message) { | ||||
|         int hash = message.hashCode(); | ||||
| @ -183,7 +183,8 @@ public class MaterialPreviewRenderer implements SceneListener { | ||||
|             //compilation error, the shader code will be output to the console | ||||
|             //the following code will output the error | ||||
|             //System.err.println(e.getMessage()); | ||||
|             Logger.getLogger(MaterialDebugAppState.class.getName()).log(Level.SEVERE, e.getMessage()); | ||||
|             //Logger.getLogger(MaterialDebugAppState.class.getName()).log(Level.SEVERE, e.getMessage()); | ||||
|             smartLog("{0}", e.getMessage()); | ||||
| 
 | ||||
|             java.awt.EventQueue.invokeLater(new Runnable() { | ||||
|                 public void run() { | ||||
|  | ||||
| @ -32,14 +32,16 @@ | ||||
| package com.jme3.gde.terraineditor.sky; | ||||
| 
 | ||||
| import com.jme3.math.Vector3f; | ||||
| import com.jme3.texture.Image; | ||||
| import com.jme3.texture.Texture; | ||||
| import java.awt.Component; | ||||
| import javax.swing.event.ChangeListener; | ||||
| import org.openide.WizardDescriptor; | ||||
| import org.openide.WizardValidationException; | ||||
| import org.openide.util.HelpCtx; | ||||
| 
 | ||||
| @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 | ||||
| @ -76,10 +78,12 @@ public class SkyboxWizardPanel2 implements WizardDescriptor.Panel { | ||||
|         // fireChangeEvent(); | ||||
|         // and uncomment the complicated stuff below. | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     @Override | ||||
|     public final void addChangeListener(ChangeListener l) { | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     @Override | ||||
|     public final void removeChangeListener(ChangeListener l) { | ||||
|     } | ||||
|     /* | ||||
| @ -105,14 +109,56 @@ 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 | ||||
|     // settings object will be the WizardDescriptor, so you can use | ||||
|     // WizardDescriptor.getProperty & putProperty to store information entered | ||||
|     // by the user. | ||||
|     public void readSettings(Object settings) { | ||||
|         WizardDescriptor wiz = (WizardDescriptor) settings; | ||||
|         multipleTextures = (Boolean)wiz.getProperty("multipleTextures"); | ||||
|     @Override | ||||
|     public void readSettings(WizardDescriptor settings) { | ||||
|         multipleTextures = (Boolean)settings.getProperty("multipleTextures"); | ||||
|         SkyboxVisualPanel2 comp = (SkyboxVisualPanel2) getComponent(); | ||||
|         if (multipleTextures) { | ||||
|             comp.getMultipleTexturePanel().setVisible(true); | ||||
| @ -124,28 +170,27 @@ public class SkyboxWizardPanel2 implements WizardDescriptor.Panel { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void storeSettings(Object settings) { | ||||
|         WizardDescriptor wiz = (WizardDescriptor) settings; | ||||
|     public void storeSettings(WizardDescriptor settings) { | ||||
|         SkyboxVisualPanel2 comp = (SkyboxVisualPanel2) getComponent(); | ||||
|         if (multipleTextures) { | ||||
|             wiz.putProperty("textureSouth", (Texture)comp.getEditorSouth().getValue()); | ||||
|             wiz.putProperty("textureNorth", (Texture)comp.getEditorNorth().getValue()); | ||||
|             wiz.putProperty("textureEast", (Texture)comp.getEditorEast().getValue()); | ||||
|             wiz.putProperty("textureWest", (Texture)comp.getEditorWest().getValue()); | ||||
|             wiz.putProperty("textureTop", (Texture)comp.getEditorTop().getValue()); | ||||
|             wiz.putProperty("textureBottom", (Texture)comp.getEditorBottom().getValue()); | ||||
|             settings.putProperty("textureSouth", (Texture)comp.getEditorSouth().getValue()); | ||||
|             settings.putProperty("textureNorth", (Texture)comp.getEditorNorth().getValue()); | ||||
|             settings.putProperty("textureEast", (Texture)comp.getEditorEast().getValue()); | ||||
|             settings.putProperty("textureWest", (Texture)comp.getEditorWest().getValue()); | ||||
|             settings.putProperty("textureTop", (Texture)comp.getEditorTop().getValue()); | ||||
|             settings.putProperty("textureBottom", (Texture)comp.getEditorBottom().getValue()); | ||||
|             float x = new Float(comp.getNormal1X().getText()); | ||||
|             float y = new Float(comp.getNormal1Y().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 { | ||||
|             wiz.putProperty("textureSingle", (Texture)comp.getEditorSingle().getValue()); | ||||
|             settings.putProperty("textureSingle", (Texture)comp.getEditorSingle().getValue()); | ||||
|             float x = new Float(comp.getNormal2X().getText()); | ||||
|             float y = new Float(comp.getNormal2Y().getText()); | ||||
|             float z = new Float(comp.getNormal2Z().getText()); | ||||
|             wiz.putProperty("normalScale", new Vector3f(x,y,z) ); | ||||
|             wiz.putProperty("envMapType", comp.getEnvMapType());          | ||||
|             wiz.putProperty("flipY", comp.getFlipYCheckBox().isSelected()); | ||||
|             settings.putProperty("normalScale", new Vector3f(x,y,z) ); | ||||
|             settings.putProperty("envMapType", comp.getEnvMapType());          | ||||
|             settings.putProperty("flipY", comp.getFlipYCheckBox().isSelected()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,6 @@ OpenIDE-Module-Long-Description=\ | ||||
|     The jMonkeyEngine GDE Welcome Screen | ||||
| OpenIDE-Module-Name=Welcome Screen | ||||
| OpenIDE-Module-Short-Description=The jMonkeyEngine GDE Welcome Screen | ||||
| WelcomeScreenTopComponent.http.link=http://hub.jmonkeyengine.org/wiki/doku.php/sdk:welcome:3_0?do=export_xhtmlbody | ||||
| WelcomeScreenTopComponent.http.link=http://hub.jmonkeyengine.org/wiki/doku.php/sdk:welcome:3_1?do=export_xhtmlbody | ||||
| WelcomeScreenTopComponent.rss.link=http://hub.jmonkeyengine.org/feed/rdf/ | ||||
| WelcomeScreenTopComponent.local.link=nbres:/com/jme3/gde/docs/sdk/welcome/local.html | ||||
|  | ||||
							
								
								
									
										140
									
								
								version.gradle
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								version.gradle
									
									
									
									
									
								
							| @ -3,27 +3,31 @@ | ||||
|  ===================== | ||||
|   | ||||
|  Nightly Build Snapshot | ||||
|  * git tag: | ||||
|  * Full Version: 3.1-5124 | ||||
|  * POM Version: 3.1.0-SNAPSHOT | ||||
|  * NBM Revision: 5124 | ||||
|  * NBM UC Suffix: nightly/3.1/plugins | ||||
| 
 | ||||
|  Nightly Build Snapshot (PBRIsComing branch) | ||||
|  * git tag: | ||||
|  * Full Version: 3.1-PBRIsComing-5124 | ||||
|  * POM Version: 3.1.0-PBRIsComing-SNAPSHOT | ||||
|  * NBM Revision: 5124 | ||||
|  * NBM UC Suffix: PBRIsComing-nightly/3.1/plugins | ||||
| 
 | ||||
|  Alpha1 Release | ||||
|  * git tag: v3.1.0-alpha1 | ||||
|  * Full Version: 3.1-alpha1 | ||||
|  * POM Version: 3.1.0-alpha1 | ||||
|  * NBM Revision: 1 | ||||
|  * NBM Revision: 0 | ||||
|  * NBM UC Suffix: stable/3.1/plugins | ||||
|   | ||||
|  Final Release | ||||
|  * git tag: v3.1.0 | ||||
|  * Full Version: 3.1 | ||||
|  * POM Version: 3.1.0 | ||||
|  * NBM Revision: 5 | ||||
|  * NBM Revision: 0 | ||||
|  * NBM UC Suffix: stable/3.1/plugins | ||||
|  */  | ||||
| 
 | ||||
| @ -52,59 +56,109 @@ ext { | ||||
|     jmeNbmUcSuffix  = "unknown" | ||||
| } | ||||
| 
 | ||||
| def getReleaseInfo(String tag) { | ||||
|     if (tag == null) { | ||||
|         // not a tagged commit | ||||
|         return null; | ||||
|     } | ||||
|     if (!tag.startsWith("v")) { | ||||
|         // syntax error | ||||
|         return null; | ||||
|     } | ||||
|     tag = tag.substring(1) | ||||
| 
 | ||||
|     String[] parts = tag.split("-", 2); | ||||
|     String mainVersion; | ||||
|     boolean prerelease; | ||||
|     String releaseName = null; | ||||
| 
 | ||||
|     if (parts.length == 2) { | ||||
|         // prerelease | ||||
|         prerelease = true; | ||||
|         mainVersion = parts[0]; | ||||
|         releaseName = parts[1]; | ||||
|         if (releaseName.size() == 0) { | ||||
|             // syntax error | ||||
|             return null; | ||||
|         } | ||||
|     } else if (parts.length == 1) { | ||||
|         // final release | ||||
|         prerelease = false; | ||||
|         mainVersion = parts[0]; | ||||
|     } else { | ||||
|         // error | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     if (mainVersion.size() == 0) { | ||||
|         // syntax error | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     parts = mainVersion.split("\\."); | ||||
|     if (parts.size() != 3) { | ||||
|         // syntax error | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     String baseVersion = parts[0] + "." + parts[1]; | ||||
| 
 | ||||
|     return [ | ||||
|         "tag" : tag, | ||||
|         "baseVersion" : baseVersion, | ||||
|         "mainVersion" : mainVersion, | ||||
|         "prerelease" :  prerelease, | ||||
|         "releaseName" : releaseName, | ||||
|         "releaseSuffix": (prerelease ? "-${releaseName}": "") | ||||
|     ] | ||||
| } | ||||
| 
 | ||||
| task configureVersionInfo { | ||||
|     try { | ||||
|         def grgit = Grgit.open(project.file('.')) | ||||
|         jmeRevision = grgit.log(includes:['HEAD']).size() | ||||
|         jmeGitHash = grgit.head().id | ||||
|         jmeShortGitHash = grgit.head().abbreviatedId | ||||
|         def head = grgit.head() | ||||
|         jmeRevision = grgit.log(includes: [head]).size() | ||||
|         jmeGitHash = head.id | ||||
|         jmeShortGitHash = head.abbreviatedId | ||||
|         jmeBranchName = grgit.branch.current.name | ||||
|         jmeGitTag = grgit.describe() | ||||
|         if (jmeGitTag == null) jmeGitTag = "" | ||||
|         jmeGitTag = grgit.tag.list().find { it.commit == head } | ||||
|          | ||||
|         if (System.env.TRAVIS_BRANCH != null) { | ||||
|             jmeBranchName = System.env.TRAVIS_BRANCH | ||||
|         } | ||||
|         if (System.env.TRAVIS_TAG != null) { | ||||
|         if (jmeGitTag != null) { | ||||
|             jmeGitTag = jmeGitTag.name | ||||
|         } else { | ||||
|             jmeGitTag = System.env.TRAVIS_TAG | ||||
|         } | ||||
|         if (System.env.TRAVIS_PULL_REQUEST != null &&  | ||||
|             System.env.TRAVIS_PULL_REQUEST != "false") { | ||||
|             jmeBranchName += "-pr-" + System.env.TRAVIS_PULL_REQUEST | ||||
|         } | ||||
|          | ||||
|         jmeFullVersion = jmeMainVersion | ||||
|         jmePomVersion  = jmeVersion | ||||
|          | ||||
|         if (jmeBranchName != "master") { | ||||
|             jmeFullVersion += "-${jmeBranchName}" | ||||
|             jmePomVersion  += "-${jmeBranchName}" | ||||
|              | ||||
|             jmeNbmUcSuffix = "${jmeBranchName}-" | ||||
| 
 | ||||
|         def releaseInfo = getReleaseInfo(jmeGitTag) | ||||
|         if (releaseInfo != null) { | ||||
|             jmeFullVersion = "${releaseInfo.baseVersion}${releaseInfo.releaseSuffix}" | ||||
|             jmePomVersion = "${releaseInfo.mainVersion}${releaseInfo.releaseSuffix}" | ||||
|             jmeNbmRevision = "0" | ||||
|             jmeNbmUcSuffix = "stable/${releaseInfo.baseVersion}/plugins" | ||||
|         } else { | ||||
|             jmeNbmUcSuffix = "" | ||||
|         } | ||||
|          | ||||
|         if (jmeVersionTag == "SNAPSHOT") { | ||||
|             jmeNbmUcSuffix += "nightly" | ||||
|         } else { | ||||
|             jmeNbmUcSuffix += "stable" | ||||
|         } | ||||
|          | ||||
|         jmeNbmUcSuffix += "/" + jmeMainVersion + "/plugins" | ||||
|          | ||||
|         if (jmeVersionTag == "SNAPSHOT") { | ||||
|             // SNAPSHOT | ||||
|             jmeFullVersion = jmeMainVersion | ||||
|             jmePomVersion  = jmeVersion | ||||
|             if (System.env.TRAVIS_BRANCH != null) { | ||||
|                 jmeBranchName = System.env.TRAVIS_BRANCH | ||||
|             } | ||||
|             if (System.env.TRAVIS_PULL_REQUEST != null &&  | ||||
|                 System.env.TRAVIS_PULL_REQUEST != "false") { | ||||
|                 jmeBranchName += "-pr-" + System.env.TRAVIS_PULL_REQUEST | ||||
|             } | ||||
|             if (jmeBranchName != "master") { | ||||
|                 jmeFullVersion += "-${jmeBranchName}" | ||||
|                 jmePomVersion  += "-${jmeBranchName}" | ||||
|                 jmeNbmUcSuffix = "${jmeBranchName}-" | ||||
|             } else { | ||||
|                 jmeNbmUcSuffix = "" | ||||
|             } | ||||
|             jmeNbmUcSuffix += "nightly/" + jmeMainVersion + "/plugins" | ||||
|             jmeFullVersion += "-${jmeRevision}" | ||||
|             jmePomVersion  += "-SNAPSHOT" | ||||
|             jmeNbmRevision = jmeRevision | ||||
|         } else if (jmeVersionTag == "") { | ||||
|             jmeNbmRevision = jmeVersionTagID | ||||
|         } else { | ||||
|             jmeFullVersion += "-${jmeVersionTag}" | ||||
|             jmePomVersion  += "-${jmeVersionTag}" | ||||
|             jmeNbmRevision = jmeVersionTagID | ||||
|         } | ||||
|          | ||||
|              | ||||
|         logger.warn("Full Version: ${jmeFullVersion}") | ||||
|         logger.warn("POM Version: ${jmePomVersion}") | ||||
|         logger.warn("NBM Revision: ${jmeNbmRevision}") | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user