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