Merge remote-tracking branch 'origin/master' into in-pass-shadows

in-pass-shadows
Kirill Vainer 7 years ago
commit 6fb2d029d2
  1. 1
      .gitignore
  2. 2
      CONTRIBUTING.md
  3. 2
      README.md
  4. 14
      build.gradle
  5. 3
      common.gradle
  6. 4
      gradle.properties
  7. BIN
      gradle/wrapper/gradle-wrapper.jar
  8. 4
      gradle/wrapper/gradle-wrapper.properties
  9. 22
      gradlew
  10. 6
      gradlew.bat
  11. 2
      jme3-android-examples/src/main/java/org/jmonkeyengine/jme3androidexamples/MainActivity.java
  12. 2
      jme3-android/build.gradle
  13. 8
      jme3-android/src/main/java/com/jme3/input/android/AndroidSensorJoyInput.java
  14. 4
      jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java
  15. 10
      jme3-blender/src/main/java/com/jme3/asset/BlenderKey.java
  16. 2
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java
  17. 14
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/curves/CurvesTemporalMesh.java
  18. 6
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/DnaBlockData.java
  19. 6
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/DynamicArray.java
  20. 6
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/Structure.java
  21. 36
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java
  22. 18
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Vector3d.java
  23. 37
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java
  24. 4
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/SubdivisionSurfaceModifier.java
  25. 133
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/ImageLoader.java
  26. 4
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/ImageUtils.java
  27. 32
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/TextureHelper.java
  28. 12
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java
  29. 4
      jme3-bullet/src/common/java/com/jme3/bullet/collision/PhysicsCollisionGroupListener.java
  30. 13
      jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java
  31. 11
      jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java
  32. 17
      jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java
  33. 15
      jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java
  34. 46
      jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
  35. 28
      jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java
  36. 51
      jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java
  37. 8
      jme3-bullet/src/common/java/com/jme3/bullet/control/ragdoll/RagdollUtils.java
  38. 6
      jme3-bullet/src/main/java/com/jme3/bullet/PhysicsSpace.java
  39. 6
      jme3-bullet/src/main/java/com/jme3/bullet/collision/PhysicsCollisionObject.java
  40. 4
      jme3-bullet/src/main/java/com/jme3/bullet/joints/ConeJoint.java
  41. 4
      jme3-bullet/src/main/java/com/jme3/bullet/joints/HingeJoint.java
  42. 4
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsRigidBody.java
  43. 10
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsVehicle.java
  44. 4
      jme3-bullet/src/main/java/com/jme3/bullet/objects/VehicleWheel.java
  45. 12
      jme3-bullet/src/main/java/com/jme3/bullet/util/DebugShapeFactory.java
  46. 2
      jme3-core/src/main/java/checkers/quals/DefaultQualifiers.java
  47. 734
      jme3-core/src/main/java/com/jme3/animation/AnimChannel.java
  48. 33
      jme3-core/src/main/java/com/jme3/animation/AnimControl.java
  49. 10
      jme3-core/src/main/java/com/jme3/animation/AnimationUtils.java
  50. 20
      jme3-core/src/main/java/com/jme3/animation/Bone.java
  51. 92
      jme3-core/src/main/java/com/jme3/animation/BoneTrack.java
  52. 52
      jme3-core/src/main/java/com/jme3/animation/CompactArray.java
  53. 33
      jme3-core/src/main/java/com/jme3/animation/EffectTrack.java
  54. 7
      jme3-core/src/main/java/com/jme3/animation/Skeleton.java
  55. 62
      jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java
  56. 55
      jme3-core/src/main/java/com/jme3/animation/SpatialTrack.java
  57. 8
      jme3-core/src/main/java/com/jme3/animation/Track.java
  58. 32
      jme3-core/src/main/java/com/jme3/app/DetailedProfilerState.java
  59. 7
      jme3-core/src/main/java/com/jme3/app/StatsView.java
  60. 36
      jme3-core/src/main/java/com/jme3/app/state/ScreenshotAppState.java
  61. 4
      jme3-core/src/main/java/com/jme3/asset/AssetManager.java
  62. 5
      jme3-core/src/main/java/com/jme3/asset/ImplHandler.java
  63. 3
      jme3-core/src/main/java/com/jme3/asset/cache/WeakRefCloneAssetCache.java
  64. 10
      jme3-core/src/main/java/com/jme3/audio/AudioNode.java
  65. 337
      jme3-core/src/main/java/com/jme3/audio/openal/AL.java
  66. 91
      jme3-core/src/main/java/com/jme3/audio/openal/ALC.java
  67. 1398
      jme3-core/src/main/java/com/jme3/audio/openal/EFX.java
  68. 1435
      jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java
  69. 182
      jme3-core/src/main/java/com/jme3/cinematic/KeyFrame.java
  70. 6
      jme3-core/src/main/java/com/jme3/cinematic/MotionPath.java
  71. 4
      jme3-core/src/main/java/com/jme3/cinematic/MotionPathListener.java
  72. 35
      jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java
  73. 146
      jme3-core/src/main/java/com/jme3/cinematic/events/CameraEvent.java
  74. 969
      jme3-core/src/main/java/com/jme3/cinematic/events/MotionEvent.java
  75. 459
      jme3-core/src/main/java/com/jme3/cinematic/events/SoundEvent.java
  76. 4
      jme3-core/src/main/java/com/jme3/collision/SweepSphere.java
  77. 10
      jme3-core/src/main/java/com/jme3/effect/ParticleEmitter.java
  78. 4
      jme3-core/src/main/java/com/jme3/effect/influencers/ParticleInfluencer.java
  79. 4
      jme3-core/src/main/java/com/jme3/effect/shapes/EmitterMeshConvexHullShape.java
  80. 4
      jme3-core/src/main/java/com/jme3/effect/shapes/EmitterMeshFaceShape.java
  81. 6
      jme3-core/src/main/java/com/jme3/effect/shapes/EmitterMeshVertexShape.java
  82. 10
      jme3-core/src/main/java/com/jme3/effect/shapes/EmitterSphereShape.java
  83. 6
      jme3-core/src/main/java/com/jme3/environment/EnvironmentCamera.java
  84. 76
      jme3-core/src/main/java/com/jme3/environment/LightProbeFactory.java
  85. 4
      jme3-core/src/main/java/com/jme3/environment/generation/IrradianceSphericalHarmonicsGenerator.java
  86. 235
      jme3-core/src/main/java/com/jme3/environment/generation/PrefilteredEnvMapFaceGenerator.java
  87. 4
      jme3-core/src/main/java/com/jme3/environment/generation/RunnableWithProgress.java
  88. 34
      jme3-core/src/main/java/com/jme3/environment/util/CubeMapWrapper.java
  89. 22
      jme3-core/src/main/java/com/jme3/environment/util/EnvMapUtils.java
  90. 4
      jme3-core/src/main/java/com/jme3/environment/util/LightsDebugState.java
  91. 14
      jme3-core/src/main/java/com/jme3/input/ChaseCamera.java
  92. 21
      jme3-core/src/main/java/com/jme3/input/InputManager.java
  93. 4
      jme3-core/src/main/java/com/jme3/input/Joystick.java
  94. 10
      jme3-core/src/main/java/com/jme3/input/KeyInput.java
  95. 7
      jme3-core/src/main/java/com/jme3/light/LightProbe.java
  96. 4
      jme3-core/src/main/java/com/jme3/light/LightProbeBlendingStrategy.java
  97. 6
      jme3-core/src/main/java/com/jme3/light/PointLight.java
  98. 4
      jme3-core/src/main/java/com/jme3/light/SpotLight.java
  99. 45
      jme3-core/src/main/java/com/jme3/material/Materials.java
  100. 4
      jme3-core/src/main/java/com/jme3/material/ShaderGenerationInfo.java
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -2,6 +2,7 @@
**/.classpath
**/.settings
**/.project
**/out
/.gradle/
/.nb-gradle/
/.idea/

@ -55,5 +55,5 @@ We generally abide by the standard Java Code Conventions. Besides that, just mak
## Documentation
- How to edit the wiki - WIP
- How to edit the [wiki](https://github.com/jMonkeyEngine/wiki).
- How to edit JavaDocs - WIP

@ -3,7 +3,7 @@ jMonkeyEngine
[![Build Status](https://travis-ci.org/jMonkeyEngine/jmonkeyengine.svg?branch=master)](https://travis-ci.org/jMonkeyEngine/jmonkeyengine)
jMonkeyEngine is a 3D game engine for adventurous Java developers. It’s open-source, cross-platform, and cutting-edge. 3.1.0 is the latest stable version of the jMonkeyEngine 3 SDK, a complete game development suite. We'll release 3.1.x updates until the major 3.2 release arrives.
jMonkeyEngine is a 3D game engine for adventurous Java developers. It’s open-source, cross-platform, and cutting-edge. 3.2.0 is the latest stable version of the jMonkeyEngine 3 SDK, a complete game development suite. We'll release 3.2.x updates until the major 3.3 release arrives.
The engine is used by several commercial game studios and computer-science courses. Here's a taste:

@ -15,7 +15,7 @@ apply from: file('version.gradle')
subprojects {
if(!project.name.equals('jme3-android-examples')) {
apply from: rootProject.file('common.gradle')
if (!['jme3-testdata', 'sdk'].contains(project.name)) {
if (!project.name.equals('jme3-testdata')) {
apply from: rootProject.file('bintray.gradle')
}
} else {
@ -66,9 +66,9 @@ task createZipDistribution(type:Zip,dependsOn:["dist","libDist"], description:"P
archiveName "jME" + jmeFullVersion + ".zip"
into("/") {
from {"./dist"}
}
}
into("/sources") {
from {"$buildDir/libDist/sources"}
from {"$buildDir/libDist/sources"}
}
}
@ -88,14 +88,14 @@ 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()) {
options.addStringOption('Xdoclint:none', '-quiet')
}
options.overview = file("javadoc-overview.html")
// Note: The closures below are executed lazily.
source subprojects.collect {project ->
@ -116,7 +116,7 @@ task mergedSource(type: Copy){
}
task wrapper(type: Wrapper, description: 'Creates and deploys the Gradle wrapper to the current directory.') {
gradleVersion = '3.2.1'
gradleVersion = '4.1'
}
ext {
@ -137,7 +137,7 @@ task configureAndroidNDK {
if (System.env.ANDROID_NDK != null) {
ndkBuildPath = System.env.ANDROID_NDK + File.separator + ndkBuildFile
}
if (new File(ndkBuildPath).exists()) {
ndkExists = true
ndkCommandPath = ndkBuildPath

@ -16,6 +16,9 @@ repositories {
maven {
url "http://nifty-gui.sourceforge.net/nifty-maven-repo"
}
flatDir {
dirs rootProject.file('lib')
}
}
dependencies {

@ -1,7 +1,7 @@
# Version number used for plugins, only 3 numbers (e.g. 3.1.3)
jmeVersion = 3.2.0
jmeVersion = 3.3.0
# Version used for application and settings folder, no spaces!
jmeMainVersion = 3.2
jmeMainVersion = 3.3
# Version addition pre-alpha-svn, Stable, Beta
jmeVersionTag = SNAPSHOT
# Increment this each time jmeVersionTag changes but jmeVersion stays the same

Binary file not shown.

@ -1,6 +1,6 @@
#Fri Nov 25 13:05:50 EST 2016
#Sun Sep 17 22:55:30 EDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip

22
gradlew vendored

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save ( ) {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

6
gradlew.bat vendored

@ -49,7 +49,6 @@ goto fail
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

@ -214,7 +214,7 @@ public class MainActivity extends AppCompatActivity implements OnItemClickListen
/**
* User clicked a view on the screen. Check for the OK and Cancel buttons
* and either start the applicaiton or exit.
* and either start the application or exit.
* @param view
*/
public void onClick(View view) {

@ -5,5 +5,5 @@ if (!hasProperty('mainClass')) {
dependencies {
compile project(':jme3-core')
compile project(':jme3-plugins')
compile files('../lib/android.jar')
compileOnly 'android:android'
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -59,7 +59,7 @@ import java.util.logging.Logger;
/**
* AndroidSensorJoyInput converts the Android Sensor system into Joystick events.
* A single joystick is configured and includes data for all configured sensors
* as seperate axes of the joystick.
* as separate axes of the joystick.
*
* Each axis is named according to the static strings in SensorJoystickAxis.
* Refer to the strings defined in SensorJoystickAxis for a list of supported
@ -285,8 +285,8 @@ public class AndroidSensorJoyInput implements SensorEventListener {
}
/**
* Calculates the device orientation based off the data recieved from the
* Acceleration Sensor and Mangetic Field sensor
* Calculates the device orientation based off the data received from the
* Acceleration Sensor and Magnetic Field sensor
* Values are returned relative to the Earth.
*
* From the Android Doc

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -136,7 +136,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex
// stops at the setFormat call without a crash.
// We look at the user setting for alpha bits and set the surfaceview
// PixelFormat to either Opaque, Transparent, or Translucent.
// ConfigChooser will do it's best to honor the alpha requested by the user
// ConfigChooser will do its best to honor the alpha requested by the user
// For best rendering performance, use Opaque (alpha bits = 0).
int curAlphaBits = settings.getAlphaBits();
logger.log(Level.FINE, "curAlphaBits: {0}", curAlphaBits);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -69,7 +69,7 @@ public class BlenderKey extends ModelKey {
*/
protected String usedWorld;
/**
* User's default material that is set fo objects that have no material definition in blender. The default value is
* User's default material that is set for objects that have no material definition in blender. The default value is
* null. If the value is null the importer will use its own default material (gray color - like in blender).
*/
protected Material defaultMaterial;
@ -476,9 +476,9 @@ public class BlenderKey extends ModelKey {
}
/**
* This mehtod sets the name of the WORLD data block taht should be used during file loading. By default the name is
* This method sets the name of the WORLD data block that should be used during file loading. By default the name is
* not set. If no name is set or the given name does not occur in the file - the first WORLD data block will be used
* during loading (assumin any exists in the file).
* during loading (assuming any exists in the file).
* @param usedWorld
* the name of the WORLD block used during loading
*/
@ -487,7 +487,7 @@ public class BlenderKey extends ModelKey {
}
/**
* This mehtod returns the name of the WORLD data block taht should be used during file loading.
* This method returns the name of the WORLD data block that should be used during file loading.
* @return the name of the WORLD block used during loading
*/
public String getUsedWorld() {

@ -237,7 +237,7 @@ public class SimulationNode {
}
}
// ... add virtual tracks if neccessary, for bones that were altered but had no tracks before ...
// ... add virtual tracks if necessary, for bones that were altered but had no tracks before ...
for (Long boneOMA : alteredOmas) {
BoneContext boneContext = blenderContext.getBoneContext(boneOMA);
int boneIndex = skeleton.getBoneIndex(boneContext.getBone());

@ -37,7 +37,7 @@ import com.jme3.util.BufferUtils;
/**
* A temporal mesh for curves and surfaces. It works in similar way as TemporalMesh for meshes.
* It prepares all neccessary lines and faces and allows to apply modifiers just like in regular temporal mesh.
* It prepares all necessary lines and faces and allows to apply modifiers just like in regular temporal mesh.
*
* @author Marcin Roguski (Kaelthas)
*/
@ -210,7 +210,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
}
/**
* The method computes the value of a point at the certain relational distance from its beggining.
* The method computes the value of a point at the certain relational distance from its beginning.
* @param alongRatio
* the relative distance along the curve; should be a value between 0 and 1 inclusive;
* if the value exceeds the boundaries it is truncated to them
@ -369,7 +369,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
}
/**
* The method loads the bevel object that sould be applied to curve. It can either be another curve or a generated one
* The method loads the bevel object that should be applied to curve. It can either be another curve or a generated one
* based on the bevel generating parameters in blender.
* @param curveStructure
* the structure with the curve's data (the curve being loaded, NOT the bevel curve)
@ -707,7 +707,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
/**
* the method applies scale for the given bevel points. The points table is
* being modified so expect ypur result there.
* being modified so expect your result there.
*
* @param points
* the bevel points
@ -726,7 +726,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
/**
* A helper class that represents a single bezier line. It consists of Edge's and allows to
* get a subline of a lentgh of the line.
* get a subline of a length of the line.
*
* @author Marcin Roguski (Kaelthas)
*/
@ -776,7 +776,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
}
if (cyclic) {
// if the first vertex is repeated at the end the distance will be = 0 so it won't affect the result, and if it is not repeated
// then it is neccessary to add the length between the last and the first vertex
// then it is necessary to add the length between the last and the first vertex
length += vertices[vertices.length - 1].distance(vertices[0]);
}
}
@ -834,7 +834,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
}
/**
* The method computes the value of a point at the certain relational distance from its beggining.
* The method computes the value of a point at the certain relational distance from its beginning.
* @param alongRatio
* the relative distance along the curve; should be a value between 0 and 1 inclusive;
* if the value exceeds the boundaries it is truncated to them

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -85,7 +85,7 @@ public class DnaBlockData {
names[i] = inputStream.readString();
}
// reding types
// reading types
inputStream.alignPosition(4);
identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte();
if (identifier != TYPE_ID) {
@ -181,7 +181,7 @@ public class DnaBlockData {
/**
* This method converts the given identifier code to string.
* @param code
* the code taht is to be converted
* the code that is to be converted
* @return the string value of the identifier
*/
private String toString(int code) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@
package com.jme3.scene.plugins.blender.file;
/**
* An array that can be dynamically modified/
* An array that can be dynamically modified
* @author Marcin Roguski
* @param <T>
* the type of stored data in the array
@ -42,7 +42,7 @@ public class DynamicArray<T> implements Cloneable {
/** An array object that holds the required data. */
private T[] array;
/**
* This table holds the sizes of dimetions of the dynamic table. It's length specifies the table dimension or a
* This table holds the sizes of dimensions of the dynamic table. Its length specifies the table dimension or a
* pointer level. For example: if tableSizes.length == 3 then it either specifies a dynamic table of fixed lengths:
* dynTable[a][b][c], where a,b,c are stored in the tableSizes table.
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -169,7 +169,7 @@ public class Structure implements Cloneable {
}
/**
* This methos should be used on structures that are of a 'ListBase' type. It creates a List of structures that are
* This method should be used on structures that are of a 'ListBase' type. It creates a List of structures that are
* held by this structure within the blend file.
* @return a list of filled structures
* @throws BlenderFileException
@ -232,7 +232,7 @@ public class Structure implements Cloneable {
}
/**
* This method returns the address of the structure. The strucutre should be filled with data otherwise an exception
* This method returns the address of the structure. The structure should be filled with data otherwise an exception
* is thrown.
* @return the address of the feature stored in this structure
*/

@ -1,6 +1,7 @@
package com.jme3.scene.plugins.blender.materials;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -106,7 +107,7 @@ public final class MaterialContext implements Savable {
boolean transparent = false;
if (diffuseColor != null) {
transparent = diffuseColor.a < 1.0f;
if (loadedTextures.size() > 0) {// texutre covers the material color
if (loadedTextures.size() > 0) {// texture covers the material color
diffuseColor.set(1, 1, 1, 1);
}
}
@ -163,6 +164,12 @@ public final class MaterialContext implements Savable {
material.setColor("Ambient", new ColorRGBA(ambientFactor, ambientFactor, ambientFactor, 1f));
}
// initializing unused "user-defined UV coords" to all available
Map<String, List<Vector2f>> unusedUserDefinedUVCoords = Collections.emptyMap();
if(userDefinedUVCoordinates != null && !userDefinedUVCoordinates.isEmpty()) {
unusedUserDefinedUVCoords = new HashMap<>(userDefinedUVCoordinates);
}
// applying textures
int textureIndex = 0;
@ -175,16 +182,19 @@ public final class MaterialContext implements Savable {
String usedUserUVSet = combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
this.setTexture(material, combinedTexture.getMappingType(), combinedTexture.getResultTexture());
List<Vector2f> uvs = combinedTexture.getResultUVS();
if(uvs != null && uvs.size() > 0) {
VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
geometry.getMesh().setBuffer(uvCoordsBuffer);
}//uvs might be null if the user assigned non existing UV coordinates group name to the mesh (this should be fixed in blender file)
if(usedUserUVSet != null) {
userDefinedUVCoordinates = new HashMap<>(userDefinedUVCoordinates);
userDefinedUVCoordinates.remove(usedUserUVSet);
if(usedUserUVSet == null || unusedUserDefinedUVCoords.containsKey(usedUserUVSet)) {
List<Vector2f> uvs = combinedTexture.getResultUVS();
if(uvs != null && uvs.size() > 0) {
VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
geometry.getMesh().setBuffer(uvCoordsBuffer);
}//uvs might be null if the user assigned non existing UV coordinates group name to the mesh (this should be fixed in blender file)
// Remove used "user-defined UV coords" from the unused collection
if(usedUserUVSet != null) {
unusedUserDefinedUVCoords.remove(usedUserUVSet);
}
}
} else {
LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length);
@ -192,12 +202,12 @@ public final class MaterialContext implements Savable {
}
}
if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
if (unusedUserDefinedUVCoords != null && unusedUserDefinedUVCoords.size() > 0) {
LOGGER.fine("Storing unused, user defined UV coordinates sets.");
if (userDefinedUVCoordinates.size() > TextureHelper.TEXCOORD_TYPES.length) {
if (unusedUserDefinedUVCoords.size() > TextureHelper.TEXCOORD_TYPES.length) {
LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different UV coordinates for the mesh. JME supports only {0} UV coordinates buffers.", TextureHelper.TEXCOORD_TYPES.length);
}
for (Entry<String, List<Vector2f>> entry : userDefinedUVCoordinates.entrySet()) {
for (Entry<String, List<Vector2f>> entry : unusedUserDefinedUVCoords.entrySet()) {
if (textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
List<Vector2f> uvs = entry.getValue();
VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -324,7 +324,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
* the vector to take the cross product of with this.
* @param result
* the vector to store the cross product result.
* @return result, after recieving the cross product vector.
* @return result, after receiving the cross product vector.
*/
public Vector3d cross(Vector3d v, Vector3d result) {
return this.cross(v.x, v.y, v.z, result);
@ -342,7 +342,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
* z component of the vector to take the cross product of with this.
* @param result
* the vector to store the cross product result.
* @return result, after recieving the cross product vector.
* @return result, after receiving the cross product vector.
*/
public Vector3d cross(double otherX, double otherY, double otherZ, Vector3d result) {
if (result == null) {
@ -485,12 +485,12 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* <code>multLocal</code> multiplies a provided vector by this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
* @param vec
* the vector to mult to this vector.
* the vector to multiply by this vector.
* @return this
*/
public Vector3d multLocal(Vector3d vec) {
@ -522,7 +522,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* <code>multLocal</code> multiplies a provided vector by this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
@ -539,7 +539,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
}
/**
* <code>multLocal</code> multiplies a provided vector to this vector
* <code>multLocal</code> multiplies a provided vector by this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
@ -657,7 +657,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
}
/**
* <code>subtractLocal</code> subtracts a provided vector to this vector
* <code>subtractLocal</code> subtracts a provided vector from this vector
* internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned.
*
@ -825,7 +825,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
/**
* <code>hashCode</code> returns a unique code for this vector object based
* on it's values. If two vectors are logically equivalent, they will return
* on its values. If two vectors are logically equivalent, they will return
* the same hash code value.
* @return the hash code value of this vector.
*/

@ -291,27 +291,30 @@ public class MeshHelper extends AbstractBlenderHelper {
Structure defbase = (Structure) parent.getFieldValue("defbase");
List<String> groupNames = new ArrayList<String>();
List<Structure> defs = defbase.evaluateListBase();
for (Structure def : defs) {
groupNames.add(def.getFieldValue("name").toString());
}
if(!defs.isEmpty()) {
for (Structure def : defs) {
groupNames.add(def.getFieldValue("name").toString());
}
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
if (pDvert.isNotNull()) {// assigning weights and bone indices
List<Structure> dverts = pDvert.fetchData();
for (Structure dvert : dverts) {
Map<String, Float> weightsForVertex = new HashMap<String, Float>();
Pointer pDW = (Pointer) dvert.getFieldValue("dw");
if (pDW.isNotNull()) {
List<Structure> dw = pDW.fetchData();
for (Structure deformWeight : dw) {
int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue();
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
String groupName = groupNames.get(groupIndex);
Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
if (pDvert.isNotNull()) {// assigning weights and bone indices
List<Structure> dverts = pDvert.fetchData();
for (Structure dvert : dverts) {
Map<String, Float> weightsForVertex = new HashMap<String, Float>();
Pointer pDW = (Pointer) dvert.getFieldValue("dw");
if (pDW.isNotNull()) {
List<Structure> dw = pDW.fetchData();
for (Structure deformWeight : dw) {
int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue();
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
String groupName = groupNames.get(groupIndex);
weightsForVertex.put(groupName, weight);
weightsForVertex.put(groupName, weight);
}
}
result.add(weightsForVertex);
}
result.add(weightsForVertex);
}
}
}

@ -47,7 +47,7 @@ public class SubdivisionSurfaceModifier extends Modifier {
private Set<Integer> verticesOnOriginalEdges = new HashSet<Integer>();
/**
* Constructor loads all neccessary modifier data.
* Constructor loads all necessary modifier data.
* @param modifierStructure
* the modifier structure
* @param blenderContext
@ -193,7 +193,7 @@ public class SubdivisionSurfaceModifier extends Modifier {
// moving the vertex
v.addLocal(t);
// applying crease weight if neccessary
// applying crease weight if necessary
CreasePoint creasePoint = creasePoints.get(i);
if (creasePoint.getTarget() != null && creasePoint.getWeight() != 0) {
t = creasePoint.getTarget().subtractLocal(v).multLocal(creasePoint.getWeight());

@ -31,12 +31,14 @@
*/
package com.jme3.scene.plugins.blender.textures;
import com.jme3.asset.AssetManager;
import com.jme3.asset.TextureKey;
import com.jme3.scene.plugins.blender.file.BlenderInputStream;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.plugins.AWTLoader;
import com.jme3.texture.plugins.DDSLoader;
import com.jme3.texture.plugins.TGALoader;
import java.io.InputStream;
import com.jme3.texture.plugins.HDRLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
@ -47,11 +49,29 @@ import java.util.logging.Logger;
*/
/* package */class ImageLoader extends AWTLoader {
private static final Logger LOGGER = Logger.getLogger(ImageLoader.class.getName());
protected DDSLoader ddsLoader = new DDSLoader(); // DirectX image loader
private static final Logger hdrLogger = Logger.getLogger(HDRLoader.class.getName()); // Used to silence HDR Errors
/**
* List of Blender-Supported Texture Extensions (we have to guess them, so
* the AssetLoader can find them. Not good, but better than nothing.
* Source: https://docs.blender.org/manual/en/dev/data_system/files/media/image_formats.html
*/
private static final String[] extensions = new String[]
{ /* Windows Bitmap */".bmp",
/* Iris */ ".sgi", ".rgb", ".bw",
/* PNG */ ".png",
/* JPEG */ ".jpg", ".jpeg",
/* JPEG 2000 */ ".jp2", ".j2c",
/* Targa */".tga",
/* Cineon & DPX */".cin", ".dpx",
/* OpenEXR */ ".exr",
/* Radiance HDR */ ".hdr",
/* TIFF */ ".tif", ".tiff",
/* DDS (Direct X) */ ".dds" };
/**
* This method loads the image from the blender file itself. It tries each loader to load the image.
* This method loads a image which is packed into the blender file.
* It makes use of all the registered AssetLoaders
*
* @param inputStream
* blender input stream
@ -60,76 +80,57 @@ import java.util.logging.Logger;
* @param flipY
* if the image should be flipped (does not work with DirectX image)
* @return loaded image or null if it could not be loaded
* @deprecated This method has only been left in for API compability.
* Use loadTexture instead
*/
public Image loadImage(BlenderInputStream inputStream, int startPosition, boolean flipY) {
// loading using AWT loader
inputStream.setPosition(startPosition);
Image result = this.loadImage(inputStream, ImageType.AWT, flipY);
// loading using TGA loader
if (result == null) {
inputStream.setPosition(startPosition);
result = this.loadImage(inputStream, ImageType.TGA, flipY);
}
// loading using DDS loader
if (result == null) {
inputStream.setPosition(startPosition);
result = this.loadImage(inputStream, ImageType.DDS, flipY);
public Image loadImage(AssetManager assetManager, BlenderInputStream inputStream, int startPosition, boolean flipY) {
Texture tex = loadTexture(assetManager, inputStream, startPosition, flipY);
if (tex == null) {
return null;
} else {
return tex.getImage();
}
if (result == null) {
LOGGER.warning("Image could not be loaded by none of available loaders!");
}
return result;
}
/**
* This method loads an image of a specified type from the given input stream.
* This method loads a texture which is packed into the blender file.
* It makes use of all the registered AssetLoaders
*
* @param inputStream
* the input stream we read the image from
* @param imageType
* the type of the image {@link ImageType}
* blender input stream
* @param startPosition
* position in the stream where the image data starts
* @param flipY
* if the image should be flipped (does not work with DirectX image)
* @return loaded image or null if it could not be loaded
* @return loaded texture or null if it could not be loaded
*/
public Image loadImage(InputStream inputStream, ImageType imageType, boolean flipY) {
Image result = null;
switch (imageType) {
case AWT:
try {
result = this.load(inputStream, flipY);
} catch (Exception e) {
LOGGER.warning("Unable to load image using AWT loader!");
}
break;
case DDS:
try {
result = ddsLoader.load(inputStream);
} catch (Exception e) {
LOGGER.warning("Unable to load image using DDS loader!");
}
break;
case TGA:
try {
result = TGALoader.load(inputStream, flipY);
} catch (Exception e) {
LOGGER.warning("Unable to load image using TGA loader!");
}
break;
default:
throw new IllegalStateException("Unknown image type: " + imageType);
public Texture loadTexture(AssetManager assetManager, BlenderInputStream inputStream, int startPosition, boolean flipY) {
inputStream.setPosition(startPosition);
TextureKey tKey;
Texture result = null;
hdrLogger.setLevel(Level.SEVERE); // When we bruteforce try HDR on a non hdr file, it prints unreadable chars
for (String ext: extensions) {
tKey = new TextureKey("dummy" + ext, flipY);
try {
result = assetManager.loadAssetFromStream(tKey, inputStream);
} catch (Exception e) {
continue;
}
if (result != null) {
break; // Could locate a possible asset
}
}
if (result == null) {
LOGGER.warning("Texture could not be loaded by any of the available loaders!\n"
+ "Since the file has been packed into the blender file, there is no"
+ "way for us to tell you which texture it was.");
}
return result;
}
/**
* Image types that can be loaded. AWT: png, jpg, jped or bmp TGA: tga DDS: DirectX image files
*
* @author Marcin Roguski (Kaelthas)
*/
private static enum ImageType {
AWT, TGA, DDS;
}
}

@ -206,7 +206,7 @@ public final class ImageUtils {
N.z = 1;
N.divideLocal(den);
// setting thge pixel in the result image
// setting the pixel in the result image
bumpMap.setRGB(x, y, ImageUtils.vectorToColor(N.x, N.y, N.z));
}
}
@ -422,7 +422,7 @@ public final class ImageUtils {
* pixel's X coordinate
* @param y
* pixel's Y coordinate
* @return height reprezented by the given texture in the specified location
* @return height represented by the given texture in the specified location
*/
private static int getHeight(BufferedImage image, int x, int y) {
if (x < 0) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -72,6 +72,7 @@ import com.jme3.texture.Texture.WrapMode;
import com.jme3.texture.Texture2D;
import com.jme3.texture.image.ColorSpace;
import com.jme3.util.BufferUtils;
import com.jme3.util.PlaceholderAssets;
/**
* A class that is used in texture calculations.
@ -251,7 +252,11 @@ public class TextureHelper extends AbstractBlenderHelper {
blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition());
// Should the texture be flipped? It works for sinbad ..
result = new Texture2D(new ImageLoader().loadImage(blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true));
result = new ImageLoader().loadTexture(blenderContext.getAssetManager(), blenderContext.getInputStream(), dataFileBlock.getBlockPosition(), true);
if (result == null) {
result = new Texture2D(PlaceholderAssets.getPlaceholderImage(blenderContext.getAssetManager()));
LOGGER.fine("ImageLoader returned null. It probably failed to load the packed texture, using placeholder asset");
}
}
}
//} else {
@ -310,7 +315,7 @@ public class TextureHelper extends AbstractBlenderHelper {
* @param pos
* the relative position (value of range <0, 1> (both inclusive))
* @param size
* the size of the line the pixel lies on (width, heigth or
* the size of the line the pixel lies on (width, height or
* depth)
* @return the integer index of the pixel on the line of the specified width
*/
@ -429,10 +434,10 @@ public class TextureHelper extends AbstractBlenderHelper {
}
/**
* This method loads the textre from outside the blend file using the
* This method loads the texture from outside the blend file using the
* AssetManager that the blend file was loaded with. It returns a texture
* with a full assetKey that references the original texture so it later
* doesn't need to ba packed when the model data is serialized. It searches
* doesn't need to be packed when the model data is serialized. It searches
* the AssetManager for the full path if the model file is a relative path
* and will attempt to truncate the path if it is an absolute file path
* until the path can be found in the AssetManager. If the texture can not
@ -614,8 +619,15 @@ public class TextureHelper extends AbstractBlenderHelper {
int texflag = ((Number) textureData.mtex.getFieldValue("texflag")).intValue();
boolean negateTexture = (texflag & 0x04) != 0;
boolean colorSet = false;
for (int i = 0; i < mappings.length; ++i) {
if ((mappings[i] & mapto.intValue()) != 0) {
if(mappings[i] == MaterialContext.MTEX_COL) {
colorSet = true;
} else if(colorSet && mappings[i] == MaterialContext.MTEX_ALPHA) {
continue;
}
CombinedTexture combinedTexture = new CombinedTexture(mappings[i], !skyTexture);
int blendType = ((Number) textureData.mtex.getFieldValue("blendtype")).intValue();
float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
@ -646,8 +658,16 @@ public class TextureHelper extends AbstractBlenderHelper {
Map<Number, List<TextureData>> result = new HashMap<Number, List<TextureData>>();
for (TextureData data : textures) {
Number mapto = (Number) data.mtex.getFieldValue("mapto");
boolean colorSet = false;
for (int i = 0; i < mappings.length; ++i) {
if ((mappings[i] & mapto.intValue()) != 0) {
if(mappings[i] == MaterialContext.MTEX_COL) {
colorSet = true;
} else if(colorSet && mappings[i] == MaterialContext.MTEX_ALPHA) {
continue;
}
List<TextureData> datas = result.get(mappings[i]);
if (datas == null) {
datas = new ArrayList<TextureData>();
@ -668,4 +688,4 @@ public class TextureHelper extends AbstractBlenderHelper {
/** The name of the user's UV coordinates that are used for this texture. */
public String uvCoordinatesName;
}
}
}

@ -163,9 +163,19 @@ public class TextureBlenderAWT extends AbstractTextureBlender {
* the blender context
*/
protected void blendPixel(float[] result, float[] materialColor, float[] pixelColor, BlenderContext blenderContext) {
// We calculate first the importance of the texture (colFactor * texAlphaValue)
float blendFactor = this.blendFactor * pixelColor[3];
float oneMinusFactor = 1.0f - blendFactor, col;
// Then, we get the object material factor ((1 - texture importance) * matAlphaValue)
float oneMinusFactor = (1f - blendFactor) * materialColor[3];
// Finally, we can get the final blendFactor, which is 1 - the material factor.
blendFactor = 1f - oneMinusFactor;
// --- Compact method ---
// float blendFactor = this.blendFactor * (1f - ((1f - pixelColor[3]) * materialColor[3]));
// float oneMinusFactor = 1f - blendFactor;
float col;
switch (blendType) {
case MTEX_BLEND:
result[0] = blendFactor * pixelColor[0] + oneMinusFactor * materialColor[0];

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -40,7 +40,7 @@ public interface PhysicsCollisionGroupListener {
/**
* Called when two physics objects of the registered group are about to collide, <i>called from physics thread</i>.<br>
* This is only called when the collision will happen based on the collisionGroup and collideWithGroups
* settings in the PhysicsCollisionObject. That is the case when <b>one</b> of the partys has the
* settings in the PhysicsCollisionObject. That is the case when <b>one</b> of the parties has the
* collisionGroup of the other in its collideWithGroups set.<br>
* @param nodeA CollisionObject #1
* @param nodeB CollisionObject #2

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,6 +41,7 @@ import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
@ -162,8 +163,14 @@ public abstract class AbstractPhysicsControl implements PhysicsControl, JmeClone
}
}
@Override
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
throw new UnsupportedOperationException();
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial);
createSpatialData(this.spatial);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -48,9 +48,7 @@ import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.List;
@ -665,13 +663,6 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
rigidBody.setUserObject(null);
}
@Override
public Control cloneForSpatial(Spatial spatial) {
BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);
control.setJumpForce(jumpForce);
return control;
}
@Override
public Object jmeClone() {
BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -89,21 +89,10 @@ public class CharacterControl extends PhysicsCharacter implements PhysicsControl
return spatial.getWorldTranslation();
}
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
CharacterControl control = new CharacterControl(collisionShape, stepHeight);
control.setCcdMotionThreshold(getCcdMotionThreshold());
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
control.setCollideWithGroups(getCollideWithGroups());
control.setCollisionGroup(getCollisionGroup());
control.setFallSpeed(getFallSpeed());
control.setGravity(getGravity());
control.setJumpSpeed(getJumpSpeed());
control.setMaxSlope(getMaxSlope());
control.setPhysicsLocation(getPhysicsLocation());
control.setUpAxis(getUpAxis());
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
return control;
throw new UnsupportedOperationException();
}
@Override

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -95,20 +95,13 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl,
return spatial.getWorldRotation();
}
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
GhostControl control = new GhostControl(collisionShape);
control.setCcdMotionThreshold(getCcdMotionThreshold());
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
control.setCollideWithGroups(getCollideWithGroups());
control.setCollisionGroup(getCollisionGroup());
control.setPhysicsLocation(getPhysicsLocation());
control.setPhysicsRotation(getPhysicsRotationMatrix());
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
return control;
throw new UnsupportedOperationException();
}
@Override
@Override
public Object jmeClone() {
GhostControl control = new GhostControl(collisionShape);
control.setCcdMotionThreshold(getCcdMotionThreshold());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -59,9 +59,7 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.*;
@ -73,7 +71,7 @@ import java.util.logging.Logger;
* use this control you need a model with an AnimControl and a
* SkeletonControl.<br> This should be the case if you imported an animated
* model from Ogre or blender.<br> Note enabling/disabling the control
* add/removes it from the physic space<br> <p> This control creates collision
* add/removes it from the physics space<br> <p> This control creates collision
* shapes for each bones of the skeleton when you call
* spatial.addControl(ragdollControl). <ul> <li>The shape is HullCollision shape
* based on the vertices associated with each bone and based on a tweakable
@ -84,11 +82,11 @@ import java.util.logging.Logger;
* </ul> </p> <p> There are 2 modes for this control : <ul> <li><strong>The
* kinematic modes :</strong><br> this is the default behavior, this means that
* the collision shapes of the body are able to interact with physics enabled
* objects. in this mode physic shapes follow the moovements of the animated
* objects. in this mode physics shapes follow the motion of the animated
* skeleton (for example animated by a key framed animation) this mode is
* enabled by calling setKinematicMode(); </li> <li><strong>The ragdoll modes
* :</strong><br> To enable this behavior, you need to call setRagdollMode()
* method. In this mode the charater is entirely controled by physics, so it
* method. In this mode the character is entirely controlled by physics, so it
* will fall under the gravity and move if any force is applied to it. </li>
* </ul> </p>
*
@ -171,7 +169,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
}
/**
* contruct a KinematicRagdollControl
* construct a KinematicRagdollControl
*/
public KinematicRagdollControl() {
baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1);
@ -201,7 +199,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
if(mode == Mode.IK){
ikUpdate(tpf);
} else if (mode == mode.Ragdoll && targetModel.getLocalTranslation().equals(modelPosition)) {
//if the ragdoll has the control of the skeleton, we update each bone with its position in physic world space.
//if the ragdoll has the control of the skeleton, we update each bone with its position in physics world space.
ragDollUpdate(tpf);
} else {
kinematicUpdate(tpf);
@ -217,12 +215,12 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
Vector3f position = vars.vect1;
//retrieving bone position in physic world space
//retrieving bone position in physics world space
Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
//transforming this position with inverse transforms of the model
targetModel.getWorldTransform().transformInverseVector(p, position);
//retrieving bone rotation in physic world space
//retrieving bone rotation in physics world space
Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
//multiplying this rotation by the initialWorld rotation of the bone,
@ -255,7 +253,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
link.bone.setUserTransformsInModelSpace(position, tmpRot1);
} else {
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape.
//So we update them recusively
//So we update them recursively
RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList);
}
}
@ -264,7 +262,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
}
protected void kinematicUpdate(float tpf) {
//the ragdoll does not have the controll, so the keyframed animation updates the physic position of the physic bonces
//the ragdoll does not have control, so the keyframed animation updates the physics position of the physics bonces
TempVars vars = TempVars.get();
Quaternion tmpRot1 = vars.quat1;
Quaternion tmpRot2 = vars.quat2;
@ -420,7 +418,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
targetModel.getWorldRotation().mult(tmpRot1, tmpRot1);
tmpRot1.normalizeLocal();
//updating physic location/rotation of the physic bone
//updating physics location/rotation of the physics bone
link.rigidBody.setPhysicsLocation(position);
link.rigidBody.setPhysicsRotation(tmpRot1);
@ -707,9 +705,9 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
/**
* Enable or disable the ragdoll behaviour. if ragdollEnabled is true, the
* character motion will only be powerd by physics else, the characted will
* character motion will only be powered by physics else, the character will
* be animated by the keyframe animation, but will be able to physically
* interact with its physic environnement
* interact with its physics environment
*
* @param ragdollEnabled
*/
@ -789,9 +787,9 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
}
/**
* Set the control into Kinematic mode In theis mode, the collision shapes
* Set the control into Kinematic mode In this mode, the collision shapes
* follow the movements of the skeleton, and can interact with physical
* environement
* environment
*/
public void setKinematicMode() {
if (mode != Mode.Kinematic) {
@ -820,7 +818,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
}
/**
* retruns the mode of this control
* returns the mode of this control
*
* @return
*/
@ -903,7 +901,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
}
/**
* For internal use only specific render for the ragdoll(if debugging)
* For internal use only specific render for the ragdoll (if debugging)
*
* @param rm
* @param vp
@ -912,16 +910,6 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
public void render(RenderManager rm, ViewPort vp) {
}
@Override
public Control cloneForSpatial(Spatial spatial) {
KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);
control.setMode(mode);
control.setRootMass(rootMass);
control.setWeightThreshold(weightThreshold);
control.setApplyPhysicsLocal(applyLocal);
return control;
}
@Override
public Object jmeClone() {
KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -53,7 +53,6 @@ import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
@ -92,31 +91,10 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
super(shape, mass);
}
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
control.setAngularFactor(getAngularFactor());
control.setAngularSleepingThreshold(getAngularSleepingThreshold());
control.setCcdMotionThreshold(getCcdMotionThreshold());
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
control.setCollideWithGroups(getCollideWithGroups());
control.setCollisionGroup(getCollisionGroup());
control.setDamping(getLinearDamping(), getAngularDamping());
control.setFriction(getFriction());
control.setGravity(getGravity());
control.setKinematic(isKinematic());
control.setKinematicSpatial(isKinematicSpatial());
control.setLinearSleepingThreshold(getLinearSleepingThreshold());
control.setPhysicsLocation(getPhysicsLocation(null));
control.setPhysicsRotation(getPhysicsRotationMatrix(null));
control.setRestitution(getRestitution());
if (mass > 0) {
control.setAngularVelocity(getAngularVelocity());
control.setLinearVelocity(getLinearVelocity());
}
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
return control;
throw new UnsupportedOperationException();
}
@Override

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,7 +43,6 @@ import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner;
@ -108,54 +107,10 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
return spatial.getWorldRotation();
}
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
VehicleControl control = new VehicleControl(collisionShape, mass);
control.setAngularFactor(getAngularFactor());
control.setAngularSleepingThreshold(getAngularSleepingThreshold());
control.setAngularVelocity(getAngularVelocity());
control.setCcdMotionThreshold(getCcdMotionThreshold());
control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
control.setCollideWithGroups(getCollideWithGroups());
control.setCollisionGroup(getCollisionGroup());
control.setDamping(getLinearDamping(), getAngularDamping());
control.setFriction(getFriction());
control.setGravity(getGravity());
control.setKinematic(isKinematic());
control.setLinearSleepingThreshold(getLinearSleepingThreshold());
control.setLinearVelocity(getLinearVelocity());
control.setPhysicsLocation(getPhysicsLocation());
control.setPhysicsRotation(getPhysicsRotationMatrix());
control.setRestitution(getRestitution());
control.setFrictionSlip(getFrictionSlip());
control.setMaxSuspensionTravelCm(getMaxSuspensionTravelCm());
control.setSuspensionStiffness(getSuspensionStiffness());
control.setSuspensionCompression(tuning.suspensionCompression);
control.setSuspensionDamping(tuning.suspensionDamping);
control.setMaxSuspensionForce(getMaxSuspensionForce());
for (Iterator<VehicleWheel> it = wheels.iterator(); it.hasNext();) {
VehicleWheel wheel = it.next();
VehicleWheel newWheel = control.addWheel(wheel.getLocation(), wheel.getDirection(), wheel.getAxle(), wheel.getRestLength(), wheel.getRadius(), wheel.isFrontWheel());
newWheel.setFrictionSlip(wheel.getFrictionSlip());
newWheel.setMaxSuspensionTravelCm(wheel.getMaxSuspensionTravelCm());
newWheel.setSuspensionStiffness(wheel.getSuspensionStiffness());
newWheel.setWheelsDampingCompression(wheel.getWheelsDampingCompression());
newWheel.setWheelsDampingRelaxation(wheel.getWheelsDampingRelaxation());
newWheel.setMaxSuspensionForce(wheel.getMaxSuspensionForce());
//TODO: bad way finding children!
if (spatial instanceof Node) {
Node node = (Node) spatial;
Spatial wheelSpat = node.getChild(wheel.getWheelSpatial().getName());
if (wheelSpat != null) {
newWheel.setWheelSpatial(wheelSpat);
}
}
}
control.setApplyPhysicsLocal(isApplyPhysicsLocal());
return control;
throw new UnsupportedOperationException();
}
@Override

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -123,7 +123,7 @@ public class RagdollUtils {
/**
* Create a hull collision shape from linked vertices to this bone.
* Vertices have to be previoulsly gathered in a map using buildPointMap method
* Vertices have to be previously gathered in a map using buildPointMap method
*
* @param pointsMap
* @param boneIndices
@ -160,7 +160,7 @@ public class RagdollUtils {
return new HullCollisionShape(p);
}
//retruns the list of bone indices of the given bone and its child(if they are not in the boneList)
//returns the list of bone indices of the given bone and its child (if they are not in the boneList)
public static List<Integer> getBoneIndices(Bone bone, Skeleton skeleton, Set<String> boneList) {
List<Integer> list = new LinkedList<Integer>();
if (boneList.isEmpty()) {
@ -266,7 +266,7 @@ public class RagdollUtils {
/**
* Updates a bone position and rotation.
* if the child bones are not in the bone list this means, they are not associated with a physic shape.
* if the child bones are not in the bone list this means, they are not associated with a physics shape.
* So they have to be updated
* @param bone the bone
* @param pos the position

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -235,7 +235,7 @@ public class PhysicsSpace {
// collides = (bp1.collisionFilterGroup & bp.collisionFilterMask) != 0;
// }
// if (collides) {
// assert (bp.clientObject instanceof com.bulletphysics.collision.dispatch.CollisionObject && bp.clientObject instanceof com.bulletphysics.collision.dispatch.CollisionObject);
// assert (bp.clientObject instanceof com.bulletphysics.collision.dispatch.CollisionObject && bp1.clientObject instanceof com.bulletphysics.collision.dispatch.CollisionObject);
// com.bulletphysics.collision.dispatch.CollisionObject colOb = (com.bulletphysics.collision.dispatch.CollisionObject) bp.clientObject;
// com.bulletphysics.collision.dispatch.CollisionObject colOb1 = (com.bulletphysics.collision.dispatch.CollisionObject) bp1.clientObject;
// assert (colOb.getUserPointer() != null && colOb1.getUserPointer() != null);
@ -954,7 +954,7 @@ public class PhysicsSpace {
* determinism in physics. For example a maximum number of 2 can compensate
* for framerates as low as 30fps when the physics has the default accuracy
* of 60 fps. Note that setting this value too high can make the physics
* drive down its own fps in case its overloaded.
* drive down its own fps in case it's overloaded.
*
* @param steps The maximum number of extra steps, default is 4.
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -96,7 +96,7 @@ public abstract class PhysicsCollisionObject implements Savable {
* Sets the collision group number for this physics object. <br>
* The groups are integer bit masks and some pre-made variables are available in CollisionObject.
* All physics objects are by default in COLLISION_GROUP_01.<br>
* Two object will collide when <b>one</b> of the partys has the
* Two object will collide when <b>one</b> of the parties has the
* collisionGroup of the other in its collideWithGroups set.
* @param collisionGroup the collisionGroup to set
*/
@ -109,7 +109,7 @@ public abstract class PhysicsCollisionObject implements Savable {
/**
* Add a group that this object will collide with.<br>
* Two object will collide when <b>one</b> of the partys has the
* Two object will collide when <b>one</b> of the parties has the
* collisionGroup of the other in its collideWithGroups set.<br>
* @param collisionGroup
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -44,7 +44,7 @@ import java.util.logging.Logger;
/**
* <i>From bullet manual:</i><br>
* To create ragdolls, the conve twist constraint is very useful for limbs like the upper arm.
* To create ragdolls, the cone twist constraint is very useful for limbs like the upper arm.
* It is a special point to point constraint that adds cone and twist axis limits.
* The x-axis serves as twist axis.
* @author normenhansen

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -121,7 +121,7 @@ public class HingeJoint extends PhysicsJoint {
* @param high the high limit in radians.
* @param _softness the factor at which the velocity error correction starts operating,i.e a softness of 0.9 means that the vel. corr starts at 90% of the limit range.
* @param _biasFactor the magnitude of the position correction. It tells you how strictly the position error (drift ) is corrected.
* @param _relaxationFactor the rate at which velocity errors are corrected. This can be seen as the strength of the limits. A low value will make the the limits more spongy.
* @param _relaxationFactor the rate at which velocity errors are corrected. This can be seen as the strength of the limits. A low value will make the limits more spongy.
*/
public void setLimit(float low, float high, float _softness, float _biasFactor, float _relaxationFactor) {
biasFactor = _biasFactor;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -265,7 +265,7 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
// }
/**
* Sets the node to kinematic mode. in this mode the node is not affected by physics
* but affects other physics objects. Iits kinetic force is calculated by the amount
* but affects other physics objects. Its kinetic force is calculated by the amount
* of movement it is exposed to and its weight.
* @param kinematic
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -283,8 +283,8 @@ public class PhysicsVehicle extends PhysicsRigidBody {
}
/**
* This vaue caps the maximum suspension force, raise this above the default 6000 if your suspension cannot
* handle the weight of your vehcile.
* This value caps the maximum suspension force, raise this above the default 6000 if your suspension cannot
* handle the weight of your vehicle.
* @param maxSuspensionForce
*/
public void setMaxSuspensionForce(float maxSuspensionForce) {
@ -292,8 +292,8 @@ public class PhysicsVehicle extends PhysicsRigidBody {
}
/**
* This vaue caps the maximum suspension force, raise this above the default 6000 if your suspension cannot
* handle the weight of your vehcile.
* This value caps the maximum suspension force, raise this above the default 6000 if your suspension cannot
* handle the weight of your vehicle.
* @param wheel
* @param maxSuspensionForce
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -242,7 +242,7 @@ public class VehicleWheel implements Savable {
/**
* The maximum suspension force, raise this above the default 6000 if your suspension cannot
* handle the weight of your vehcile.
* handle the weight of your vehicle.
* @param maxSuspensionTravelCm
*/
public void setMaxSuspensionForce(float maxSuspensionForce) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2017 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,6 +35,7 @@ import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape;
import com.jme3.math.Matrix3f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
@ -111,9 +112,16 @@ public class DebugShapeFactory {
public static Mesh getDebugMesh(CollisionShape shape) {
Mesh mesh = new Mesh();
mesh = new Mesh();
DebugMeshCallback callback = new DebugMeshCallback();
/*
* Populate the mesh based on an unscaled shape;
* the shape's scale will be applied later, to the geometry.
*/
Vector3f savedScale = shape.getScale().clone();
shape.setScale(Vector3f.UNIT_XYZ);
getVertices(shape.getObjectId(), callback);
shape.setScale(savedScale);
mesh.setBuffer(Type.Position, 3, callback.getVertices());
mesh.getFloatBuffer(Type.Position).clear();
return mesh;

@ -15,7 +15,7 @@ import java.lang.annotation.Target;
* annotations of the same name at a single location.
*
* Example:
* <!-- &nbsp; is a hack that prevents @ from being the first charater on the line, which confuses Javadoc -->
* <!-- &nbsp; is a hack that prevents @ from being the first character on the line, which confuses Javadoc -->
* <code><pre>
* &nbsp; @DefaultQualifiers({
* &nbsp; @DefaultQualifier("NonNull"),

@ -1,365 +1,369 @@
/*
* Copyright (c) 2009-2012 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.animation;
import com.jme3.math.FastMath;
import com.jme3.util.TempVars;
import java.util.BitSet;
/**
* <code>AnimChannel</code> provides controls, such as play, pause,
* fast forward, etc, for an animation. The animation
* channel may influence the entire model or specific bones of the model's
* skeleton. A single model may have multiple animation channels influencing
* various parts of its body. For example, a character model may have an
* animation channel for its feet, and another for its torso, and
* the animations for each channel are controlled independently.
*
* @author Kirill Vainer
*/
public final class AnimChannel {
private static final float DEFAULT_BLEND_TIME = 0.15f;
private AnimControl control;
private BitSet affectedBones;
private Animation animation;
private Animation blendFrom;
private float time;
private float speed;
private float timeBlendFrom;
private float blendTime;
private float speedBlendFrom;
private boolean notified=false;
private LoopMode loopMode, loopModeBlendFrom;
private float blendAmount = 1f;
private float blendRate = 0;
AnimChannel(AnimControl control){
this.control = control;
}
/**
* Returns the parent control of this AnimChannel.
*
* @return the parent control of this AnimChannel.
* @see AnimControl
*/
public AnimControl getControl() {
return control;
}
/**
* @return The name of the currently playing animation, or null if
* none is assigned.
*
* @see AnimChannel#setAnim(java.lang.String)
*/
public String getAnimationName() {
return animation != null ? animation.getName() : null;
}
/**
* @return The loop mode currently set for the animation. The loop mode
* determines what will happen to the animation once it finishes
* playing.
*
* For more information, see the LoopMode enum class.
* @see LoopMode
* @see AnimChannel#setLoopMode(com.jme3.animation.LoopMode)
*/
public LoopMode getLoopMode() {
return loopMode;
}
/**
* @param loopMode Set the loop mode for the channel. The loop mode
* determines what will happen to the animation once it finishes
* playing.
*
* For more information, see the LoopMode enum class.
* @see LoopMode
*/
public void setLoopMode(LoopMode loopMode) {
this.loopMode = loopMode;
}
/**
* @return The speed that is assigned to the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*
* @see AnimChannel#setSpeed(float)
*/
public float getSpeed() {
return speed;
}
/**
* @param speed Set the speed of the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*/
public void setSpeed(float speed) {
this.speed = speed;
if(blendTime>0){
this.speedBlendFrom = speed;
blendTime = Math.min(blendTime, animation.getLength() / speed);
blendRate = 1/ blendTime;
}
}
/**
* @return The time of the currently playing animation. The time
* starts at 0 and continues on until getAnimMaxTime().
*
* @see AnimChannel#setTime(float)
*/
public float getTime() {
return time;
}
/**
* @param time Set the time of the currently playing animation, the time
* is clamped from 0 to {@link #getAnimMaxTime()}.
*/
public void setTime(float time) {
this.time = FastMath.clamp(time, 0, getAnimMaxTime());
}
/**
* @return The length of the currently playing animation, or zero
* if no animation is playing.
*
* @see AnimChannel#getTime()
*/
public float getAnimMaxTime(){
return animation != null ? animation.getLength() : 0f;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* This resets the time to zero, and optionally blends the animation
* over <code>blendTime</code> seconds with the currently playing animation.
* Notice that this method will reset the control's speed to 1.0.
*
* @param name The name of the animation to play
* @param blendTime The blend time over which to blend the new animation
* with the old one. If zero, then no blending will occur and the new
* animation will be applied instantly.
*/
public void setAnim(String name, float blendTime){
if (name == null)
throw new IllegalArgumentException("name cannot be null");
if (blendTime < 0f)
throw new IllegalArgumentException("blendTime cannot be less than zero");
Animation anim = control.animationMap.get(name);
if (anim == null)
throw new IllegalArgumentException("Cannot find animation named: '"+name+"'");
control.notifyAnimChange(this, name);
if (animation != null && blendTime > 0f){
this.blendTime = blendTime;
// activate blending
blendTime = Math.min(blendTime, anim.getLength() / speed);
blendFrom = animation;
timeBlendFrom = time;
speedBlendFrom = speed;
loopModeBlendFrom = loopMode;
blendAmount = 0f;
blendRate = 1f / blendTime;
}else{
blendFrom = null;
}
animation = anim;
time = 0;
speed = 1f;
loopMode = LoopMode.Loop;
notified = false;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* See {@link #setAnim(java.lang.String, float)}.
* The blendTime argument by default is 150 milliseconds.
*
* @param name The name of the animation to play
*/
public void setAnim(String name){
setAnim(name, DEFAULT_BLEND_TIME);
}
/**
* Add all the bones of the model's skeleton to be
* influenced by this animation channel.
*/
public void addAllBones() {
affectedBones = null;
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(String name) {
addBone(control.getSkeleton().getBone(name));
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(Bone bone) {
int boneIndex = control.getSkeleton().getBoneIndex(bone);
if(affectedBones == null) {
affectedBones = new BitSet(control.getSkeleton().getBoneCount());
}
affectedBones.set(boneIndex);
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone name and going toward the root bone.
*/
public void addToRootBone(String name) {
addToRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone and going toward the root bone.
*/
public void addToRootBone(Bone bone) {
addBone(bone);
while (bone.getParent() != null) {
bone = bone.getParent();
addBone(bone);
}
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given named bone and going toward its children.
*/
public void addFromRootBone(String name) {
addFromRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given bone and going toward its children.
*/
public void addFromRootBone(Bone bone) {
addBone(bone);
if (bone.getChildren() == null)
return;
for (Bone childBone : bone.getChildren()) {
addBone(childBone);
addFromRootBone(childBone);
}
}
BitSet getAffectedBones(){
return affectedBones;
}
public void reset(boolean rewind){
if(rewind){
setTime(0);
if(control.getSkeleton()!=null){
control.getSkeleton().resetAndUpdate();
}else{
TempVars vars = TempVars.get();
update(0, vars);
vars.release();
}
}
animation = null;
notified = false;
}
void update(float tpf, TempVars vars) {
if (animation == null)
return;
if (blendFrom != null && blendAmount != 1.0f){
// The blendFrom anim is set, the actual animation
// playing will be set
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
timeBlendFrom += tpf * speedBlendFrom;
timeBlendFrom = AnimationUtils.clampWrapTime(timeBlendFrom,
blendFrom.getLength(),
loopModeBlendFrom);
if (timeBlendFrom < 0){
timeBlendFrom = -timeBlendFrom;
speedBlendFrom = -speedBlendFrom;
}
blendAmount += tpf * blendRate;
if (blendAmount > 1f){
blendAmount = 1f;
blendFrom = null;
}
}
animation.setTime(time, blendAmount, control, this, vars);
time += tpf * speed;
if (animation.getLength() > 0){
if (!notified && (time >= animation.getLength() || time < 0)) {
if (loopMode == LoopMode.DontLoop) {
// Note that this flag has to be set before calling the notify
// since the notify may start a new animation and then unset
// the flag.
notified = true;
}
control.notifyAnimCycleDone(this, animation.getName());
}
}
time = AnimationUtils.clampWrapTime(time, animation.getLength(), loopMode);
if (time < 0){
// Negative time indicates that speed should be inverted
// (for cycle loop mode only)
time = -time;
speed = -speed;
}
}
}
/*
* Copyright (c) 2009-2012 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.animation;
import com.jme3.math.FastMath;
import com.jme3.util.TempVars;
import java.util.BitSet;
/**
* <code>AnimChannel</code> provides controls, such as play, pause,
* fast forward, etc, for an animation. The animation
* channel may influence the entire model or specific bones of the model's
* skeleton. A single model may have multiple animation channels influencing
* various parts of its body. For example, a character model may have an
* animation channel for its feet, and another for its torso, and
* the animations for each channel are controlled independently.
*
* @author Kirill Vainer
*/
public final class AnimChannel {
private static final float DEFAULT_BLEND_TIME = 0.15f;
private AnimControl control;
private BitSet affectedBones;
private Animation animation;
private Animation blendFrom;
private float time;
private float speed;
private float timeBlendFrom;
private float blendTime;
private float speedBlendFrom;
private boolean notified=false;
private LoopMode loopMode, loopModeBlendFrom;
private float blendAmount = 1f;
private float blendRate = 0;
public AnimChannel(){
}
public AnimChannel(AnimControl control){
this.control = control;
}
/**
* Returns the parent control of this AnimChannel.
*
* @return the parent control of this AnimChannel.
* @see AnimControl
*/
public AnimControl getControl() {
return control;
}
/**
* @return The name of the currently playing animation, or null if
* none is assigned.
*
* @see AnimChannel#setAnim(java.lang.String)
*/
public String getAnimationName() {
return animation != null ? animation.getName() : null;
}
/**
* @return The loop mode currently set for the animation. The loop mode
* determines what will happen to the animation once it finishes
* playing.
*
* For more information, see the LoopMode enum class.
* @see LoopMode
* @see AnimChannel#setLoopMode(com.jme3.animation.LoopMode)
*/
public LoopMode getLoopMode() {
return loopMode;
}
/**
* @param loopMode Set the loop mode for the channel. The loop mode
* determines what will happen to the animation once it finishes
* playing.
*
* For more information, see the LoopMode enum class.
* @see LoopMode
*/
public void setLoopMode(LoopMode loopMode) {
this.loopMode = loopMode;
}
/**
* @return The speed that is assigned to the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*
* @see AnimChannel#setSpeed(float)
*/
public float getSpeed() {
return speed;
}
/**
* @param speed Set the speed of the animation channel. The speed
* is a scale value starting from 0.0, at 1.0 the animation will play
* at its default speed.
*/
public void setSpeed(float speed) {
this.speed = speed;
if(blendTime>0){
this.speedBlendFrom = speed;
blendTime = Math.min(blendTime, animation.getLength() / speed);
blendRate = 1/ blendTime;
}
}
/**
* @return The time of the currently playing animation. The time
* starts at 0 and continues on until getAnimMaxTime().
*
* @see AnimChannel#setTime(float)
*/
public float getTime() {
return time;
}
/**
* @param time Set the time of the currently playing animation, the time
* is clamped from 0 to {@link #getAnimMaxTime()}.
*/
public void setTime(float time) {
this.time = FastMath.clamp(time, 0, getAnimMaxTime());
}
/**
* @return The length of the currently playing animation, or zero
* if no animation is playing.
*
* @see AnimChannel#getTime()
*/
public float getAnimMaxTime(){
return animation != null ? animation.getLength() : 0f;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* This resets the time to zero, and optionally blends the animation
* over <code>blendTime</code> seconds with the currently playing animation.
* Notice that this method will reset the control's speed to 1.0.
*
* @param name The name of the animation to play
* @param blendTime The blend time over which to blend the new animation
* with the old one. If zero, then no blending will occur and the new
* animation will be applied instantly.
*/
public void setAnim(String name, float blendTime){
if (name == null)
throw new IllegalArgumentException("name cannot be null");
if (blendTime < 0f)
throw new IllegalArgumentException("blendTime cannot be less than zero");
Animation anim = control.animationMap.get(name);
if (anim == null)
throw new IllegalArgumentException("Cannot find animation named: '"+name+"'");
control.notifyAnimChange(this, name);
if (animation != null && blendTime > 0f){
this.blendTime = blendTime;
// activate blending
blendTime = Math.min(blendTime, anim.getLength() / speed);
blendFrom = animation;
timeBlendFrom = time;
speedBlendFrom = speed;
loopModeBlendFrom = loopMode;
blendAmount = 0f;
blendRate = 1f / blendTime;
}else{
blendFrom = null;
}
animation = anim;
time = 0;
speed = 1f;
loopMode = LoopMode.Loop;
notified = false;
}
/**
* Set the current animation that is played by this AnimChannel.
* <p>
* See {@link #setAnim(java.lang.String, float)}.
* The blendTime argument by default is 150 milliseconds.
*
* @param name The name of the animation to play
*/
public void setAnim(String name){
setAnim(name, DEFAULT_BLEND_TIME);
}
/**
* Add all the bones of the model's skeleton to be
* influenced by this animation channel.
*/
public void addAllBones() {
affectedBones = null;
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(String name) {
addBone(control.getSkeleton().getBone(name));
}
/**
* Add a single bone to be influenced by this animation channel.
*/
public void addBone(Bone bone) {
int boneIndex = control.getSkeleton().getBoneIndex(bone);
if(affectedBones == null) {
affectedBones = new BitSet(control.getSkeleton().getBoneCount());
}
affectedBones.set(boneIndex);
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone name and going toward the root bone.
*/
public void addToRootBone(String name) {
addToRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel starting from the
* given bone and going toward the root bone.
*/
public void addToRootBone(Bone bone) {
addBone(bone);
while (bone.getParent() != null) {
bone = bone.getParent();
addBone(bone);
}
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given named bone and going toward its children.
*/
public void addFromRootBone(String name) {
addFromRootBone(control.getSkeleton().getBone(name));
}
/**
* Add bones to be influenced by this animation channel, starting
* from the given bone and going toward its children.
*/
public void addFromRootBone(Bone bone) {
addBone(bone);
if (bone.getChildren() == null)
return;
for (Bone childBone : bone.getChildren()) {
addBone(childBone);
addFromRootBone(childBone);
}
}
BitSet getAffectedBones(){
return affectedBones;
}
public void reset(boolean rewind){
if(rewind){
setTime(0);
if(control.getSkeleton()!=null){
control.getSkeleton().resetAndUpdate();
}else{
TempVars vars = TempVars.get();
update(0, vars);
vars.release();
}
}
animation = null;
notified = false;
}
void update(float tpf, TempVars vars) {
if (animation == null)
return;
if (blendFrom != null && blendAmount != 1.0f){
// The blendFrom anim is set, the actual animation
// playing will be set
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
timeBlendFrom += tpf * speedBlendFrom;
timeBlendFrom = AnimationUtils.clampWrapTime(timeBlendFrom,
blendFrom.getLength(),
loopModeBlendFrom);
if (timeBlendFrom < 0){
timeBlendFrom = -timeBlendFrom;
speedBlendFrom = -speedBlendFrom;
}
blendAmount += tpf * blendRate;
if (blendAmount > 1f){
blendAmount = 1f;
blendFrom = null;
}
}
animation.setTime(time, blendAmount, control, this, vars);
time += tpf * speed;
if (animation.getLength() > 0){
if (!notified && (time >= animation.getLength() || time < 0)) {
if (loopMode == LoopMode.DontLoop) {
// Note that this flag has to be set before calling the notify
// since the notify may start a new animation and then unset
// the flag.
notified = true;
}
control.notifyAnimCycleDone(this, animation.getName());
}
}
time = AnimationUtils.clampWrapTime(time, animation.getLength(), loopMode);
if (time < 0){
// Negative time indicates that speed should be inverted
// (for cycle loop mode only)
time = -time;
speed = -speed;
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,19 +34,16 @@ package com.jme3.animation;
import com.jme3.export.*;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Mesh;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.TempVars;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* <code>AnimControl</code> is a Spatial control that allows manipulation
@ -108,32 +105,6 @@ public final class AnimControl extends AbstractControl implements Cloneable, Jme
public AnimControl() {
}
/**
* Internal use only.
*/
@Override
public Control cloneForSpatial(Spatial spatial) {
try {
AnimControl clone = (AnimControl) super.clone();
clone.spatial = spatial;
clone.channels = new ArrayList<AnimChannel>();
clone.listeners = new ArrayList<AnimEventListener>();
if (skeleton != null) {
clone.skeleton = new Skeleton(skeleton);
}
// animationMap is cloned, but only ClonableTracks will be cloned as they need a reference to a cloned spatial
for (Entry<String, Animation> animEntry : animationMap.entrySet()) {
clone.animationMap.put(animEntry.getKey(), animEntry.getValue().cloneForSpatial(spatial));
}
return clone;
} catch (CloneNotSupportedException ex) {
throw new AssertionError();
}
}
@Override
public Object jmeClone() {
AnimControl clone = (AnimControl) super.jmeClone();

@ -31,17 +31,15 @@
*/
package com.jme3.animation;
import static com.jme3.animation.LoopMode.Cycle;
import static com.jme3.animation.LoopMode.DontLoop;
import static com.jme3.animation.LoopMode.Loop;
/**
*
* @author Nehon
*/
public class AnimationUtils {
public AnimationUtils(){
}
/**
* Clamps the time according to duration and loopMode
* @param time
@ -50,7 +48,7 @@ public class AnimationUtils {
* @return
*/
public static float clampWrapTime(float time, float duration, LoopMode loopMode){
if (time == 0) {
if (time == 0 || duration == 0) {
return 0; // prevent division by 0 errors
}
switch (loopMode) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2017 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,15 +32,15 @@
package com.jme3.animation;
import com.jme3.export.*;
import com.jme3.material.MatParamOverride;
import com.jme3.math.*;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.*;
import com.jme3.shader.VarType;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.ArrayList;
@ -550,7 +550,7 @@ public final class Bone implements Savable, JmeCloneable {
}
/**
* Updates world transforms for this bone and it's children.
* Updates world transforms for this bone and its children.
*/
public final void update() {
this.updateModelTransforms();
@ -590,7 +590,7 @@ public final class Bone implements Savable, JmeCloneable {
}
/**
* Reset the bone and it's children to bind pose.
* Reset the bone and its children to bind pose.
*/
final void reset() {
if (!userControl) {
@ -677,7 +677,7 @@ public final class Bone implements Savable, JmeCloneable {
modelPos.set(translation);
modelRot.set(rotation);
//if there is an attached Node we need to set it's local transforms too.
//if there is an attached Node we need to set its local transforms too.
if(attachNode != null){
attachNode.setLocalTranslation(translation);
attachNode.setLocalRotation(rotation);
@ -723,6 +723,8 @@ public final class Bone implements Savable, JmeCloneable {
if (attachNode == null) {
attachNode = new Node(name + "_attachnode");
attachNode.setUserData("AttachedBone", this);
//We don't want the node to have a numBone set by a parent node so we force it to null
attachNode.addMatParamOverride(new MatParamOverride(VarType.Int, "NumberOfBones", null));
}
return attachNode;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,6 +35,8 @@ import com.jme3.export.*;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.BitSet;
@ -43,10 +45,10 @@ import java.util.BitSet;
*
* @author Kirill Vainer
*/
public final class BoneTrack implements Track {
public final class BoneTrack implements JmeCloneable, Track {
/**
* Bone index in the skeleton which this track effects.
* Bone index in the skeleton which this track affects.
*/
private int targetBoneIndex;
@ -138,16 +140,23 @@ public final class BoneTrack implements Track {
/**
* Set the translations and rotations for this bone track
* @param times a float array with the time of each frame
* @param translations the translation of the bone for each frame
* @param rotations the rotation of the bone for each frame
*
* @param times the time of each frame, measured from the start of the track
* (not null, length&gt;0)
* @param translations the translation of the bone for each frame (not null,
* same length as times)
* @param rotations the rotation of the bone for each frame (not null, same
* length as times)
*/
public void setKeyframes(float[] times, Vector3f[] translations, Quaternion[] rotations) {
if (times.length == 0) {
throw new RuntimeException("BoneTrack with no keyframes!");
}
assert times.length == translations.length && times.length == rotations.length;
assert translations != null;
assert times.length == translations.length;
assert rotations != null;
assert times.length == rotations.length;
this.times = times;
this.translations = new CompactVector3Array();
@ -160,15 +169,19 @@ public final class BoneTrack implements Track {
/**
* Set the translations, rotations and scales for this bone track
* @param times a float array with the time of each frame
* @param translations the translation of the bone for each frame
* @param rotations the rotation of the bone for each frame
* @param scales the scale of the bone for each frame
*
* @param times the time of each frame, measured from the start of the track
* (not null, length&gt;0)
* @param translations the translation of the bone for each frame (not null,
* same length as times)
* @param rotations the rotation of the bone for each frame (not null, same
* length as times)
* @param scales the scale of the bone for each frame (ignored if null)
*/
public void setKeyframes(float[] times, Vector3f[] translations, Quaternion[] rotations, Vector3f[] scales) {
this.setKeyframes(times, translations, rotations);
assert times.length == scales.length;
if (scales != null) {
assert times.length == scales.length;
this.scales = new CompactVector3Array();
this.scales.add(scales);
this.scales.freeze();
@ -261,33 +274,48 @@ public final class BoneTrack implements Track {
public float[] getKeyFrameTimes() {
return times;
}
/**
* This method creates a clone of the current object.
* @return a clone of the current object
* Create a deep clone of this track.
*
* @return a new track
*/
@Override
public BoneTrack clone() {
int tablesLength = times.length;
float[] times = this.times.clone();
Vector3f[] sourceTranslations = this.getTranslations();
Quaternion[] sourceRotations = this.getRotations();
Vector3f[] sourceScales = this.getScales();
return Cloner.deepClone(this);
}
Vector3f[] translations = new Vector3f[tablesLength];
Quaternion[] rotations = new Quaternion[tablesLength];
Vector3f[] scales = new Vector3f[tablesLength];
for (int i = 0; i < tablesLength; ++i) {
translations[i] = sourceTranslations[i].clone();
rotations[i] = sourceRotations[i].clone();
scales[i] = sourceScales != null ? sourceScales[i].clone() : new Vector3f(1.0f, 1.0f, 1.0f);
/**
* Create a shallow clone for the JME cloner.
*
* @return a new track
*/
@Override
public BoneTrack jmeClone() {
try {
return (BoneTrack) super.clone();
} catch (CloneNotSupportedException exception) {
throw new RuntimeException("Can't clone track", exception);
}
// Need to use the constructor here because of the final fields used in this class
return new BoneTrack(targetBoneIndex, times, translations, rotations, scales);
}
/**
* Callback from {@link com.jme3.util.clone.Cloner} to convert this
* shallow-cloned track into a deep-cloned one, using the specified cloner
* to resolve copied fields.
*
* @param cloner the cloner currently cloning this control (not null)
* @param original the track from which this track was shallow-cloned
* (unused)
*/
@Override
public void cloneFields(Cloner cloner, Object original) {
translations = cloner.clone(translations);
rotations = cloner.clone(rotations);
scales = cloner.clone(scales);
times = cloner.clone(times);
}
@Override
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,6 +31,8 @@
*/
package com.jme3.animation;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
@ -40,7 +42,7 @@ import java.util.Map;
* @author Lim, YongHoon
* @param <T>
*/
public abstract class CompactArray<T> {
public abstract class CompactArray<T> implements JmeCloneable {
private Map<T, Integer> indexPool = new HashMap<T, Integer>();
protected int[] index;
@ -68,6 +70,7 @@ public abstract class CompactArray<T> {
* They are serialized automatically when get() method is called.
* @param objArray
*/
@SuppressWarnings("unchecked")
public void add(T... objArray) {
if (objArray == null || objArray.length == 0) {
return;
@ -186,10 +189,11 @@ public abstract class CompactArray<T> {
}
/**
* retrun an array of indices for the given objects
* Return an array of indices for the given objects
* @param objArray
* @return
*/
@SuppressWarnings("unchecked")
public final int[] getIndex(T... objArray) {
int[] index = new int[objArray.length];
for (int i = 0; i < index.length; i++) {
@ -228,6 +232,7 @@ public abstract class CompactArray<T> {
* decompress and return object array
* @return decompress and return object array
*/
@SuppressWarnings("unchecked")
public final T[] toObjectArray() {
try {
T[] compactArr = (T[]) Array.newInstance(getElementClass(), getSerializedSize() / getTupleSize());
@ -247,6 +252,47 @@ public abstract class CompactArray<T> {
}
}
/**
* Create a deep clone of this array.
*
* @return a new array
* @throws java.lang.CloneNotSupportedException
*/
@Override
public Object clone() throws CloneNotSupportedException {
return Cloner.deepClone(this);
}
/**
* Create a shallow clone for the JME cloner.
*
* @return a new array
*/
@Override
public Object jmeClone() {
try {
return super.clone();
} catch (CloneNotSupportedException exception) {
throw new RuntimeException("Can't clone array", exception);
}
}
/**
* Callback from {@link com.jme3.util.clone.Cloner} to convert this
* shallow-cloned array into a deep-cloned one, using the specified cloner
* to resolve copied fields.
*
* @param cloner the cloner currently cloning this control (not null)
* @param original the array from which this array was shallow-cloned
* (unused)
*/
@Override
public void cloneFields(Cloner cloner, Object original) {
indexPool = cloner.clone(indexPool);
index = cloner.clone(index);
array = cloner.clone(array);
}
/**
* serialize object
* @param compactIndex compacted object index

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -42,18 +42,16 @@ import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* EffectTrack is a track to add to an existing animation, to emit particles
* during animations for example : exhausts, dust raised by foot steps, shock
* waves, lightnings etc...
* during animations for example: exhaust, dust raised by footsteps, shock
* waves, lightning, etc...
*
* usage is
* <pre>
@ -62,9 +60,9 @@ import java.util.logging.Logger;
* control.getAnim("TheAnim").addTrack(track);
* </pre>
*
* if the emitter has emits 0 particles per seconds emmitAllPArticles will be
* called on it at time 0 + startOffset. if it he it has more it will start
* emit normally at time 0 + startOffset.
* if the emitter emits 0 particles per second, emitAllPArticles will be
* called on it at time 0 + startOffset. if it has more it will start
* emitting normally at time 0 + startOffset.
*
*
* @author Nehon
@ -132,19 +130,6 @@ public class EffectTrack implements ClonableTrack {
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {
}
@Override
public Control cloneForSpatial(Spatial spatial) {
KillParticleControl c = new KillParticleControl();
//this control should be removed as it shouldn't have been persisted in the first place
//In the quest to find the less hackish solution to achieve this,
//making it remove itself from the spatial in the first update loop when loaded was the less bad.
c.remove = true;
c.setSpatial(spatial);
return c;
}
};
//Anim listener that stops the Emmitter when the animation is finished or changed.
@ -213,7 +198,7 @@ public class EffectTrack implements ClonableTrack {
control.addListener(new OnEndListener());
initialized = true;
}
//checking fo time to trigger the effect
//checking for time to trigger the effect
if (!emitted && time >= startOffset) {
emitted = true;
emitter.setCullHint(CullHint.Dynamic);
@ -430,7 +415,7 @@ public class EffectTrack implements ClonableTrack {
*/
public void write(JmeExporter ex) throws IOException {
OutputCapsule out = ex.getCapsule(this);
//reseting the particle emission rate on the emitter before saving.
//reset the particle emission rate on the emitter before saving.
emitter.setParticlesPerSec(particlesPerSeconds);
out.write(emitter, "emitter", null);
out.write(particlesPerSeconds, "particlesPerSeconds", 0);
@ -449,7 +434,7 @@ public class EffectTrack implements ClonableTrack {
public void read(JmeImporter im) throws IOException {
InputCapsule in = im.getCapsule(this);
this.particlesPerSeconds = in.readFloat("particlesPerSeconds", 0);
//reading the emitter even if the track will then reference its cloned counter part if it's loaded with the assetManager.
//reading the emitter even if the track will then reference its cloned counterpart if it's loaded with the assetManager.
//This also avoid null pointer exception if the model is not loaded via the AssetManager.
emitter = (ParticleEmitter) in.readSavable("emitter", null);
emitter.setParticlesPerSec(0);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -53,7 +53,7 @@ public final class Skeleton implements Savable, JmeCloneable {
private Bone[] boneList;
/**
* Contains the skinning matrices, multiplying it by a vertex effected by a bone
* Contains the skinning matrices, multiplying it by a vertex affected by a bone
* will cause it to go to the animated position.
*/
private transient Matrix4f[] skinningMatrixes;
@ -169,7 +169,7 @@ public final class Skeleton implements Savable, JmeCloneable {
}
/**
* Saves the current skeleton state as it's binding pose.
* Saves the current skeleton state as its binding pose.
*/
public void setBindingPose() {
for (int i = rootBones.length - 1; i >= 0; i--) {
@ -304,6 +304,7 @@ public final class Skeleton implements Savable, JmeCloneable {
createSkinningMatrices();
for (Bone rootBone : rootBones) {
rootBone.reset();
rootBone.update();
rootBone.setBindingPose();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2017 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,21 +35,18 @@ import com.jme3.export.*;
import com.jme3.material.MatParamOverride;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix4f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.RendererException;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.*;
import com.jme3.scene.*;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.shader.VarType;
import com.jme3.util.*;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -145,6 +142,12 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
}
private boolean testHardwareSupported(RenderManager rm) {
//Only 255 bones max supported with hardware skinning
if (skeleton.getBoneCount() > 255) {
return false;
}
switchToHardware();
try {
@ -158,7 +161,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
/**
* Specifies if hardware skinning is preferred. If it is preferred and
* supported by GPU, it shall be enabled, if its not preferred, or not
* supported by GPU, it shall be enabled, if it's not preferred, or not
* supported by GPU, then it shall be disabled.
*
* @param preferred
@ -326,7 +329,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
bpb.clear();
bnb.clear();
//reseting bind tangents if there is a bind tangent buffer
//reset bind tangents if there is a bind tangent buffer
VertexBuffer bindTangents = mesh.getBuffer(Type.BindPoseTangent);
if (bindTangents != null) {
VertexBuffer tangents = mesh.getBuffer(Type.Tangent);
@ -344,47 +347,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
}
}
@Override
public Control cloneForSpatial(Spatial spatial) {
Node clonedNode = (Node) spatial;
SkeletonControl clone = new SkeletonControl();
AnimControl ctrl = spatial.getControl(AnimControl.class);
if (ctrl != null) {
// AnimControl is responsible for cloning the skeleton, not
// SkeletonControl.
clone.skeleton = ctrl.getSkeleton();
} else {
// If there's no AnimControl, create the clone ourselves.
clone.skeleton = new Skeleton(skeleton);
}
clone.hwSkinningDesired = this.hwSkinningDesired;
clone.hwSkinningEnabled = this.hwSkinningEnabled;
clone.hwSkinningSupported = this.hwSkinningSupported;
clone.hwSkinningTested = this.hwSkinningTested;
clone.setSpatial(clonedNode);
// Fix attachments for the cloned node
for (int i = 0; i < clonedNode.getQuantity(); i++) {
// go through attachment nodes, apply them to correct bone
Spatial child = clonedNode.getChild(i);
if (child instanceof Node) {
Node clonedAttachNode = (Node) child;
Bone originalBone = (Bone) clonedAttachNode.getUserData("AttachedBone");
if (originalBone != null) {
Bone clonedBone = clone.skeleton.getBone(originalBone.getName());
clonedAttachNode.setUserData("AttachedBone", clonedBone);
clonedBone.setAttachmentsNode(clonedAttachNode);
}
}
}
return clone;
}
@Override
public Object jmeClone() {
return super.jmeClone();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,16 +41,14 @@ import com.jme3.scene.Spatial;
import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.Arrays;
/**
* This class represents the track for spatial animation.
*
* @author Marcin Roguski (Kaelthas)
*/
public class SpatialTrack implements Track, JmeCloneable {
public class SpatialTrack implements JmeCloneable, Track {
/**
* Translations of the track.
@ -250,9 +248,16 @@ public class SpatialTrack implements Track, JmeCloneable {
return times == null ? 0 : times[times.length - 1] - times[0];
}
/**
* Create a clone with the same track spatial.
*
* @return a new track
*/
@Override
public Track clone() {
return (Track) jmeClone();
public SpatialTrack clone() {
Cloner cloner = new Cloner();
cloner.setClonedValue(trackSpatial, trackSpatial);
return cloner.clone(this);
}
@Override
@ -268,24 +273,38 @@ public class SpatialTrack implements Track, JmeCloneable {
return trackSpatial;
}
/**
* Create a shallow clone for the JME cloner.
*
* @return a new track
*/
@Override
public Object jmeClone() {
int tablesLength = times.length;
float[] timesCopy = this.times.clone();
Vector3f[] translationsCopy = this.getTranslations() == null ? null : Arrays.copyOf(this.getTranslations(), tablesLength);
Quaternion[] rotationsCopy = this.getRotations() == null ? null : Arrays.copyOf(this.getRotations(), tablesLength);
Vector3f[] scalesCopy = this.getScales() == null ? null : Arrays.copyOf(this.getScales(), tablesLength);
//need to use the constructor here because of the final fields used in this class
return new SpatialTrack(timesCopy, translationsCopy, rotationsCopy, scalesCopy);
public SpatialTrack jmeClone() {
try {
return (SpatialTrack) super.clone();
} catch (CloneNotSupportedException exception) {
throw new RuntimeException("Can't clone track", exception);
}
}
/**
* Callback from {@link com.jme3.util.clone.Cloner} to convert this
* shallow-cloned track into a deep-cloned one, using the specified cloner
* to resolve copied fields.
*
* @param cloner the cloner currently cloning this control (not null)
* @param original the track from which this track was shallow-cloned
* (unused)
*/
@Override
public void cloneFields(Cloner cloner, Object original) {
this.trackSpatial = cloner.clone(((SpatialTrack) original).trackSpatial);
translations = cloner.clone(translations);
rotations = cloner.clone(rotations);
scales = cloner.clone(scales);
trackSpatial = cloner.clone(trackSpatial);
times = cloner.clone(times);
}
@Override
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -44,9 +44,9 @@ public interface Track extends Savable, Cloneable {
* given parameters.
*
* @param time The time in the animation
* @param weight The weight from 0 to 1 on how much to apply the track
* @param control The control which the track should effect
* @param channel The channel which the track should effect
* @param weight The weight from 0 to 1 on how much to apply the track
* @param control The control which the track should affect
* @param channel The channel which the track should affect
*/
public void setTime(float time, float weight, AnimControl control, AnimChannel channel, TempVars vars);

@ -59,6 +59,8 @@ public class DetailedProfilerState extends BaseAppState {
private ColorRGBA dimmedOrange = ColorRGBA.Orange.mult(0.7f);
private ColorRGBA dimmedRed = ColorRGBA.Red.mult(0.7f);
private ProfilerInputListener inputListener = new ProfilerInputListener();
public DetailedProfilerState() {
}
@ -119,23 +121,17 @@ public class DetailedProfilerState extends BaseAppState {
if (inputManager != null) {
inputManager.addMapping(TOGGLE_KEY, new KeyTrigger(KeyInput.KEY_F6));
inputManager.addMapping(CLICK_KEY, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals(TOGGLE_KEY) && isPressed) {
setEnabled(!isEnabled());
}
if (isEnabled() && name.equals(CLICK_KEY) && isPressed) {
handleClick(inputManager.getCursorPosition());
}
}
}, TOGGLE_KEY, CLICK_KEY);
inputManager.addListener(inputListener, TOGGLE_KEY, CLICK_KEY);
}
}
@Override
protected void cleanup(Application app) {
ui.detachAllChildren();
InputManager manager = getApplication().getInputManager();
manager.deleteMapping(TOGGLE_KEY);
manager.deleteMapping(CLICK_KEY);
manager.removeListener(inputListener);
}
@Override
@ -441,8 +437,18 @@ public class DetailedProfilerState extends BaseAppState {
public String toString() {
return label.getText() + " - " + df.format(getMsFromNs(cpuValue)) + "ms / " + df.format(getMsFromNs(gpuValue)) + "ms";
}
}
private class ProfilerInputListener implements ActionListener {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals(TOGGLE_KEY) && isPressed) {
setEnabled(!isEnabled());
}
if (isEnabled() && name.equals(CLICK_KEY) && isPressed) {
handleClick(getApplication().getInputManager().getCursorPosition());
}
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -117,11 +117,12 @@ public class StatsView extends Node implements Control, JmeCloneable {
//statistics.clearFrame();
}
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
return (Control) spatial;
throw new UnsupportedOperationException();
}
@Override
public StatsView jmeClone() {
throw new UnsupportedOperationException("Not yet implemented.");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -80,10 +80,10 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
/**
* This constructor allows you to specify the output file path of the screenshot.
* Include the seperator at the end of the path.
* Use an emptry string to use the application folder. Use NULL to use the system
* Include the separator at the end of the path.
* Use an empty string to use the application folder. Use NULL to use the system
* default storage folder.
* @param filePath The screenshot file path to use. Include the seperator at the end of the path.
* @param filePath The screenshot file path to use. Include the separator at the end of the path.
*/
public ScreenshotAppState(String filePath) {
this.filePath = filePath;
@ -91,11 +91,11 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
/**
* This constructor allows you to specify the output file path of the screenshot.
* Include the seperator at the end of the path.
* Use an emptry string to use the application folder. Use NULL to use the system
* Include the separator at the end of the path.
* Use an empty string to use the application folder. Use NULL to use the system
* default storage folder.
* @param filePath The screenshot file path to use. Include the seperator at the end of the path.
* @param fileName The name of the file to save the screeshot as.
* @param filePath The screenshot file path to use. Include the separator at the end of the path.
* @param fileName The name of the file to save the screenshot as.
*/
public ScreenshotAppState(String filePath, String fileName) {
this.filePath = filePath;
@ -105,10 +105,10 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
/**
* This constructor allows you to specify the output file path of the screenshot and
* a base index for the shot index.
* Include the seperator at the end of the path.
* Use an emptry string to use the application folder. Use NULL to use the system
* Include the separator at the end of the path.
* Use an empty string to use the application folder. Use NULL to use the system
* default storage folder.
* @param filePath The screenshot file path to use. Include the seperator at the end of the path.
* @param filePath The screenshot file path to use. Include the separator at the end of the path.
* @param shotIndex The base index for screen shots. The first screen shot will have
* shotIndex + 1 appended, the next shotIndex + 2, and so on.
*/
@ -120,11 +120,11 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
/**
* This constructor allows you to specify the output file path of the screenshot and
* a base index for the shot index.
* Include the seperator at the end of the path.
* Use an emptry string to use the application folder. Use NULL to use the system
* Include the separator at the end of the path.
* Use an empty string to use the application folder. Use NULL to use the system
* default storage folder.
* @param filePath The screenshot file path to use. Include the seperator at the end of the path.
* @param fileName The name of the file to save the screeshot as.
* @param filePath The screenshot file path to use. Include the separator at the end of the path.
* @param fileName The name of the file to save the screenshot as.
* @param shotIndex The base index for screen shots. The first screen shot will have
* shotIndex + 1 appended, the next shotIndex + 2, and so on.
*/
@ -136,10 +136,10 @@ public class ScreenshotAppState extends AbstractAppState implements ActionListen
/**
* Set the file path to store the screenshot.
* Include the seperator at the end of the path.
* Use an emptry string to use the application folder. Use NULL to use the system
* Include the separator at the end of the path.
* Use an empty string to use the application folder. Use NULL to use the system
* default storage folder.
* @param filePath File path to use to store the screenshot. Include the seperator at the end of the path.
* @param filePath File path to use to store the screenshot. Include the separator at the end of the path.
*/
public void setFilePath(String filePath) {
this.filePath = filePath;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -217,7 +217,7 @@ public interface AssetManager {
* Load an asset from a key, the asset will be located
* by one of the {@link AssetLocator} implementations provided in the
* {@link AssetManager#registerLocator(java.lang.String, java.lang.Class) }
* call. If located successfully, it will be loaded via the the appropriate
* call. If located successfully, it will be loaded via the appropriate
* {@link AssetLoader} implementation based on the file's extension, as
* specified in the call
* {@link AssetManager#registerLoader(java.lang.Class, java.lang.String[]) }.

@ -32,6 +32,7 @@
package com.jme3.asset;
import com.jme3.asset.cache.AssetCache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -279,9 +280,9 @@ final class ImplHandler {
// Synchronized access must be used for any ops on classToLoaderMap
// Find the loader ImplThreadLocal for this class
synchronized (classToLoaderMap){
ImplThreadLocal local = classToLoaderMap.get(loaderType);
// Remove it from the class->loader map
classToLoaderMap.remove(loaderType);
ImplThreadLocal local = classToLoaderMap.remove(loaderType);
if (local == null) return;
// Remove it from the extension->loader map
for (String extension : local.getExtensions()){
extensionToLoaderMap.remove(extension);

@ -112,11 +112,10 @@ public class WeakRefCloneAssetCache implements AssetCache {
// might not even have this asset anymore, it is OK.
if (smartCache.remove(key) != null){
removedAssets ++;
//System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache");
}
}
if (removedAssets >= 1) {
logger.log(Level.FINE, "WeakRefAssetCache: {0} assets were purged from the cache.", removedAssets);
logger.log(Level.FINE, "WeakRefCloneAssetCache: {0} assets were purged from the cache.", removedAssets);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012, 2016 jMonkeyEngine
* Copyright (c) 2009-2012, 2016, 2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -221,7 +221,7 @@ public class AudioNode extends Node implements AudioSource {
/**
* Start playing an instance of this audio. This method can be used
* to play the same <code>AudioNode</code> multiple times. Note
* that changes to the parameters of this AudioNode will not effect the
* that changes to the parameters of this AudioNode will not affect the
* instances already playing.
*/
public void playInstance(){
@ -278,8 +278,8 @@ public class AudioNode extends Node implements AudioSource {
* the dry filter will only influence the "dry" portion of the audio,
* e.g. not the reverberated parts of the AudioNode playing.
*
* See the relevent documentation for the {@link Filter} to determine
* the effect.
* See the relevant documentation for the {@link Filter} to determine the
* effect.
*
* @param dryFilter The filter to set, or null to disable dry filter.
*/
@ -692,7 +692,7 @@ public class AudioNode extends Node implements AudioSource {
/**
* Set the audio node as positional.
* The position, velocity, and distance parameters effect positional
* The position, velocity, and distance parameters affect positional
* audio nodes. Set to false if the audio node should play in "headspace".
*
* @param positional True if the audio node should be positional, otherwise

@ -12,37 +12,37 @@ public interface AL {
/**
* Boolean False.
*/
static final int AL_FALSE = 0;
public static final int AL_FALSE = 0;
/**
* Boolean True.
*/
static final int AL_TRUE = 1;
public static final int AL_TRUE = 1;
/* "no distance model" or "no buffer" */
static final int AL_NONE = 0;
public static final int AL_NONE = 0;
/**
* Indicate Source has relative coordinates.
*/
static final int AL_SOURCE_RELATIVE = 0x202;
public static final int AL_SOURCE_RELATIVE = 0x202;
/**
* Directional source, inner cone angle, in degrees. Range: [0-360] Default:
* 360
*/
static final int AL_CONE_INNER_ANGLE = 0x1001;
public static final int AL_CONE_INNER_ANGLE = 0x1001;
/**
* Directional source, outer cone angle, in degrees. Range: [0-360] Default:
* 360
*/
static final int AL_CONE_OUTER_ANGLE = 0x1002;
public static final int AL_CONE_OUTER_ANGLE = 0x1002;
/**
* Specify the pitch to be applied at source. Range: [0.5-2.0] Default: 1.0
*/
static final int AL_PITCH = 0x1003;
public static final int AL_PITCH = 0x1003;
/**
* Specify the current location in three dimensional space. OpenAL, like
@ -52,84 +52,84 @@ public interface AL {
* coordinate system, flip the sign on the Z coordinate. Listener position
* is always in the world coordinate system.
*/
static final int AL_POSITION = 0x1004;
public static final int AL_POSITION = 0x1004;
/**
* Specify the current direction.
*/
static final int AL_DIRECTION = 0x1005;
public static final int AL_DIRECTION = 0x1005;
/**
* Specify the current velocity in three dimensional space.
*/
static final int AL_VELOCITY = 0x1006;
public static final int AL_VELOCITY = 0x1006;
/**
* Indicate whether source is looping. Type: ALboolean? Range: [AL_TRUE,
* AL_FALSE] Default: FALSE.
*/
static final int AL_LOOPING = 0x1007;
public static final int AL_LOOPING = 0x1007;
/**
* Indicate the buffer to provide sound samples. Type: ALuint. Range: any
* valid Buffer id.
*/
static final int AL_BUFFER = 0x1009;
public static final int AL_BUFFER = 0x1009;
/**
* Indicate the gain (volume amplification) applied. Type: ALfloat. Range:
* ]0.0- ] A value of 1.0 means un-attenuated/unchanged. Each division by 2
* equals an attenuation of -6dB. Each multiplicaton with 2 equals an
* equals an attenuation of -6dB. Each multiplication by 2 equals an
* amplification of +6dB. A value of 0.0 is meaningless with respect to a
* logarithmic scale; it is interpreted as zero volume - the channel is
* effectively disabled.
*/
static final int AL_GAIN = 0x100A;
public static final int AL_GAIN = 0x100A;
/*
* Indicate minimum source attenuation
* Type: ALfloat
* Range: [0.0 - 1.0]
*
* Logarthmic
* Logarithmic
*/
static final int AL_MIN_GAIN = 0x100D;
public static final int AL_MIN_GAIN = 0x100D;
/**
* Indicate maximum source attenuation Type: ALfloat Range: [0.0 - 1.0]
*
* Logarthmic
* Logarithmic
*/
static final int AL_MAX_GAIN = 0x100E;
public static final int AL_MAX_GAIN = 0x100E;
/**
* Indicate listener orientation.
*
* at/up
*/
static final int AL_ORIENTATION = 0x100F;
public static final int AL_ORIENTATION = 0x100F;
/**
* Source state information.
*/
static final int AL_SOURCE_STATE = 0x1010;
static final int AL_INITIAL = 0x1011;
static final int AL_PLAYING = 0x1012;
static final int AL_PAUSED = 0x1013;
static final int AL_STOPPED = 0x1014;
public static final int AL_SOURCE_STATE = 0x1010;
public static final int AL_INITIAL = 0x1011;
public static final int AL_PLAYING = 0x1012;
public static final int AL_PAUSED = 0x1013;
public static final int AL_STOPPED = 0x1014;
/**
* Buffer Queue params
*/
static final int AL_BUFFERS_QUEUED = 0x1015;
static final int AL_BUFFERS_PROCESSED = 0x1016;
public static final int AL_BUFFERS_QUEUED = 0x1015;
public static final int AL_BUFFERS_PROCESSED = 0x1016;
/**
* Source buffer position information
*/
static final int AL_SEC_OFFSET = 0x1024;
static final int AL_SAMPLE_OFFSET = 0x1025;
static final int AL_BYTE_OFFSET = 0x1026;
public static final int AL_SEC_OFFSET = 0x1024;
public static final int AL_SAMPLE_OFFSET = 0x1025;
public static final int AL_BYTE_OFFSET = 0x1026;
/*
* Source type (Static, Streaming or undetermined)
@ -137,38 +137,38 @@ public interface AL {
* Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers
* Source is undetermined when it has the NULL buffer attached
*/
static final int AL_SOURCE_TYPE = 0x1027;
static final int AL_STATIC = 0x1028;
static final int AL_STREAMING = 0x1029;
static final int AL_UNDETERMINED = 0x1030;
public static final int AL_SOURCE_TYPE = 0x1027;
public static final int AL_STATIC = 0x1028;
public static final int AL_STREAMING = 0x1029;
public static final int AL_UNDETERMINED = 0x1030;
/**
* Sound samples: format specifier.
*/
static final int AL_FORMAT_MONO8 = 0x1100;
static final int AL_FORMAT_MONO16 = 0x1101;
static final int AL_FORMAT_STEREO8 = 0x1102;
static final int AL_FORMAT_STEREO16 = 0x1103;
public static final int AL_FORMAT_MONO8 = 0x1100;
public static final int AL_FORMAT_MONO16 = 0x1101;
public static final int AL_FORMAT_STEREO8 = 0x1102;
public static final int AL_FORMAT_STEREO16 = 0x1103;
/**
* source specific reference distance Type: ALfloat Range: 0.0 - +inf
*
* At 0.0, no distance attenuation occurs. Default is 1.0.
*/
static final int AL_REFERENCE_DISTANCE = 0x1020;
public static final int AL_REFERENCE_DISTANCE = 0x1020;
/**
* source specific rolloff factor Type: ALfloat Range: 0.0 - +inf
*
*/
static final int AL_ROLLOFF_FACTOR = 0x1021;
public static final int AL_ROLLOFF_FACTOR = 0x1021;
/**
* Directional source, outer cone gain.
*
* Default: 0.0 Range: [0.0 - 1.0] Logarithmic
*/
static final int AL_CONE_OUTER_GAIN = 0x1022;
public static final int AL_CONE_OUTER_GAIN = 0x1022;
/**
* Indicate distance above which sources are not attenuated using the
@ -176,64 +176,64 @@ public interface AL {
*
* Default: +inf Type: ALfloat Range: 0.0 - +inf
*/
static final int AL_MAX_DISTANCE = 0x1023;
public static final int AL_MAX_DISTANCE = 0x1023;
/**
* Sound samples: frequency, in units of Hertz [Hz]. This is the number of
* samples per second. Half of the sample frequency marks the maximum
* significant frequency component.
*/
static final int AL_FREQUENCY = 0x2001;
static final int AL_BITS = 0x2002;
static final int AL_CHANNELS = 0x2003;
static final int AL_SIZE = 0x2004;
public static final int AL_FREQUENCY = 0x2001;
public static final int AL_BITS = 0x2002;
public static final int AL_CHANNELS = 0x2003;
public static final int AL_SIZE = 0x2004;
/**
* Buffer state.
*
* Not supported for public use (yet).
*/
static final int AL_UNUSED = 0x2010;
static final int AL_PENDING = 0x2011;
static final int AL_PROCESSED = 0x2012;
public static final int AL_UNUSED = 0x2010;
public static final int AL_PENDING = 0x2011;
public static final int AL_PROCESSED = 0x2012;
/**
* Errors: No Error.
*/
static final int AL_NO_ERROR = 0;
public static final int AL_NO_ERROR = 0;
/**
* Invalid Name paramater passed to AL call.
* Invalid Name parameter passed to AL call.
*/
static final int AL_INVALID_NAME = 0xA001;
public static final int AL_INVALID_NAME = 0xA001;
/**
* Invalid parameter passed to AL call.
*/
static final int AL_INVALID_ENUM = 0xA002;
public static final int AL_INVALID_ENUM = 0xA002;
/**
* Invalid enum parameter value.
*/
static final int AL_INVALID_VALUE = 0xA003;
public static final int AL_INVALID_VALUE = 0xA003;
/**
* Illegal call.
*/
static final int AL_INVALID_OPERATION = 0xA004;
public static final int AL_INVALID_OPERATION = 0xA004;
/**
* No mojo.
*/
static final int AL_OUT_OF_MEMORY = 0xA005;
public static final int AL_OUT_OF_MEMORY = 0xA005;
/**
* Context strings: Vendor Name.
*/
static final int AL_VENDOR = 0xB001;
static final int AL_VERSION = 0xB002;
static final int AL_RENDERER = 0xB003;
static final int AL_EXTENSIONS = 0xB004;
public static final int AL_VENDOR = 0xB001;
public static final int AL_VERSION = 0xB002;
public static final int AL_RENDERER = 0xB003;
public static final int AL_EXTENSIONS = 0xB004;
/**
* Global tweakage.
@ -241,56 +241,241 @@ public interface AL {
/**
* Doppler scale. Default 1.0
*/
static final int AL_DOPPLER_FACTOR = 0xC000;
public static final int AL_DOPPLER_FACTOR = 0xC000;
/**
* Tweaks speed of propagation.
*/
static final int AL_DOPPLER_VELOCITY = 0xC001;
public static final int AL_DOPPLER_VELOCITY = 0xC001;
/**
* Speed of Sound in units per second
*/
static final int AL_SPEED_OF_SOUND = 0xC003;
public static final int AL_SPEED_OF_SOUND = 0xC003;
/**
* Distance models
*
* used in conjunction with DistanceModel
*
* implicit: NONE, which disances distance attenuation.
*/
static final int AL_DISTANCE_MODEL = 0xD000;
static final int AL_INVERSE_DISTANCE = 0xD001;
static final int AL_INVERSE_DISTANCE_CLAMPED = 0xD002;
static final int AL_LINEAR_DISTANCE = 0xD003;
static final int AL_LINEAR_DISTANCE_CLAMPED = 0xD004;
static final int AL_EXPONENT_DISTANCE = 0xD005;
static final int AL_EXPONENT_DISTANCE_CLAMPED = 0xD006;
//
///* Listener parameter value ranges and defaults. */
//#define AL_MIN_METERS_PER_UNIT FLT_MIN
//#define AL_MAX_METERS_PER_UNIT FLT_MAX
//#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
* implicit: NONE, which disables distance attenuation.
*/
public static final int AL_DISTANCE_MODEL = 0xD000;
public static final int AL_INVERSE_DISTANCE = 0xD001;
public static final int AL_INVERSE_DISTANCE_CLAMPED = 0xD002;
public static final int AL_LINEAR_DISTANCE = 0xD003;
public static final int AL_LINEAR_DISTANCE_CLAMPED = 0xD004;
public static final int AL_EXPONENT_DISTANCE = 0xD005;
public static final int AL_EXPONENT_DISTANCE_CLAMPED = 0xD006;
//
///* Listener parameter value ranges and defaults. */
//#define AL_MIN_METERS_PER_UNIT FLT_MIN
//#define AL_MAX_METERS_PER_UNIT FLT_MAX
//#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
public String alGetString(int parameter);
/**
* Requests a number of source names.
*
* @return the number of source names.
*/
public int alGenSources();
/**
* Obtains error information.
* <p>
* <p>Each detectable error is assigned a numeric code. When an error is detected by AL, a flag is set and the error code is recorded. Further errors, if they
* occur, do not affect this recorded code. When alGetError is called, the code is returned and the flag is cleared, so that a further error will again
* record its code. If a call to alGetError returns AL_NO_ERROR then there has been no detectable error since the last call to alGetError (or since the AL
* was initialized).</p>
* <p>
* <p>Error codes can be mapped to strings. The alGetString function returns a pointer to a constant (literal) string that is identical to the identifier used
* for the enumeration value, as defined in the specification.</p>
*/
public int alGetError();
/**
* Requests the deletion of a number of sources.
*
* @param numSources the number of sources.
* @param sources the sources to delete.
*/
public void alDeleteSources(int numSources, IntBuffer sources);
/**
* Requests a number of buffer names.
*
* @param numBuffers the number of buffers.
* @param buffers the buffer that will receive the buffer names.
*/
public void alGenBuffers(int numBuffers, IntBuffer buffers);
/**
* Requests the deletion of a number of buffers.
*
* @param numBuffers the number of buffers.
* @param buffers the buffers to delete.
*/
public void alDeleteBuffers(int numBuffers, IntBuffer buffers);
/**
* Sets the source state to AL_STOPPED.
* <p>
* <p>alSourceStop applied to an AL_INITIAL source is a legal NOP. alSourceStop applied to a AL_PLAYING source will change its state to AL_STOPPED. The source
* is exempt from processing, its current state is preserved. alSourceStop applied to a AL_PAUSED source will change its state to AL_STOPPED, with the same
* consequences as on a AL_PLAYING source. alSourceStop applied to a AL_STOPPED source is a legal NOP.</p>
*
* @param source the source to stop.
*/
public void alSourceStop(int source);
/**
* Integer version of {@link #alSourcef Sourcef}.
*
* @param source the source to modify.
* @param param the parameter to modify.
* @param value the parameter value.
*/
public void alSourcei(int source, int param, int value);
/**
* Sets the sample data of the specified buffer.
* <p>
* <p>The data specified is copied to an internal software, or if possible, hardware buffer. The implementation is free to apply decompression, conversion,
* resampling, and filtering as needed.</p>
* <p>
* <p>8-bit data is expressed as an unsigned value over the range 0 to 255, 128 being an audio output level of zero.</p>
* <p>
* <p>16-bit data is expressed as a signed value over the range -32768 to 32767, 0 being an audio output level of zero. Byte order for 16-bit values is
* determined by the native format of the CPU.</p>
* <p>
* <p>Stereo data is expressed in an interleaved format, left channel sample followed by the right channel sample.</p>
* <p>
* <p>Buffers containing audio data with more than one channel will be played without 3D spatialization features these formats are normally used for
* background music.</p>
*
* @param buffer the buffer to modify.
* @param format the data format. One of:<br><table><tr><td>{@link #AL_FORMAT_MONO8 FORMAT_MONO8}</td><td>{@link #AL_FORMAT_MONO16 FORMAT_MONO16}</td><td>{@link #AL_FORMAT_STEREO8 FORMAT_STEREO8}</td><td>{@link #AL_FORMAT_STEREO16 FORMAT_STEREO16}</td></tr></table>
* @param data the sample data.
* @param frequency the data frequency.
*/
public void alBufferData(int buffer, int format, ByteBuffer data, int size, int frequency);
/**
* Sets the source state to AL_PLAYING.
* <p>
* <p>alSourcePlay applied to an AL_INITIAL source will promote the source to AL_PLAYING, thus the data found in the buffer will be fed into the processing,
* starting at the beginning. alSourcePlay applied to a AL_PLAYING source will restart the source from the beginning. It will not affect the configuration,
* and will leave the source in AL_PLAYING state, but reset the sampling offset to the beginning. alSourcePlay applied to a AL_PAUSED source will resume
* processing using the source state as preserved at the alSourcePause operation. alSourcePlay applied to a AL_STOPPED source will propagate it to
* AL_INITIAL then to AL_PLAYING immediately.</p>
*
* @param source the source to play.
*/
public void alSourcePlay(int source);
/**
* Sets the source state to AL_PAUSED.
* <p>
* <p>alSourcePause applied to an AL_INITIAL source is a legal NOP. alSourcePause applied to a AL_PLAYING source will change its state to AL_PAUSED. The
* source is exempt from processing, its current state is preserved. alSourcePause applied to a AL_PAUSED source is a legal NOP. alSourcePause applied to a
* AL_STOPPED source is a legal NOP.</p>
*
* @param source the source to pause.
*/
public void alSourcePause(int source);
/**
* Sets the float value of a source parameter.
*
* @param source the source to modify.
* @param param the parameter to modify. One of:<br><table><tr><td>{@link #AL_CONE_INNER_ANGLE CONE_INNER_ANGLE}</td><td>{@link #AL_CONE_OUTER_ANGLE CONE_OUTER_ANGLE}</td><td>{@link #AL_PITCH PITCH}</td><td>{@link #AL_DIRECTION DIRECTION}</td><td>{@link #AL_LOOPING LOOPING}</td><td>{@link #AL_BUFFER BUFFER}</td><td>{@link #AL_SOURCE_STATE SOURCE_STATE}</td></tr><tr><td>{@link #AL_CONE_OUTER_GAIN CONE_OUTER_GAIN}</td><td>{@link #AL_SOURCE_TYPE SOURCE_TYPE}</td><td>{@link #AL_POSITION POSITION}</td><td>{@link #AL_VELOCITY VELOCITY}</td><td>{@link #AL_GAIN GAIN}</td><td>{@link #AL_REFERENCE_DISTANCE REFERENCE_DISTANCE}</td><td>{@link #AL_ROLLOFF_FACTOR ROLLOFF_FACTOR}</td></tr><tr><td>{@link #AL_MAX_DISTANCE MAX_DISTANCE}</td></tr></table>
* @param value the parameter value.
*/
public void alSourcef(int source, int param, float value);
/**
* Sets the 3 dimensional values of a source parameter.
*
* @param source the source to modify.
* @param param the parameter to modify. One of:<br><table><tr><td>{@link #AL_CONE_INNER_ANGLE CONE_INNER_ANGLE}</td><td>{@link #AL_CONE_OUTER_ANGLE CONE_OUTER_ANGLE}</td><td>{@link #AL_PITCH PITCH}</td><td>{@link #AL_DIRECTION DIRECTION}</td><td>{@link #AL_LOOPING LOOPING}</td><td>{@link #AL_BUFFER BUFFER}</td><td>{@link #AL_SOURCE_STATE SOURCE_STATE}</td></tr><tr><td>{@link #AL_CONE_OUTER_GAIN CONE_OUTER_GAIN}</td><td>{@link #AL_SOURCE_TYPE SOURCE_TYPE}</td><td>{@link #AL_POSITION POSITION}</td><td>{@link #AL_VELOCITY VELOCITY}</td><td>{@link #AL_GAIN GAIN}</td><td>{@link #AL_REFERENCE_DISTANCE REFERENCE_DISTANCE}</td><td>{@link #AL_ROLLOFF_FACTOR ROLLOFF_FACTOR}</td></tr><tr><td>{@link #AL_MAX_DISTANCE MAX_DISTANCE}</td></tr></table>
* @param value1 the first parameter value.
* @param value2 the second parameter value.
* @param value3 the third parameter value.
*/
public void alSource3f(int source, int param, float value1, float value2, float value3);
/**
* Returns the integer value of the specified source parameter.
*
* @param source the source to query.
* @param param the parameter to query. One of:<br><table><tr><td>{@link #AL_CONE_INNER_ANGLE CONE_INNER_ANGLE}</td><td>{@link #AL_CONE_OUTER_ANGLE CONE_OUTER_ANGLE}</td><td>{@link #AL_PITCH PITCH}</td><td>{@link #AL_DIRECTION DIRECTION}</td><td>{@link #AL_LOOPING LOOPING}</td><td>{@link #AL_BUFFER BUFFER}</td><td>{@link #AL_SOURCE_STATE SOURCE_STATE}</td></tr><tr><td>{@link #AL_CONE_OUTER_GAIN CONE_OUTER_GAIN}</td><td>{@link #AL_SOURCE_TYPE SOURCE_TYPE}</td><td>{@link #AL_POSITION POSITION}</td><td>{@link #AL_VELOCITY VELOCITY}</td><td>{@link #AL_GAIN GAIN}</td><td>{@link #AL_REFERENCE_DISTANCE REFERENCE_DISTANCE}</td><td>{@link #AL_ROLLOFF_FACTOR ROLLOFF_FACTOR}</td></tr><tr><td>{@link #AL_MAX_DISTANCE MAX_DISTANCE}</td></tr></table>
*/
public int alGetSourcei(int source, int param);
/**
* Removes a number of buffer entries that have finished processing, in the order of apperance, from the queue of the specified source.
* <p>
* <p>Once a queue entry for a buffer has been appended to a queue and is pending processing, it should not be changed. Removal of a given queue entry is not
* possible unless either the source is stopped (in which case then entire queue is considered processed), or if the queue entry has already been processed
* (AL_PLAYING or AL_PAUSED source). A playing source will enter the AL_STOPPED state if it completes playback of the last buffer in its queue (the same
* behavior as when a single buffer has been attached to a source and has finished playback).</p>
*
* @param source the target source
* @param numBuffers the names count.
* @param buffers the buffer names
*/
public void alSourceUnqueueBuffers(int source, int numBuffers, IntBuffer buffers);
/**
* Queues up one or multiple buffer names to the specified source.
* <p>
* <p>The buffers will be queued in the sequence in which they appear in the array. This command is legal on a source in any playback state (to allow for
* streaming, queuing has to be possible on a AL_PLAYING source). All buffers in a queue must have the same format and attributes, with the exception of
* the {@code NULL} buffer (i.e., 0) which can always be queued.</p>
*
* @param source the target source.
* @param numBuffers the names count.
* @param buffers the buffer names.
*/
public void alSourceQueueBuffers(int source, int numBuffers, IntBuffer buffers);
/**
* Pointer version of {@link #alListenerf Listenerf}.
*
* @param param the parameter to modify.
* @param data the parameter values.
*/
public void alListener(int param, FloatBuffer data);
/**
* Sets the float value of a listener parameter.
*
* @param param the parameter to modify. One of:<br><table><tr><td>{@link #AL_ORIENTATION ORIENTATION}</td><td>{@link #AL_POSITION POSITION}</td><td>{@link #AL_VELOCITY VELOCITY}</td><td>{@link #AL_GAIN GAIN}</td></tr></table>
* @param value the parameter value.
*/
public void alListenerf(int param, float value);
/**
* Sets the 3 dimensional float values of a listener parameter.
*
* @param param the parameter to modify. One of:<br><table><tr><td>{@link #AL_ORIENTATION ORIENTATION}</td><td>{@link #AL_POSITION POSITION}</td><td>{@link #AL_VELOCITY VELOCITY}</td><td>{@link #AL_GAIN GAIN}</td></tr></table>
* @param value1 the first value.
* @param value2 the second value.
* @param value3 the third value.
*/
public void alListener3f(int param, float value1, float value2, float value3);
/**
* Sets the 3 dimensional integer values of a source parameter.
*
* @param source the source to modify.
* @param param the parameter to modify.
* @param value1 the first value.
* @param value2 the second value.
* @param value3 the third value.
*/
public void alSource3i(int source, int param, int value1, int value2, int value3);
}

@ -7,67 +7,120 @@ public interface ALC {
/**
* No error
*/
static final int ALC_NO_ERROR = 0;
public static final int ALC_NO_ERROR = 0;
/**
* No device
*/
static final int ALC_INVALID_DEVICE = 0xA001;
public static final int ALC_INVALID_DEVICE = 0xA001;
/**
* invalid context ID
*/
static final int ALC_INVALID_CONTEXT = 0xA002;
public static final int ALC_INVALID_CONTEXT = 0xA002;
/**
* bad enum
*/
static final int ALC_INVALID_ENUM = 0xA003;
public static final int ALC_INVALID_ENUM = 0xA003;
/**
* bad value
*/
static final int ALC_INVALID_VALUE = 0xA004;
public static final int ALC_INVALID_VALUE = 0xA004;
/**
* Out of memory.
*/
static final int ALC_OUT_OF_MEMORY = 0xA005;
public static final int ALC_OUT_OF_MEMORY = 0xA005;
/**
* The Specifier string for default device
*/
static final int ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004;
static final int ALC_DEVICE_SPECIFIER = 0x1005;
static final int ALC_EXTENSIONS = 0x1006;
public static final int ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004;
public static final int ALC_DEVICE_SPECIFIER = 0x1005;
public static final int ALC_EXTENSIONS = 0x1006;
static final int ALC_MAJOR_VERSION = 0x1000;
static final int ALC_MINOR_VERSION = 0x1001;
public static final int ALC_MAJOR_VERSION = 0x1000;
public static final int ALC_MINOR_VERSION = 0x1001;
static final int ALC_ATTRIBUTES_SIZE = 0x1002;
static final int ALC_ALL_ATTRIBUTES = 0x1003;
public static final int ALC_ATTRIBUTES_SIZE = 0x1002;
public static final int ALC_ALL_ATTRIBUTES = 0x1003;
/**
* Capture extension
*/
static final int ALC_CAPTURE_DEVICE_SPECIFIER = 0x310;
static final int ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311;
static final int ALC_CAPTURE_SAMPLES = 0x312;
public static final int ALC_CAPTURE_DEVICE_SPECIFIER = 0x310;
public static final int ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311;
public static final int ALC_CAPTURE_SAMPLES = 0x312;
/**
* ALC_ENUMERATE_ALL_EXT enums
*/
static final int ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012;
static final int ALC_ALL_DEVICES_SPECIFIER = 0x1013;
public static final int ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012;
public static final int ALC_ALL_DEVICES_SPECIFIER = 0x1013;
//public static ALCCapabilities createCapabilities(long device);
/**
* Creates an AL context.
*/
public void createALC();
/**
* Destroys an AL context.
*/
public void destroyALC();
/**
* Checks of creating an AL context.
*
* @return true if an AL context is created.
*/
public boolean isCreated();
/**
* Obtains string value(s) from ALC.
*
* @param parameter the information to query. One of:<br><table><tr><td>{@link #ALC_DEFAULT_DEVICE_SPECIFIER DEFAULT_DEVICE_SPECIFIER}</td><td>{@link #ALC_DEVICE_SPECIFIER DEVICE_SPECIFIER}</td><td>{@link #ALC_EXTENSIONS EXTENSIONS}</td></tr><tr><td>{@link #ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER CAPTURE_DEFAULT_DEVICE_SPECIFIER}</td><td>{@link #ALC_CAPTURE_DEVICE_SPECIFIER CAPTURE_DEVICE_SPECIFIER}</td></tr></table>
*/
public String alcGetString(int parameter);
/**
* Verifies that a given extension is available for the current context and the device it is associated with.
* <p>
* <p>Invalid and unsupported string tokens return ALC_FALSE. A {@code NULL} deviceHandle is acceptable. {@code extName} is not case sensitive the implementation
* will convert the name to all upper-case internally (and will express extension names in upper-case).</p>
*
* @param extension the extension name.
*/
public boolean alcIsExtensionPresent(String extension);
/**
* Obtains integer value(s) from ALC.
*
* @param param the information to query. One of:<br><table><tr><td>{@link #ALC_MAJOR_VERSION MAJOR_VERSION}</td><td>{@link #ALC_MINOR_VERSION MINOR_VERSION}</td><td>{@link #ALC_ATTRIBUTES_SIZE ATTRIBUTES_SIZE}</td><td>{@link #ALC_ALL_ATTRIBUTES ALL_ATTRIBUTES}</td><td>{@link #ALC_CAPTURE_SAMPLES CAPTURE_SAMPLES}</td></tr></table>
* @param buffer the destination buffer.
* @param size the buffer size.
*/
public void alcGetInteger(int param, IntBuffer buffer, int size);
/**
* Pauses a playback device.
* <p>
* <p>When paused, no contexts associated with the device will be processed or updated. Playing sources will not produce sound, have their offsets
* incremented, or process any more buffers, until the device is resumed. Pausing a device that is already paused is a legal no-op.</p>
*/
public void alcDevicePauseSOFT();
/**
* Resumes playback of a paused device.
* <p>
* <p>This will restart processing on the device -- sources will resume playing sound as normal. Resuming playback on a device that is not paused is a legal
* no-op.</p>
* <p>
* <p>These functions are not reference counted. alcDeviceResumeSOFT only needs to be called once to resume playback, regardless of how many times
* {@link #alcDevicePauseSOFT DevicePauseSOFT} was called.</p>
*/
public void alcDeviceResumeSOFT();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,89 +1,93 @@
/*
* Copyright (c) 2009-2012 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.cinematic;
import com.jme3.cinematic.events.CinematicEvent;
import com.jme3.export.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Nehon
*/
public class KeyFrame implements Savable {
List<CinematicEvent> cinematicEvents = new ArrayList<CinematicEvent>();
private int index;
public List<CinematicEvent> getCinematicEvents() {
return cinematicEvents;
}
public void setCinematicEvents(List<CinematicEvent> cinematicEvents) {
this.cinematicEvents = cinematicEvents;
}
public List<CinematicEvent> trigger() {
for (CinematicEvent event : cinematicEvents) {
event.play();
}
return cinematicEvents;
}
public boolean isEmpty(){
return cinematicEvents.isEmpty();
}
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.writeSavableArrayList((ArrayList) cinematicEvents, "cinematicEvents", null);
oc.write(index, "index", 0);
}
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
cinematicEvents = ic.readSavableArrayList("cinematicEvents", null);
index=ic.readInt("index", 0);
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
/*
* Copyright (c) 2009-2012 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.cinematic;
import com.jme3.cinematic.events.CinematicEvent;
import com.jme3.export.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Nehon
*/
public class KeyFrame implements Savable {
public KeyFrame(){
}
List<CinematicEvent> cinematicEvents = new ArrayList<>();
private int index;
public List<CinematicEvent> getCinematicEvents() {
return cinematicEvents;
}
public void setCinematicEvents(List<CinematicEvent> cinematicEvents) {
this.cinematicEvents = cinematicEvents;
}
public List<CinematicEvent> trigger() {
for (CinematicEvent event : cinematicEvents) {
event.play();
}
return cinematicEvents;
}
public boolean isEmpty(){
return cinematicEvents.isEmpty();
}
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.writeSavableArrayList((ArrayList) cinematicEvents, "cinematicEvents", null);
oc.write(index, "index", 0);
}
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
cinematicEvents = ic.readSavableArrayList("cinematicEvents", null);
index=ic.readInt("index", 0);
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -202,7 +202,7 @@ public class MotionPath implements Savable {
}
/**
* Addsa waypoint to the path
* Add a waypoint to the path
* @param wayPoint a position in world space
*/
public void addWayPoint(Vector3f wayPoint) {
@ -210,7 +210,7 @@ public class MotionPath implements Savable {
}
/**
* retruns the length of the path in world units
* Return the length of the path in world units
* @return the length
*/
public float getLength() {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,7 +34,7 @@ package com.jme3.cinematic;
import com.jme3.cinematic.events.MotionEvent;
/**
* Trigger the events happening on an motion path
* Trigger the events happening on a motion path
* @author Nehon
*/
public interface MotionPathListener {

@ -41,7 +41,10 @@ import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
@ -80,8 +83,9 @@ public class AnimationEvent extends AbstractCinematicEvent {
* constructors
*/
public AnimationEvent() {
super();
}
/**
* creates an animation event
*
@ -90,6 +94,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
*/
public AnimationEvent(Spatial model, String animationName) {
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
}
@ -104,6 +109,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration) {
super(initialDuration);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
}
@ -119,6 +125,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
}
@ -134,6 +141,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
}
@ -149,6 +157,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, float blendTime) {
super(initialDuration);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.blendTime = blendTime;
}
@ -167,6 +176,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.blendTime = blendTime;
}
@ -185,6 +195,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, float blendTime) {
super(initialDuration, loopMode);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.blendTime = blendTime;
}
@ -203,6 +214,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.channelIndex = channelIndex;
}
@ -217,6 +229,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
*/
public AnimationEvent(Spatial model, String animationName, int channelIndex) {
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.channelIndex = channelIndex;
@ -233,6 +246,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
*/
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex, float blendTime) {
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.loopMode = loopMode;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
@ -252,6 +266,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, int channelIndex) {
super(initialDuration);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.channelIndex = channelIndex;
}
@ -270,6 +285,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, int channelIndex) {
super(initialDuration, loopMode);
this.model = model;
this.modelName = model.getName();
this.animationName = animationName;
this.channelIndex = channelIndex;
}
@ -299,6 +315,18 @@ public class AnimationEvent extends AbstractCinematicEvent {
model = cinematic.getScene().getChild(modelName);
}
if (model != null) {
if(cinematic.getScene() != null){
Spatial sceneModel = cinematic.getScene().getChild(model.getName());
if(sceneModel != null){
Node parent = sceneModel.getParent();
parent.detachChild(sceneModel);
sceneModel = model;
parent.attachChild(sceneModel);
} else {
cinematic.getScene().attachChild(model);
}
}
channel = model.getControl(AnimControl.class).createChannel();
map.put(channelIndex, channel);
} else {
@ -401,6 +429,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
OutputCapsule oc = ex.getCapsule(this);
oc.write(model, "model", null);
oc.write(modelName, "modelName", null);
oc.write(animationName, "animationName", "");
oc.write(blendTime, "blendTime", 0f);
oc.write(channelIndex, "channelIndex", 0);
@ -411,9 +440,9 @@ public class AnimationEvent extends AbstractCinematicEvent {
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
if (im.getFormatVersion() == 0) {
// if (im.getFormatVersion() == 0) {
modelName = ic.readString("modelName", "");
}
// }
//FIXME always the same issue, because of the clonning of assets, this won't work
//we have to somehow store userdata in the spatial and then recurse the
//scene sub scenegraph to find the correct instance of the model

@ -0,0 +1,146 @@
/*
* Copyright (c) 2009-2017 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.cinematic.events;
import com.jme3.app.Application;
import com.jme3.cinematic.Cinematic;
import com.jme3.cinematic.TimeLine;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import com.jme3.scene.CameraNode;
import java.io.IOException;
import java.util.Map;
/**
*
* @author Rickard <neph1 @ github>
*/
public class CameraEvent extends AbstractCinematicEvent{
private String cameraName;
private Cinematic cinematic;
public String getCameraName() {
return cameraName;
}
public void setCameraName(String cameraName) {
this.cameraName = cameraName;
}
public CameraEvent(){
}
public CameraEvent(Cinematic parentEvent, String cameraName){
this.cinematic = parentEvent;
this.cameraName = cameraName;
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
this.cinematic = cinematic;
}
@Override
public void play() {
super.play();
stop();
}
@Override
public void onPlay() {
cinematic.setActiveCamera(cameraName);
}
@Override
public void onUpdate(float tpf) {
}
@Override
public void onStop() {
}
@Override
public void onPause() {
}
@Override
public void forceStop() {
}
@Override
public void setTime(float time) {
play();
}
public Cinematic getCinematic() {
return cinematic;
}
public void setCinematic(Cinematic cinematic) {
this.cinematic = cinematic;
}
/**
* used internally for serialization
*
* @param ex
* @throws IOException
*/
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(cameraName, "cameraName", null);
}
/**
* used internally for serialization
*
* @param im
* @throws IOException
*/
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
cameraName = ic.readString("cameraName", null);
}
}

@ -1,491 +1,478 @@
/*
* Copyright (c) 2009-2016 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.cinematic.events;
import com.jme3.animation.AnimationUtils;
import com.jme3.animation.LoopMode;
import com.jme3.app.Application;
import com.jme3.cinematic.Cinematic;
import com.jme3.cinematic.MotionPath;
import com.jme3.cinematic.PlayState;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
* A MotionEvent is a control over the spatial that manages the position and direction of the spatial while following a motion Path.
*
* You must first create a MotionPath and then create a MotionEvent to associate a spatial and the path.
*
* @author Nehon
*/
public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable {
protected Spatial spatial;
protected int currentWayPoint;
protected float currentValue;
protected Vector3f direction = new Vector3f();
protected Vector3f lookAt = null;
protected Vector3f upVector = Vector3f.UNIT_Y;
protected Quaternion rotation = null;
protected Direction directionType = Direction.None;
protected MotionPath path;
private boolean isControl = true;
private int travelDirection = 1;
/**
* the distance traveled by the spatial on the path
*/
protected float traveledDistance = 0;
/**
* Enum for the different type of target direction behavior.
*/
public enum Direction {
/**
* The target stays in the starting direction.
*/
None,
/**
* The target rotates with the direction of the path.
*/
Path,
/**
* The target rotates with the direction of the path but with the addition of a rotation.
* You need to use the setRotation method when using this Direction.
*/
PathAndRotation,
/**
* The target rotates with the given rotation.
*/
Rotation,
/**
* The target looks at a point.
* You need to use the setLookAt method when using this direction.
*/
LookAt
}
/**
* Create MotionEvent,
* when using this constructor don't forget to assign spatial and path.
*/
public MotionEvent() {
super();
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path) {
super();
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, LoopMode loopMode) {
super();
spatial.addControl(this);
this.path = path;
this.loopMode = loopMode;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
this.loopMode = loopMode;
}
public void update(float tpf) {
if (isControl) {
internalUpdate(tpf);
}
}
@Override
public void internalUpdate(float tpf) {
if (playState == PlayState.Playing) {
time = time + (tpf * speed);
if (loopMode == LoopMode.Loop && time < 0) {
time = initialDuration;
}
if ((time >= initialDuration || time < 0) && loopMode == LoopMode.DontLoop) {
if (time >= initialDuration) {
path.triggerWayPointReach(path.getNbWayPoints() - 1, this);
}
stop();
} else {
time = AnimationUtils.clampWrapTime(time, initialDuration, loopMode);
if(time<0){
speed = - speed;
time = - time;
}
onUpdate(tpf);
}
}
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
isControl = false;
}
@Override
public void setTime(float time) {
super.setTime(time);
onUpdate(0);
}
public void onUpdate(float tpf) {
traveledDistance = path.interpolatePath(time, this, tpf);
computeTargetDirection();
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(lookAt, "lookAt", null);
oc.write(upVector, "upVector", Vector3f.UNIT_Y);
oc.write(rotation, "rotation", null);
oc.write(directionType, "directionType", Direction.None);
oc.write(path, "path", null);
oc.write(spatial, "spatial", null);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule in = im.getCapsule(this);
lookAt = (Vector3f) in.readSavable("lookAt", null);
upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
rotation = (Quaternion) in.readSavable("rotation", null);
directionType = in.readEnum("directionType", Direction.class, Direction.None);
path = (MotionPath) in.readSavable("path", null);
spatial = (Spatial) in.readSavable("spatial", null);
}
/**
* This method is meant to be called by the motion path only.
* @return
*/
public boolean needsDirection() {
return directionType == Direction.Path || directionType == Direction.PathAndRotation;
}
private void computeTargetDirection() {
switch (directionType) {
case Path:
Quaternion q = new Quaternion();
q.lookAt(direction, upVector);
spatial.setLocalRotation(q);
break;
case LookAt:
if (lookAt != null) {
spatial.lookAt(lookAt, upVector);
}
break;
case PathAndRotation:
if (rotation != null) {
Quaternion q2 = new Quaternion();
q2.lookAt(direction, upVector);
q2.multLocal(rotation);
spatial.setLocalRotation(q2);
}
break;
case Rotation:
if (rotation != null) {
spatial.setLocalRotation(rotation);
}
break;
case None:
break;
default:
break;
}
}
/**
* Clone this control for the given spatial.
* @param spatial
* @return
*/
@Override
public Control cloneForSpatial(Spatial spatial) {
MotionEvent control = new MotionEvent();
control.setPath(path);
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
return control;
}
@Override
public Object jmeClone() {
MotionEvent control = new MotionEvent();
control.path = path;
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
control.spatial = spatial;
return control;
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial);
}
@Override
public void onPlay() {
traveledDistance = 0;
}
@Override
public void onStop() {
currentWayPoint = 0;
}
@Override
public void onPause() {
}
/**
* This method is meant to be called by the motion path only.
* @return
*/
public float getCurrentValue() {
return currentValue;
}
/**
* This method is meant to be called by the motion path only.
*
*/
public void setCurrentValue(float currentValue) {
this.currentValue = currentValue;
}
/**
* This method is meant to be called by the motion path only.
* @return
*/
public int getCurrentWayPoint() {
return currentWayPoint;
}
/**
* This method is meant to be called by the motion path only.
*
*/
public void setCurrentWayPoint(int currentWayPoint) {
this.currentWayPoint = currentWayPoint;
}
/**
* Returns the direction the spatial is moving.
* @return
*/
public Vector3f getDirection() {
return direction;
}
/**
* Sets the direction of the spatial, using the Y axis as the up vector.
* Use MotionEvent#setDirection((Vector3f direction,Vector3f upVector) if
* you want a custum up vector.
* This method is used by the motion path.
* @param direction
*/
public void setDirection(Vector3f direction) {
setDirection(direction, Vector3f.UNIT_Y);
}
/**
* Sets the direction of the spatial with the given up vector.
* This method is used by the motion path.
* @param direction
* @param upVector the up vector to consider for this direction.
*/
public void setDirection(Vector3f direction,Vector3f upVector) {
this.direction.set(direction);
this.upVector.set(upVector);
}
/**
* Returns the direction type of the target.
* @return the direction type.
*/
public Direction getDirectionType() {
return directionType;
}
/**
* Sets the direction type of the target.
* On each update the direction given to the target can have different behavior.
* See the Direction Enum for explanations.
* @param directionType the direction type.
*/
public void setDirectionType(Direction directionType) {
this.directionType = directionType;
}
/**
* Set the lookAt for the target.
* This can be used only if direction Type is Direction.LookAt.
* @param lookAt the position to look at.
* @param upVector the up vector.
*/
public void setLookAt(Vector3f lookAt, Vector3f upVector) {
this.lookAt = lookAt;
this.upVector = upVector;
}
/**
* Returns the rotation of the target.
* @return the rotation quaternion.
*/
public Quaternion getRotation() {
return rotation;
}
/**
* Sets the rotation of the target.
* This can be used only if direction Type is Direction.PathAndRotation or Direction.Rotation.
* With PathAndRotation the target will face the direction of the path multiplied by the given Quaternion.
* With Rotation the rotation of the target will be set with the given Quaternion.
* @param rotation the rotation quaternion.
*/
public void setRotation(Quaternion rotation) {
this.rotation = rotation;
}
/**
* Return the motion path this control follows.
* @return
*/
public MotionPath getPath() {
return path;
}
/**
* Sets the motion path to follow.
* @param path
*/
public void setPath(MotionPath path) {
this.path = path;
}
public void setEnabled(boolean enabled) {
if (enabled) {
play();
} else {
pause();
}
}
public boolean isEnabled() {
return playState != PlayState.Stopped;
}
public void render(RenderManager rm, ViewPort vp) {
}
public void setSpatial(Spatial spatial) {
this.spatial = spatial;
}
public Spatial getSpatial() {
return spatial;
}
/**
* Return the distance traveled by the spatial on the path.
* @return
*/
public float getTraveledDistance() {
return traveledDistance;
}
}
/*
* Copyright (c) 2009-2018 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.cinematic.events;
import com.jme3.animation.AnimationUtils;
import com.jme3.animation.LoopMode;
import com.jme3.app.Application;
import com.jme3.cinematic.Cinematic;
import com.jme3.cinematic.MotionPath;
import com.jme3.cinematic.PlayState;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
* A MotionEvent is a control over the spatial that manages the position and direction of the spatial while following a motion Path.
*
* You must first create a MotionPath and then create a MotionEvent to associate a spatial and the path.
*
* @author Nehon
*/
public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable {
protected Spatial spatial;
protected int currentWayPoint;
protected float currentValue;
protected Vector3f direction = new Vector3f();
protected Vector3f lookAt = null;
protected Vector3f upVector = Vector3f.UNIT_Y;
protected Quaternion rotation = null;
protected Direction directionType = Direction.None;
protected MotionPath path;
private boolean isControl = true;
private int travelDirection = 1;
/**
* the distance traveled by the spatial on the path
*/
protected float traveledDistance = 0;
/**
* Enum for the different type of target direction behavior.
*/
public enum Direction {
/**
* The target stays in the starting direction.
*/
None,
/**
* The target rotates with the direction of the path.
*/
Path,
/**
* The target rotates with the direction of the path but with the addition of a rotation.
* You need to use the setRotation method when using this Direction.
*/
PathAndRotation,
/**
* The target rotates with the given rotation.
*/
Rotation,
/**
* The target looks at a point.
* You need to use the setLookAt method when using this direction.
*/
LookAt
}
/**
* Create MotionEvent,
* when using this constructor don't forget to assign spatial and path.
*/
public MotionEvent() {
super();
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path) {
super();
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, LoopMode loopMode) {
super();
spatial.addControl(this);
this.path = path;
this.loopMode = loopMode;
}
/**
* Creates a MotionPath for the given spatial on the given motion path.
* @param spatial
* @param path
*/
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
super(initialDuration);
spatial.addControl(this);
this.path = path;
this.loopMode = loopMode;
}
public void update(float tpf) {
if (isControl) {
internalUpdate(tpf);
}
}
@Override
public void internalUpdate(float tpf) {
if (playState == PlayState.Playing) {
time = time + (tpf * speed);
if (loopMode == LoopMode.Loop && time < 0) {
time = initialDuration;
}
if ((time >= initialDuration || time < 0) && loopMode == LoopMode.DontLoop) {
if (time >= initialDuration) {
path.triggerWayPointReach(path.getNbWayPoints() - 1, this);
}
stop();
} else {
time = AnimationUtils.clampWrapTime(time, initialDuration, loopMode);
if(time<0){
speed = - speed;
time = - time;
}
onUpdate(tpf);
}
}
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
isControl = false;
}
@Override
public void setTime(float time) {
super.setTime(time);
onUpdate(0);
}
public void onUpdate(float tpf) {
traveledDistance = path.interpolatePath(time, this, tpf);
computeTargetDirection();
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(lookAt, "lookAt", null);
oc.write(upVector, "upVector", Vector3f.UNIT_Y);
oc.write(rotation, "rotation", null);
oc.write(directionType, "directionType", Direction.None);
oc.write(path, "path", null);
oc.write(spatial, "spatial", null);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule in = im.getCapsule(this);
lookAt = (Vector3f) in.readSavable("lookAt", null);
upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
rotation = (Quaternion) in.readSavable("rotation", null);
directionType = in.readEnum("directionType", Direction.class, Direction.None);
path = (MotionPath) in.readSavable("path", null);
spatial = (Spatial) in.readSavable("spatial", null);
}
/**
* This method is meant to be called by the motion path only.
* @return
*/
public boolean needsDirection() {
return directionType == Direction.Path || directionType == Direction.PathAndRotation;
}
private void computeTargetDirection() {
switch (directionType) {
case Path:
Quaternion q = new Quaternion();
q.lookAt(direction, upVector);
spatial.setLocalRotation(q);
break;
case LookAt:
if (lookAt != null) {
spatial.lookAt(lookAt, upVector);
}
break;
case PathAndRotation:
if (rotation != null) {
Quaternion q2 = new Quaternion();
q2.lookAt(direction, upVector);
q2.multLocal(rotation);
spatial.setLocalRotation(q2);
}
break;
case Rotation:
if (rotation != null) {
spatial.setLocalRotation(rotation);
}
break;
case None:
break;
default:
break;
}
}
/**
* Clone this control for the given spatial.
* @param spatial
* @return
*/
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
throw new UnsupportedOperationException();
}
@Override
public Object jmeClone() {
MotionEvent control = new MotionEvent();
control.path = path;
control.playState = playState;
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue;
control.direction = direction.clone();
control.lookAt = lookAt;
control.upVector = upVector.clone();
control.rotation = rotation;
control.initialDuration = initialDuration;
control.speed = speed;
control.loopMode = loopMode;
control.directionType = directionType;
control.spatial = spatial;
return control;
}
@Override
public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial);
}
@Override
public void onPlay() {
traveledDistance = 0;
}
@Override
public void onStop() {
currentWayPoint = 0;
}
@Override
public void onPause() {
}
/**
* This method is meant to be called by the motion path only.
* @return
*/
public float getCurrentValue() {
return currentValue;
}
/**
* This method is meant to be called by the motion path only.
*
*/
public void setCurrentValue(float currentValue) {
this.currentValue = currentValue;
}
/**
* This method is meant to be called by the motion path only.
* @return
*/
public int getCurrentWayPoint() {
return currentWayPoint;
}
/**
* This method is meant to be called by the motion path only.
*
*/
public void setCurrentWayPoint(int currentWayPoint) {
this.currentWayPoint = currentWayPoint;
}
/**
* Returns the direction the spatial is moving.
* @return
*/
public Vector3f getDirection() {
return direction;
}
/**
* Sets the direction of the spatial, using the Y axis as the up vector.
* Use MotionEvent#setDirection((Vector3f direction,Vector3f upVector) if
* you want a custum up vector.
* This method is used by the motion path.
* @param direction
*/
public void setDirection(Vector3f direction) {
setDirection(direction, Vector3f.UNIT_Y);
}
/**
* Sets the direction of the spatial with the given up vector.
* This method is used by the motion path.
* @param direction
* @param upVector the up vector to consider for this direction.
*/
public void setDirection(Vector3f direction,Vector3f upVector) {
this.direction.set(direction);
this.upVector.set(upVector);
}
/**
* Returns the direction type of the target.
* @return the direction type.
*/
public Direction getDirectionType() {
return directionType;
}
/**
* Sets the direction type of the target.
* On each update the direction given to the target can have different behavior.
* See the Direction Enum for explanations.
* @param directionType the direction type.
*/
public void setDirectionType(Direction directionType) {
this.directionType = directionType;
}
/**
* Set the lookAt for the target.
* This can be used only if direction Type is Direction.LookAt.
* @param lookAt the position to look at.
* @param upVector the up vector.
*/
public void setLookAt(Vector3f lookAt, Vector3f upVector) {
this.lookAt = lookAt;
this.upVector = upVector;
}
/**
* Returns the rotation of the target.
* @return the rotation quaternion.
*/
public Quaternion getRotation() {
return rotation;
}
/**
* Sets the rotation of the target.
* This can be used only if direction Type is Direction.PathAndRotation or Direction.Rotation.
* With PathAndRotation the target will face the direction of the path multiplied by the given Quaternion.
* With Rotation the rotation of the target will be set with the given Quaternion.
* @param rotation the rotation quaternion.
*/
public void setRotation(Quaternion rotation) {
this.rotation = rotation;
}
/**
* Return the motion path this control follows.
* @return
*/
public MotionPath getPath() {
return path;
}
/**
* Sets the motion path to follow.
* @param path
*/
public void setPath(MotionPath path) {
this.path = path;
}
public void setEnabled(boolean enabled) {
if (enabled) {
play();
} else {
pause();
}
}
public boolean isEnabled() {
return playState != PlayState.Stopped;
}
public void render(RenderManager rm, ViewPort vp) {
}
public void setSpatial(Spatial spatial) {
this.spatial = spatial;
}
public Spatial getSpatial() {
return spatial;
}
/**
* Return the distance traveled by the spatial on the path.
* @return
*/
public float getTraveledDistance() {
return traveledDistance;
}
}

@ -1,229 +1,230 @@
/*
* Copyright (c) 2009-2012 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.cinematic.events;
import com.jme3.animation.LoopMode;
import com.jme3.app.Application;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioSource;
import com.jme3.cinematic.Cinematic;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import java.io.IOException;
/**
* A sound track to be played in a cinematic.
* @author Nehon
*/
public class SoundEvent extends AbstractCinematicEvent {
protected String path;
protected AudioNode audioNode;
protected boolean stream = false;
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
*/
public SoundEvent(String path) {
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
*/
public SoundEvent(String path, boolean stream) {
this(path);
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, boolean stream, float initialDuration) {
super(initialDuration);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, LoopMode loopMode) {
super(loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, float initialDuration) {
super(initialDuration);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, LoopMode loopMode) {
super(loopMode);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
}
/**
* creates a sound event
* used for serialization
*/
public SoundEvent() {
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
audioNode = new AudioNode(app.getAssetManager(), path, stream);
audioNode.setPositional(false);
setLoopMode(loopMode);
}
@Override
public void setTime(float time) {
super.setTime(time);
//can occur on rewind
if (time < 0f) {
stop();
}else{
audioNode.setTimeOffset(time);
}
}
@Override
public void onPlay() {
audioNode.play();
}
@Override
public void onStop() {
audioNode.stop();
}
@Override
public void onPause() {
audioNode.pause();
}
@Override
public void onUpdate(float tpf) {
if (audioNode.getStatus() == AudioSource.Status.Stopped) {
stop();
}
}
/**
* Returns the underlying audio node of this sound track
* @return
*/
public AudioNode getAudioNode() {
return audioNode;
}
@Override
public void setLoopMode(LoopMode loopMode) {
super.setLoopMode(loopMode);
if (loopMode != LoopMode.DontLoop) {
audioNode.setLooping(true);
} else {
audioNode.setLooping(false);
}
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(path, "path", "");
oc.write(stream, "stream", false);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
path = ic.readString("path", "");
stream = ic.readBoolean("stream", false);
}
}
/*
* Copyright (c) 2009-2012 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.cinematic.events;
import com.jme3.animation.LoopMode;
import com.jme3.app.Application;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioSource;
import com.jme3.cinematic.Cinematic;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import java.io.IOException;
/**
* A sound track to be played in a cinematic.
* @author Nehon
*/
public class SoundEvent extends AbstractCinematicEvent {
protected String path;
protected AudioNode audioNode;
protected boolean stream = false;
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
*/
public SoundEvent(String path) {
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
*/
public SoundEvent(String path, boolean stream) {
this(path);
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, boolean stream, float initialDuration) {
super(initialDuration);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, LoopMode loopMode) {
super(loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, boolean stream, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
this.stream = stream;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
*/
public SoundEvent(String path, float initialDuration) {
super(initialDuration);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, LoopMode loopMode) {
super(loopMode);
this.path = path;
}
/**
* creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event
* @param loopMode the loopMode
* @see LoopMode
*/
public SoundEvent(String path, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode);
this.path = path;
}
/**
* creates a sound event
* used for serialization
*/
public SoundEvent() {
super();
}
@Override
public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic);
audioNode = new AudioNode(app.getAssetManager(), path, stream);
audioNode.setPositional(false);
setLoopMode(loopMode);
}
@Override
public void setTime(float time) {
super.setTime(time);
//can occur on rewind
if (time < 0f) {
stop();
}else{
audioNode.setTimeOffset(time);
}
}
@Override
public void onPlay() {
audioNode.play();
}
@Override
public void onStop() {
audioNode.stop();
}
@Override
public void onPause() {
audioNode.pause();
}
@Override
public void onUpdate(float tpf) {
if (audioNode.getStatus() == AudioSource.Status.Stopped) {
stop();
}
}
/**
* Returns the underlying audio node of this sound track
* @return
*/
public AudioNode getAudioNode() {
return audioNode;
}
@Override
public void setLoopMode(LoopMode loopMode) {
super.setLoopMode(loopMode);
if (loopMode != LoopMode.DontLoop) {
audioNode.setLooping(true);
} else {
audioNode.setLooping(false);
}
}
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
OutputCapsule oc = ex.getCapsule(this);
oc.write(path, "path", "");
oc.write(stream, "stream", false);
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
path = ic.readString("path", "");
stream = ic.readBoolean("stream", false);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -217,7 +217,7 @@ class SweepSphere implements Collidable {
float signedDistanceToPlane = triPlane.pseudoDistance(sCenter);
if (normalDotVelocity == 0.0f){
// we are travelling exactly parrallel to the plane
// we are travelling exactly parallel to the plane
if (FastMath.abs(signedDistanceToPlane) >= 1.0f){
// no collision possible
return null;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -121,10 +121,10 @@ public class ParticleEmitter extends Geometry {
this.parentEmitter = parentEmitter;
}
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
return this; // WARNING: Sets wrong control on spatial. Will be
// fixed automatically by ParticleEmitter.clone() method.
throw new UnsupportedOperationException();
}
@Override
@ -384,7 +384,7 @@ public class ParticleEmitter extends Geometry {
* Set to true if particles should spawn in world space.
*
* <p>If set to true and the particle emitter is moved in the scene,
* then particles that have already spawned won't be effected by this
* then particles that have already spawned won't be affected by this
* motion. If set to false, the particles will emit in local space
* and when the emitter is moved, so are all the particles that
* were emitted previously.
@ -846,7 +846,7 @@ public class ParticleEmitter extends Geometry {
* @param initialVelocity Set the initial velocity a particle is spawned with,
* the initial velocity given in the parameter will be varied according
* to the velocity variation set in {@link ParticleEmitter#setVelocityVariation(float) }.
* A particle will move toward its velocity unless it is effected by the
* The particle will move with this velocity unless it is affected by
* gravity.
*
* @deprecated

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -64,7 +64,7 @@ public interface ParticleInfluencer extends Savable, Cloneable, JmeCloneable {
* Set the initial velocity a particle is spawned with,
* the initial velocity given in the parameter will be varied according
* to the velocity variation set in {@link ParticleEmitter#setVelocityVariation(float) }.
* A particle will move toward its velocity unless it is effected by the
* The particle will move with this velocity unless it is affected by
* gravity.
*/
void setInitialVelocity(Vector3f initialVelocity);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -37,7 +37,7 @@ import com.jme3.scene.Mesh;
import java.util.List;
/**
* This emiter shape emits the particles from the given shape's interior constrained by its convex hull
* This emitter shape emits the particles from the given shape's interior constrained by its convex hull
* (a geometry that tightly wraps the mesh). So in case of multiple meshes some vertices may appear
* in a space between them.
* @author Marcin Roguski (Kaelthas)

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -40,7 +40,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* This emiter shape emits the particles from the given shape's faces.
* This emitter shape emits the particles from the given shape's faces.
* @author Marcin Roguski (Kaelthas)
*/
public class EmitterMeshFaceShape extends EmitterMeshVertexShape {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -50,7 +50,7 @@ import java.util.Map;
import java.util.Map.Entry;
/**
* This emiter shape emits the particles from the given shape's vertices
* This emitter shape emits the particles from the given shape's vertices
* @author Marcin Roguski (Kaelthas)
*/
public class EmitterMeshVertexShape implements EmitterShape {
@ -74,7 +74,7 @@ public class EmitterMeshVertexShape implements EmitterShape {
}
/**
* This method sets the meshes that will form the emiter's shape.
* This method sets the meshes that will form the emitter's shape.
* @param meshes
* a list of meshes that will form the emitter's shape
*/

@ -96,10 +96,12 @@ public class EmitterSphereShape implements EmitterShape {
@Override
public void getRandomPoint(Vector3f store) {
do {
store.x = (FastMath.nextRandomFloat() * 2f - 1f) * radius;
store.y = (FastMath.nextRandomFloat() * 2f - 1f) * radius;
store.z = (FastMath.nextRandomFloat() * 2f - 1f) * radius;
} while (store.distance(center) > radius);
store.x = (FastMath.nextRandomFloat() * 2f - 1f);
store.y = (FastMath.nextRandomFloat() * 2f - 1f);
store.z = (FastMath.nextRandomFloat() * 2f - 1f);
} while (store.lengthSquared() > 1);
store.multLocal(radius);
store.addLocal(center);
}
@Override

@ -48,6 +48,7 @@ import com.jme3.texture.Texture2D;
import com.jme3.texture.TextureCubeMap;
import com.jme3.texture.image.ColorSpace;
import com.jme3.util.BufferUtils;
import com.jme3.util.MipMapGenerator;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@ -72,6 +73,8 @@ public class EnvironmentCamera extends BaseAppState {
protected Image.Format imageFormat = Image.Format.RGB16F;
public TextureCubeMap debugEnv;
//Axis for cameras
static {
//PositiveX axis(left, up, direction)
@ -188,10 +191,11 @@ public class EnvironmentCamera extends BaseAppState {
buffers[i] = BufferUtils.createByteBuffer(size * size * imageFormat.getBitsPerPixel() / 8);
renderManager.getRenderer().readFrameBufferWithFormat(framebuffers[i], buffers[i], imageFormat);
images[i] = new Image(imageFormat, size, size, buffers[i], ColorSpace.Linear);
MipMapGenerator.generateMipMaps(images[i]);
}
final TextureCubeMap map = EnvMapUtils.makeCubeMap(images[0], images[1], images[2], images[3], images[4], images[5], imageFormat);
debugEnv = map;
job.callback.done(map);
map.getImage().dispose();
jobs.remove(0);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,13 +31,14 @@
*/
package com.jme3.environment;
import com.jme3.app.Application;
import com.jme3.environment.generation.*;
import com.jme3.light.LightProbe;
import com.jme3.environment.util.EnvMapUtils;
import com.jme3.app.Application;
import com.jme3.light.LightProbe;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.texture.TextureCubeMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
/**
@ -46,7 +47,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
* Since the process can be long, you can provide a JobProgressListener that
* will be notified of the ongoing generation process when calling the makeProbe method.
*
* The process is the folowing :
* The process is as follows:
* 1. Create an EnvironmentCamera
* 2. give it a position in the scene
* 3. call {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)}
@ -60,7 +61,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
* This class is entirely thread safe and can be called from any thread.
*
* Note that in case you are using a {@link JobProgressListener} all the its
* method will be called inside and app.enqueu callable.
* method will be called inside and app.enqueue callable.
* This means that it's completely safe to modify the scenegraph within the
* Listener method, but also means that the even will be delayed until next update loop.
*
@ -72,7 +73,7 @@ public class LightProbeFactory {
/**
* Creates a LightProbe with the giver EnvironmentCamera in the given scene.
*
* Note that this is an assynchronous process that will run on multiple threads.
* Note that this is an asynchronous process that will run on multiple threads.
* The process is thread safe.
* The created lightProbe will only be marked as ready when the rendering process is done.
*
@ -93,7 +94,7 @@ public class LightProbeFactory {
/**
* Creates a LightProbe with the giver EnvironmentCamera in the given scene.
*
* Note that this is an assynchronous process that will run on multiple threads.
* Note that this is an asynchronous process that will run on multiple threads.
* The process is thread safe.
* The created lightProbe will only be marked as ready when the rendering process is done.
*
@ -106,10 +107,11 @@ public class LightProbeFactory {
* @param envCam the EnvironmentCamera
* @param scene the Scene
* @param listener the listener of the genration progress.
* @param genType Fast or HighQuality. Fast may be ok for many types of environment, but you may need high quality when an environment map has very high lighting values.
* @param listener the listener of the generation progress.
* @return the created LightProbe
*/
public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) {
public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final EnvMapUtils.GenerationType genType, final JobProgressListener<LightProbe> listener) {
final LightProbe probe = new LightProbe();
probe.setPosition(envCam.getPosition());
probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat()));
@ -117,33 +119,37 @@ public class LightProbeFactory {
@Override
public void done(TextureCubeMap map) {
generatePbrMaps(map, probe, envCam.getApplication(), listener);
generatePbrMaps(map, probe, envCam.getApplication(), genType, listener);
}
});
return probe;
}
/**
* Updates a LightProbe with the giver EnvironmentCamera in the given scene.
*
* Note that this is an assynchronous process that will run on multiple threads.
public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) {
return makeProbe(envCam, scene, EnvMapUtils.GenerationType.Fast, listener);
}
/**
* Updates a LightProbe with the given EnvironmentCamera in the given scene.
* <p>
* Note that this is an asynchronous process that will run on multiple threads.
* The process is thread safe.
* The created lightProbe will only be marked as ready when the rendering process is done.
*
* The JobProgressListener will be notified of the progress of the generation.
* Note that you can also use a {@link JobProgressAdapter}.
*
* <p>
* The JobProgressListener will be notified of the progress of the generation.
* Note that you can also use a {@link JobProgressAdapter}.
*
* @param probe the Light probe to update
* @param envCam the EnvironmentCamera
* @param scene the Scene
* @param genType Fast or HighQuality. Fast may be ok for many types of environment, but you may need high quality when an environment map has very high lighting values.
* @param listener the listener of the generation progress.
* @return the created LightProbe
* @see LightProbe
* @see EnvironmentCamera
* @see JobProgressListener
*
* @param probe the Light probe to update
* @param envCam the EnvironmentCamera
* @param scene the Scene
* @param listener the listener of the genration progress.
* @return the created LightProbe
*/
public static LightProbe updateProbe(final LightProbe probe, final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) {
public static LightProbe updateProbe(final LightProbe probe, final EnvironmentCamera envCam, Spatial scene, final EnvMapUtils.GenerationType genType, final JobProgressListener<LightProbe> listener) {
envCam.setPosition(probe.getPosition());
@ -159,23 +165,27 @@ public class LightProbeFactory {
@Override
public void done(TextureCubeMap map) {
generatePbrMaps(map, probe, envCam.getApplication(), listener);
generatePbrMaps(map, probe, envCam.getApplication(), genType, listener);
}
});
return probe;
}
public static LightProbe updateProbe(final LightProbe probe, final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) {
return updateProbe(probe, envCam, scene, EnvMapUtils.GenerationType.Fast, listener);
}
/**
* Internally called to generate the maps.
* This method will spawn 7 thread (one for the Irradiance spherical harmonics generator, and one for each face of the prefiltered env map).
* Those threads will be executed in a ScheduledThreadPoolExecutor that will be shutdown when the genration is done.
*
* Those threads will be executed in a ScheduledThreadPoolExecutor that will be shutdown when the generation is done.
*
* @param envMap the raw env map rendered by the env camera
* @param probe the LigthProbe to generate maps for
* @param probe the LightProbe to generate maps for
* @param app the Application
* @param listener a progress listener. (can be null if no progress reporting is needed)
*/
private static void generatePbrMaps(TextureCubeMap envMap, final LightProbe probe, Application app, final JobProgressListener<LightProbe> listener) {
private static void generatePbrMaps(TextureCubeMap envMap, final LightProbe probe, Application app, EnvMapUtils.GenerationType genType, final JobProgressListener<LightProbe> listener) {
IrradianceSphericalHarmonicsGenerator irrShGenerator;
PrefilteredEnvMapFaceGenerator[] pemGenerators = new PrefilteredEnvMapFaceGenerator[6];
@ -189,7 +199,7 @@ public class LightProbeFactory {
for (int i = 0; i < pemGenerators.length; i++) {
pemGenerators[i] = new PrefilteredEnvMapFaceGenerator(app, i, new JobListener(listener, jobState, probe, i));
pemGenerators[i].setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.None, probe.getPrefilteredEnvMap());
pemGenerators[i].setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.None, genType, probe.getPrefilteredEnvMap());
jobState.executor.execute(pemGenerators[i]);
}
}
@ -227,7 +237,7 @@ public class LightProbeFactory {
}
/**
* An inner JobProgressListener to controll the genration process and properly clean up when it's done
* An inner JobProgressListener to control the generation process and properly clean up when it's done
*/
private static class JobListener extends JobProgressAdapter<Integer> {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -73,7 +73,7 @@ public class IrradianceSphericalHarmonicsGenerator extends RunnableWithProgress
}
/**
* Fills all the genration parameters
* Fills all the generation parameters
*
* @param sourceMap the source cube map
* {@link EnvMapUtils.FixSeamsMethod}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,30 +31,22 @@
*/
package com.jme3.environment.generation;
import com.jme3.app.Application;
import com.jme3.environment.util.CubeMapWrapper;
import com.jme3.environment.util.EnvMapUtils;
import com.jme3.app.Application;
import com.jme3.math.*;
import static com.jme3.math.FastMath.abs;
import static com.jme3.math.FastMath.clamp;
import static com.jme3.math.FastMath.pow;
import static com.jme3.math.FastMath.sqrt;
import com.jme3.texture.TextureCubeMap;
import static com.jme3.environment.util.EnvMapUtils.getHammersleyPoint;
import static com.jme3.environment.util.EnvMapUtils.getRoughnessFromMip;
import static com.jme3.environment.util.EnvMapUtils.getSampleFromMip;
import static com.jme3.environment.util.EnvMapUtils.getVectorFromCubemapFaceTexCoord;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.jme3.environment.util.EnvMapUtils.*;
import static com.jme3.math.FastMath.abs;
import static com.jme3.math.FastMath.sqrt;
/**
* Generates one face of the prefiltered environnement map for PBR. This job can
* be lauched from a separate thread.
* Generates one face of the prefiltered environment map for PBR. This job can
* be launched from a separate thread.
* <p>
* TODO there is a lot of duplicate code here with the EnvMapUtils.
*
@ -69,6 +61,7 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
private int targetMapSize;
private EnvMapUtils.FixSeamsMethod fixSeamsMethod;
private EnvMapUtils.GenerationType genType;
private TextureCubeMap sourceMap;
private TextureCubeMap store;
private final Application app;
@ -98,7 +91,7 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
/**
* Fills all the genration parameters
* Fills all the generation parameters
*
* @param sourceMap the source cube map
* @param targetMapSize the size of the generated map (width or height in
@ -107,11 +100,12 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
* {@link EnvMapUtils.FixSeamsMethod}
* @param store The cube map to store the result in.
*/
public void setGenerationParam(TextureCubeMap sourceMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) {
public void setGenerationParam(TextureCubeMap sourceMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, EnvMapUtils.GenerationType genType, TextureCubeMap store) {
this.sourceMap = sourceMap;
this.targetMapSize = targetMapSize;
this.fixSeamsMethod = fixSeamsMethod;
this.store = store;
this.genType = genType;
init();
}
@ -162,68 +156,105 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
* @return The irradiance cube map for the given coefficients
*/
private TextureCubeMap generatePrefilteredEnvMap(TextureCubeMap sourceEnvMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) {
TextureCubeMap pem = store;
try {
TextureCubeMap pem = store;
int nbMipMap = (int) (Math.log(targetMapSize) / Math.log(2) - 1);
int nbMipMap = store.getImage().getMipMapSizes().length;
setEnd(nbMipMap);
setEnd(nbMipMap);
if (!sourceEnvMap.getImage().hasMipmaps() || sourceEnvMap.getImage().getMipMapSizes().length < nbMipMap) {
throw new IllegalArgumentException("The input cube map must have at least " + nbMipMap + "mip maps");
}
CubeMapWrapper sourceWrapper = new CubeMapWrapper(sourceEnvMap);
CubeMapWrapper targetWrapper = new CubeMapWrapper(pem);
CubeMapWrapper sourceWrapper = new CubeMapWrapper(sourceEnvMap);
CubeMapWrapper targetWrapper = new CubeMapWrapper(pem);
Vector3f texelVect = new Vector3f();
Vector3f color = new Vector3f();
ColorRGBA outColor = new ColorRGBA();
for (int mipLevel = 0; mipLevel < nbMipMap; mipLevel++) {
float roughness = getRoughnessFromMip(mipLevel, nbMipMap);
int nbSamples = getSampleFromMip(mipLevel, nbMipMap);
int targetMipMapSize = (int) pow(2, nbMipMap + 1 - mipLevel);
Vector3f texelVect = new Vector3f();
Vector3f color = new Vector3f();
ColorRGBA outColor = new ColorRGBA();
int targetMipMapSize = targetMapSize;
for (int mipLevel = 0; mipLevel < nbMipMap; mipLevel++) {
float roughness = getRoughnessFromMip(mipLevel, nbMipMap);
int nbSamples = getSampleFromMip(mipLevel, nbMipMap);
for (int y = 0; y < targetMipMapSize; y++) {
for (int x = 0; x < targetMipMapSize; x++) {
color.set(0, 0, 0);
getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, fixSeamsMethod);
prefilterEnvMapTexel(sourceWrapper, roughness, texelVect, nbSamples, color);
for (int y = 0; y < targetMipMapSize; y++) {
for (int x = 0; x < targetMipMapSize; x++) {
color.set(0, 0, 0);
getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, fixSeamsMethod);
prefilterEnvMapTexel(sourceWrapper, roughness, texelVect, nbSamples, mipLevel, color);
outColor.set(Math.max(color.x, 0.0001f), Math.max(color.y, 0.0001f), Math.max(color.z, 0.0001f), 1);
log.log(Level.FINE, "coords {0},{1}", new Object[]{x, y});
targetWrapper.setPixel(x, y, face, mipLevel, outColor);
outColor.set(Math.max(color.x, 0.0001f), Math.max(color.y, 0.0001f), Math.max(color.z, 0.0001f), 1);
targetWrapper.setPixel(x, y, face, mipLevel, outColor);
}
}
targetMipMapSize /= 2;
progress();
}
progress();
}
return pem;
return pem;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
private Vector3f prefilterEnvMapTexel(CubeMapWrapper envMapReader, float roughness, Vector3f N, int numSamples, Vector3f store) {
private Vector3f prefilterEnvMapTexel(CubeMapWrapper envMapReader, float roughness, Vector3f N, int numSamples, int mipLevel, Vector3f store) {
Vector3f prefilteredColor = store;
float totalWeight = 0.0f;
int nbRotations = 1;
if (genType == GenerationType.HighQuality) {
nbRotations = numSamples == 1 ? 1 : 18;
}
float rad = 2f * FastMath.PI / (float) nbRotations;
// offset rotation to avoid sampling pattern
float gi = (float) (FastMath.abs(N.z + N.x) * 256.0);
float offset = rad * (FastMath.cos((gi * 0.5f) % (2f * FastMath.PI)) * 0.5f + 0.5f);
// a = roughness² and a2 = a²
float a2 = roughness * roughness;
a2 *= a2;
//Computing tangent frame
Vector3f upVector = Vector3f.UNIT_X;
if (abs(N.z) < 0.999) {
upVector = Vector3f.UNIT_Y;
}
Vector3f tangentX = tmp1.set(upVector).crossLocal(N).normalizeLocal();
Vector3f tangentY = tmp2.set(N).crossLocal(tangentX);
// https://placeholderart.wordpress.com/2015/07/28/implementation-notes-runtime-environment-map-filtering-for-image-based-lighting/
// in local space view == normal == 0,0,1
Vector3f V = new Vector3f(0, 0, 1);
Vector3f lWorld = new Vector3f();
for (int i = 0; i < numSamples; i++) {
Xi = getHammersleyPoint(i, numSamples, Xi);
H = importanceSampleGGX(Xi, a2, N, H);
H = importanceSampleGGX(Xi, a2, H);
H.normalizeLocal();
tmp.set(H);
float NoH = N.dot(tmp);
Vector3f L = tmp.multLocal(NoH * 2).subtractLocal(N);
float NoL = clamp(N.dot(L), 0.0f, 1.0f);
if (NoL > 0) {
envMapReader.getPixel(L, c);
prefilteredColor.setX(prefilteredColor.x + c.r * NoL);
prefilteredColor.setY(prefilteredColor.y + c.g * NoL);
prefilteredColor.setZ(prefilteredColor.z + c.b * NoL);
totalWeight += NoL;
float VoH = H.z;
Vector3f L = H.multLocal(VoH * 2f).subtractLocal(V);
float NoL = L.z;
float computedMipLevel = mipLevel;
if (mipLevel != 0) {
computedMipLevel = computeMipLevel(roughness, numSamples, this.targetMapSize, VoH);
}
toWorld(L, N, tangentX, tangentY, lWorld);
totalWeight += samplePixel(envMapReader, lWorld, NoL, computedMipLevel, prefilteredColor);
for (int j = 1; j < nbRotations; j++) {
rotateDirection(offset + j * rad, L, lWorld);
L.set(lWorld);
toWorld(L, N, tangentX, tangentY, lWorld);
totalWeight += samplePixel(envMapReader, lWorld, NoL, computedMipLevel, prefilteredColor);
}
}
if (totalWeight > 0) {
prefilteredColor.divideLocal(totalWeight);
@ -232,7 +263,78 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
return prefilteredColor;
}
public Vector3f importanceSampleGGX(Vector4f xi, float a2, Vector3f normal, Vector3f store) {
private float samplePixel(CubeMapWrapper envMapReader, Vector3f lWorld, float NoL, float computedMipLevel, Vector3f store) {
if (NoL <= 0) {
return 0;
}
envMapReader.getPixel(lWorld, computedMipLevel, c);
store.setX(store.x + c.r * NoL);
store.setY(store.y + c.g * NoL);
store.setZ(store.z + c.b * NoL);
return NoL;
}
private void toWorld(Vector3f L, Vector3f N, Vector3f tangentX, Vector3f tangentY, Vector3f store) {
store.set(tangentX).multLocal(L.x);
tmp.set(tangentY).multLocal(L.y);
store.addLocal(tmp);
tmp.set(N).multLocal(L.z);
store.addLocal(tmp);
}
private float computeMipLevel(float roughness, int numSamples, float size, float voH) {
// H[2] is NoH in local space
// adds 1.e-5 to avoid ggx / 0.0
float NoH = voH + 1E-5f;
// Probability Distribution Function
float Pdf = ggx(NoH, roughness) * NoH / (4.0f * voH);
// Solid angle represented by this sample
float omegaS = 1.0f / (numSamples * Pdf);
// Solid angle covered by 1 pixel with 6 faces that are EnvMapSize X EnvMapSize
float omegaP = 4.0f * FastMath.PI / (6.0f * size * size);
// Original paper suggest biasing the mip to improve the results
float mipBias = 1.0f; // I tested that the result is better with bias 1
double maxLod = Math.log(size) / Math.log(2f);
double log2 = Math.log(omegaS / omegaP) / Math.log(2);
return Math.min(Math.max(0.5f * (float) log2 + mipBias, 0.0f), (float) maxLod);
}
private float ggx(float NoH, float alpha) {
// use GGX / Trowbridge-Reitz, same as Disney and Unreal 4
// cf http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf p3
float tmp = alpha / (NoH * NoH * (alpha * alpha - 1.0f) + 1.0f);
return tmp * tmp * (1f / FastMath.PI);
}
private Vector3f rotateDirection(float angle, Vector3f l, Vector3f store) {
float s, c, t;
s = FastMath.sin(angle);
c = FastMath.cos(angle);
t = 1.f - c;
store.x = l.x * c + l.y * s;
store.y = -l.x * s + l.y * c;
store.z = l.z * (t + c);
return store;
}
/**
* Computes GGX half vector in local space
*
* @param xi
* @param a2
* @param store
* @return
*/
public Vector3f importanceSampleGGX(Vector4f xi, float a2, Vector3f store) {
if (store == null) {
store = new Vector3f();
}
@ -243,22 +345,9 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
float sinThetaCosPhi = sinTheta * xi.z;//xi.z is cos(phi)
float sinThetaSinPhi = sinTheta * xi.w;//xi.w is sin(phi)
Vector3f upVector = Vector3f.UNIT_X;
if (abs(normal.z) < 0.999) {
upVector = Vector3f.UNIT_Y;
}
Vector3f tangentX = tmp1.set(upVector).crossLocal(normal).normalizeLocal();
Vector3f tangentY = tmp2.set(normal).crossLocal(tangentX);
// Tangent to world space
tangentX.multLocal(sinThetaCosPhi);
tangentY.multLocal(sinThetaSinPhi);
tmp3.set(normal).multLocal(cosTheta);
// Tangent to world space
store.set(tangentX).addLocal(tangentY).addLocal(tmp3);
store.x = sinThetaCosPhi;
store.y = sinThetaSinPhi;
store.z = cosTheta;
return store;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -61,7 +61,7 @@ public abstract class RunnableWithProgress implements Runnable {
}
/**
* return the curent progress of the process.
* return the current progress of the process.
*
* @return
*/

@ -31,17 +31,15 @@
*/
package com.jme3.environment.util;
import com.jme3.environment.util.EnvMapUtils;
import com.jme3.math.ColorRGBA;
import static com.jme3.math.FastMath.pow;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.*;
import com.jme3.texture.Image;
import com.jme3.texture.TextureCubeMap;
import com.jme3.texture.image.DefaultImageRaster;
import com.jme3.texture.image.MipMapImageRaster;
import com.jme3.util.BufferUtils;
import static com.jme3.math.FastMath.pow;
/**
* Wraps a Cube map and allows to read from or write pixels into it.
*
@ -57,6 +55,8 @@ public class CubeMapWrapper {
private final Vector2f uvs = new Vector2f();
private final Image image;
private final ColorRGBA tmpColor = new ColorRGBA();
/**
* Creates a CubeMapWrapper for the given cube map
* Note that the cube map must be initialized, and the mipmaps sizes should
@ -105,7 +105,7 @@ public class CubeMapWrapper {
* @param store the color in which to store the pixel color read.
* @return the color of the pixel read.
*/
public ColorRGBA getPixel(Vector3f vector, int mipLevel, ColorRGBA store) {
public ColorRGBA getPixel(Vector3f vector, float mipLevel, ColorRGBA store) {
if (mipMapRaster == null) {
throw new IllegalArgumentException("This cube map has no mip maps");
}
@ -113,10 +113,26 @@ public class CubeMapWrapper {
store = new ColorRGBA();
}
int face = EnvMapUtils.getCubemapFaceTexCoordFromVector(vector, sizes[mipLevel], uvs, EnvMapUtils.FixSeamsMethod.Stretch);
int lowerMipLevel = (int) mipLevel;
int higherMipLevel = (int) FastMath.ceil(mipLevel);
float ratio = mipLevel - lowerMipLevel;
int face = EnvMapUtils.getCubemapFaceTexCoordFromVector(vector, sizes[lowerMipLevel], uvs, EnvMapUtils.FixSeamsMethod.Stretch);
mipMapRaster.setSlice(face);
mipMapRaster.setMipLevel(mipLevel);
return mipMapRaster.getPixel((int) uvs.x, (int) uvs.y, store);
mipMapRaster.setMipLevel(lowerMipLevel);
mipMapRaster.getPixel((int) uvs.x, (int) uvs.y, store);
face = EnvMapUtils.getCubemapFaceTexCoordFromVector(vector, sizes[higherMipLevel], uvs, EnvMapUtils.FixSeamsMethod.Stretch);
mipMapRaster.setSlice(face);
mipMapRaster.setMipLevel(higherMipLevel);
mipMapRaster.getPixel((int) uvs.x, (int) uvs.y, tmpColor);
store.r = FastMath.interpolateLinear(ratio, store.r, tmpColor.r);
store.g = FastMath.interpolateLinear(ratio, store.g, tmpColor.g);
store.b = FastMath.interpolateLinear(ratio, store.b, tmpColor.b);
store.a = FastMath.interpolateLinear(ratio, store.a, tmpColor.a);
return store;
}
/**

@ -37,18 +37,15 @@ import com.jme3.math.*;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.TextureCubeMap;
import com.jme3.texture.*;
import com.jme3.texture.image.ColorSpace;
import com.jme3.ui.Picture;
import com.jme3.util.BufferUtils;
import com.jme3.util.TempVars;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import static com.jme3.math.FastMath.*;
import com.jme3.util.TempVars;
import static com.jme3.math.FastMath.*;
/**
*
@ -88,6 +85,11 @@ public class EnvMapUtils {
None
}
public static enum GenerationType {
Fast,
HighQuality
}
/**
* Creates a cube map from 6 images
*
@ -117,6 +119,8 @@ public class EnvMapUtils {
cubeImage.addData(backImg.getData(0));
cubeImage.addData(frontImg.getData(0));
cubeImage.setMipMapSizes(rightImg.getMipMapSizes());
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
cubeMap.setAnisotropicFilter(0);
cubeMap.setMagFilter(Texture.MagFilter.Bilinear);
@ -148,6 +152,8 @@ public class EnvMapUtils {
cubeImage.addData(d.duplicate());
}
cubeImage.setMipMapSizes(srcImg.getMipMapSizes());
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
cubeMap.setAnisotropicFilter(sourceMap.getAnisotropicFilter());
cubeMap.setMagFilter(sourceMap.getMagFilter());
@ -730,7 +736,7 @@ public class EnvMapUtils {
pem.setMagFilter(Texture.MagFilter.Bilinear);
pem.setMinFilter(Texture.MinFilter.Trilinear);
pem.getImage().setColorSpace(ColorSpace.Linear);
int nbMipMap = (int) (Math.log(size) / Math.log(2) - 1);
int nbMipMap = Math.min(6, (int) (Math.log(size) / Math.log(2)));
CubeMapWrapper targetWrapper = new CubeMapWrapper(pem);
targetWrapper.initMipMaps(nbMipMap);
return pem;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -114,7 +114,7 @@ public class LightsDebugState extends BaseAppState {
}
/**
* Set the scenes for wich to render light gizmos.
* Set the scenes for which to render light gizmos.
* @param scene
*/
public void setScene(Spatial scene) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,7 +34,6 @@ package com.jme3.input;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.input.controls.*;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
@ -420,7 +419,7 @@ public class ChaseCamera implements ActionListener, AnalogListener, Control, Jme
//the user is rotating the cam by dragging the mouse
if (canRotate) {
//reseting the trailing lerp factor
//reset the trailing lerp factor
trailingLerpFactor = 0;
//stop trailing user has the control
trailing = false;
@ -582,18 +581,17 @@ public class ChaseCamera implements ActionListener, AnalogListener, Control, Jme
/**
* clone this camera for a spatial
*
* @param spatial
* @return
*/
@Deprecated
@Override
public Control cloneForSpatial(Spatial spatial) {
ChaseCamera cc = new ChaseCamera(cam, spatial, inputManager);
cc.setMaxDistance(getMaxDistance());
cc.setMinDistance(getMinDistance());
return cc;
throw new UnsupportedOperationException();
}
@Override
@Override
public Object jmeClone() {
ChaseCamera cc = new ChaseCamera(cam, inputManager);
cc.target = target;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -423,15 +423,22 @@ public class InputManager implements RawInputListener {
/**
* Callback from RawInputListener. Do not use.
*
* @param evt event to add to the input queue (not null)
*/
@Override
public void onMouseMotionEvent(MouseMotionEvent evt) {
if (!eventsPermitted) {
throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time.");
}
/*
* If events aren't allowed, the event may be a "first mouse event"
* triggered by the constructor setting the mouse listener.
* In that case, use the event to initialize the cursor position,
* but don't queue it for further processing.
* This is part of the fix for issue #792.
*/
cursorPos.set(evt.getX(), evt.getY());
inputQueue.add(evt);
if (eventsPermitted) {
inputQueue.add(evt);
}
}
private void onMouseButtonEventQueued(MouseButtonEvent evt) {
@ -867,7 +874,7 @@ public class InputManager implements RawInputListener {
// larynx, 2011.06.10 - flag event as reusable because
// the android input uses a non-allocating ringbuffer which
// needs to know when the event is not anymore in inputQueue
// and therefor can be reused.
// and therefore can be reused.
event.setConsumed();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -123,7 +123,7 @@ public interface Joystick {
/**
* Returns the POV Y axis for this joystick. This is a convenience axis
* providing an y-axis subview of the HAT axis.
* providing a y-axis subview of the HAT axis.
*
* @see JoystickAxis#assignAxis(java.lang.String, java.lang.String)
*/

@ -445,6 +445,16 @@ public interface KeyInput extends Input {
* (J3100).
*/
public static final int KEY_UNLABELED = 0x97;
/**
* PrtScr key.
* Note: for use on keyboards with a PrtScr key that is
* separate from the SysRq key. Most keyboards combine
* SysRq and PrtScr so if the intent is to actually
* capture the user's desire to capture the screen
* then SysRq is the most likely scan code.
* Use PrtScr to catch the rest (laptops, mini-keyboards, etc.)
*/
public static final int KEY_PRTSCR = 0x9A;
/**
* Enter key (num pad).
*/

@ -127,15 +127,13 @@ public class LightProbe extends Light implements Savable {
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule ic = im.getCapsule(this);
prefilteredEnvMap = (TextureCubeMap) ic.readSavable("prefilteredEnvMap", null);
position = (Vector3f) ic.readSavable("position", this);
position = (Vector3f) ic.readSavable("position", null);
bounds = (BoundingVolume) ic.readSavable("bounds", new BoundingSphere(1.0f, Vector3f.ZERO));
nbMipMaps = ic.readInt("nbMipMaps", 0);
ready = ic.readBoolean("ready", false);
Savable[] coeffs = ic.readSavableArray("shCoeffs", null);
if (coeffs == null) {
ready = false;
@ -145,7 +143,6 @@ public class LightProbe extends Light implements Savable {
for (int i = 0; i < coeffs.length; i++) {
shCoeffs[i] = (Vector3f) coeffs[i];
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -48,7 +48,7 @@ public interface LightProbeBlendingStrategy {
public void registerProbe(LightProbe probe);
/**
* Populates the resulting light probes into the given light list.
* @param g the geometry for wich the light list is computed
* @param g the geometry for which the light list is computed
* @param lightList the result light list
*/
public void populateProbes(Geometry g, LightList lightList);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012, 2015-2016 jMonkeyEngine
* Copyright (c) 2009-2012, 2015-2016, 2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -54,7 +54,7 @@ import java.io.IOException;
* <p>
* In addition to a position, point lights also have a radius which
* can be used to attenuate the influence of the light depending on the
* distance between the light and the effected object.
* distance between the light and the affected object.
*
*/
public class PointLight extends Light {
@ -155,7 +155,7 @@ public class PointLight extends Light {
* Setting a non-zero radius indicates the light should use attenuation.
* If a pixel's distance to this light's position
* is greater than the light's radius, then the pixel will not be
* effected by this light, if the distance is less than the radius, then
* affected by this light, if the distance is less than the radius, then
* the magnitude of the influence is equal to distance / radius.
*
* @param radius the radius of the light influence.

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012, 2015-2016 jMonkeyEngine
* Copyright (c) 2009-2012, 2015-2016, 2018 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -337,7 +337,7 @@ public class SpotLight extends Light {
* Setting a non-zero range indicates the light should use attenuation.
* If a pixel's distance to this light's position
* is greater than the light's range, then the pixel will not be
* effected by this light, if the distance is less than the range, then
* affected by this light, if the distance is less than the range, then
* the magnitude of the influence is equal to distance / range.
*
* @param spotRange the range of the light influence.

@ -0,0 +1,45 @@
/*
* Copyright (c) 2009-2018 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.material;
/**
* This class is to provide some constants materials.
*
* @author oualid
*/
public class Materials {
public static final String UNSHADED = "Common/MatDefs/Misc/Unshaded.j3md";
public static final String LIGHTING = "Common/MatDefs/Light/Lighting.j3md";
public static final String PBR = "Common/MatDefs/Light/PBRLighting.j3md";
}

@ -206,7 +206,9 @@ public class ShaderGenerationInfo implements Savable, Cloneable {
clone.vertexUniforms.add(uniform.clone());
}
clone.vertexGlobal = vertexGlobal.clone();
if (vertexGlobal != null) {
clone.vertexGlobal = vertexGlobal.clone();
}
for (ShaderNodeVariable varying : varyings) {
clone.varyings.add(varying.clone());

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save