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 **/.classpath
**/.settings **/.settings
**/.project **/.project
**/out
/.gradle/ /.gradle/
/.nb-gradle/ /.nb-gradle/
/.idea/ /.idea/

@ -55,5 +55,5 @@ We generally abide by the standard Java Code Conventions. Besides that, just mak
## Documentation ## Documentation
- How to edit the wiki - WIP - How to edit the [wiki](https://github.com/jMonkeyEngine/wiki).
- How to edit JavaDocs - WIP - 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) [![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: 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 { subprojects {
if(!project.name.equals('jme3-android-examples')) { if(!project.name.equals('jme3-android-examples')) {
apply from: rootProject.file('common.gradle') 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') apply from: rootProject.file('bintray.gradle')
} }
} else { } else {
@ -66,9 +66,9 @@ task createZipDistribution(type:Zip,dependsOn:["dist","libDist"], description:"P
archiveName "jME" + jmeFullVersion + ".zip" archiveName "jME" + jmeFullVersion + ".zip"
into("/") { into("/") {
from {"./dist"} from {"./dist"}
} }
into("/sources") { 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.') { task mergedJavadoc(type: Javadoc, description: 'Creates Javadoc from all the projects.') {
title = 'jMonkeyEngine3' title = 'jMonkeyEngine3'
destinationDir = mkdir("dist/javadoc") destinationDir = mkdir("dist/javadoc")
options.encoding = 'UTF-8' options.encoding = 'UTF-8'
// Allows Javadoc to be generated on Java 8 despite doclint errors. // Allows Javadoc to be generated on Java 8 despite doclint errors.
if (JavaVersion.current().isJava8Compatible()) { if (JavaVersion.current().isJava8Compatible()) {
options.addStringOption('Xdoclint:none', '-quiet') options.addStringOption('Xdoclint:none', '-quiet')
} }
options.overview = file("javadoc-overview.html") options.overview = file("javadoc-overview.html")
// Note: The closures below are executed lazily. // Note: The closures below are executed lazily.
source subprojects.collect {project -> 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.') { task wrapper(type: Wrapper, description: 'Creates and deploys the Gradle wrapper to the current directory.') {
gradleVersion = '3.2.1' gradleVersion = '4.1'
} }
ext { ext {
@ -137,7 +137,7 @@ task configureAndroidNDK {
if (System.env.ANDROID_NDK != null) { if (System.env.ANDROID_NDK != null) {
ndkBuildPath = System.env.ANDROID_NDK + File.separator + ndkBuildFile ndkBuildPath = System.env.ANDROID_NDK + File.separator + ndkBuildFile
} }
if (new File(ndkBuildPath).exists()) { if (new File(ndkBuildPath).exists()) {
ndkExists = true ndkExists = true
ndkCommandPath = ndkBuildPath ndkCommandPath = ndkBuildPath

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

@ -1,7 +1,7 @@
# Version number used for plugins, only 3 numbers (e.g. 3.1.3) # 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! # Version used for application and settings folder, no spaces!
jmeMainVersion = 3.2 jmeMainVersion = 3.3
# Version addition pre-alpha-svn, Stable, Beta # Version addition pre-alpha-svn, Stable, Beta
jmeVersionTag = SNAPSHOT jmeVersionTag = SNAPSHOT
# Increment this each time jmeVersionTag changes but jmeVersion stays the same # 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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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 esac
fi fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules # Escape application args
function splitJvmOpts() { save ( ) {
JVM_OPTS=("$@") for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
} }
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS APP_ARGS=$(save "$@")
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
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 @rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args :win9xME_args
@rem Slurp the command line arguments. @rem Slurp the command line arguments.
@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%* set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute :execute
@rem Setup the command line @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 * 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 * @param view
*/ */
public void onClick(View view) { public void onClick(View view) {

@ -5,5 +5,5 @@ if (!hasProperty('mainClass')) {
dependencies { dependencies {
compile project(':jme3-core') compile project(':jme3-core')
compile project(':jme3-plugins') 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -59,7 +59,7 @@ import java.util.logging.Logger;
/** /**
* AndroidSensorJoyInput converts the Android Sensor system into Joystick events. * AndroidSensorJoyInput converts the Android Sensor system into Joystick events.
* A single joystick is configured and includes data for all configured sensors * 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. * Each axis is named according to the static strings in SensorJoystickAxis.
* Refer to the strings defined in SensorJoystickAxis for a list of supported * 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 * Calculates the device orientation based off the data received from the
* Acceleration Sensor and Mangetic Field sensor * Acceleration Sensor and Magnetic Field sensor
* Values are returned relative to the Earth. * Values are returned relative to the Earth.
* *
* From the Android Doc * From the Android Doc

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -69,7 +69,7 @@ public class BlenderKey extends ModelKey {
*/ */
protected String usedWorld; 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). * null. If the value is null the importer will use its own default material (gray color - like in blender).
*/ */
protected Material defaultMaterial; 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 * 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 * @param usedWorld
* the name of the WORLD block used during loading * 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 * @return the name of the WORLD block used during loading
*/ */
public String getUsedWorld() { 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) { for (Long boneOMA : alteredOmas) {
BoneContext boneContext = blenderContext.getBoneContext(boneOMA); BoneContext boneContext = blenderContext.getBoneContext(boneOMA);
int boneIndex = skeleton.getBoneIndex(boneContext.getBone()); 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. * 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) * @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 * @param alongRatio
* the relative distance along the curve; should be a value between 0 and 1 inclusive; * 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 * 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. * based on the bevel generating parameters in blender.
* @param curveStructure * @param curveStructure
* the structure with the curve's data (the curve being loaded, NOT the bevel curve) * 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 * 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 * @param points
* the bevel 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 * 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) * @author Marcin Roguski (Kaelthas)
*/ */
@ -776,7 +776,7 @@ public class CurvesTemporalMesh extends TemporalMesh {
} }
if (cyclic) { 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 // 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]); 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 * @param alongRatio
* the relative distance along the curve; should be a value between 0 and 1 inclusive; * 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 * 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -85,7 +85,7 @@ public class DnaBlockData {
names[i] = inputStream.readString(); names[i] = inputStream.readString();
} }
// reding types // reading types
inputStream.alignPosition(4); inputStream.alignPosition(4);
identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte(); identifier = inputStream.readByte() << 24 | inputStream.readByte() << 16 | inputStream.readByte() << 8 | inputStream.readByte();
if (identifier != TYPE_ID) { if (identifier != TYPE_ID) {
@ -181,7 +181,7 @@ public class DnaBlockData {
/** /**
* This method converts the given identifier code to string. * This method converts the given identifier code to string.
* @param code * @param code
* the code taht is to be converted * the code that is to be converted
* @return the string value of the identifier * @return the string value of the identifier
*/ */
private String toString(int code) { private String toString(int code) {

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@
package com.jme3.scene.plugins.blender.file; package com.jme3.scene.plugins.blender.file;
/** /**
* An array that can be dynamically modified/ * An array that can be dynamically modified
* @author Marcin Roguski * @author Marcin Roguski
* @param <T> * @param <T>
* the type of stored data in the array * 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. */ /** An array object that holds the required data. */
private T[] array; 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: * 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. * 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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. * held by this structure within the blend file.
* @return a list of filled structures * @return a list of filled structures
* @throws BlenderFileException * @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. * is thrown.
* @return the address of the feature stored in this structure * @return the address of the feature stored in this structure
*/ */

@ -1,6 +1,7 @@
package com.jme3.scene.plugins.blender.materials; package com.jme3.scene.plugins.blender.materials;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -106,7 +107,7 @@ public final class MaterialContext implements Savable {
boolean transparent = false; boolean transparent = false;
if (diffuseColor != null) { if (diffuseColor != null) {
transparent = diffuseColor.a < 1.0f; 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); 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)); 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 // applying textures
int textureIndex = 0; int textureIndex = 0;
@ -175,16 +182,19 @@ public final class MaterialContext implements Savable {
String usedUserUVSet = combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext); String usedUserUVSet = combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
this.setTexture(material, combinedTexture.getMappingType(), combinedTexture.getResultTexture()); 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) { if(usedUserUVSet == null || unusedUserDefinedUVCoords.containsKey(usedUserUVSet)) {
userDefinedUVCoordinates = new HashMap<>(userDefinedUVCoordinates); List<Vector2f> uvs = combinedTexture.getResultUVS();
userDefinedUVCoordinates.remove(usedUserUVSet); 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 { } 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); 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."); 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); 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) { if (textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
List<Vector2f> uvs = entry.getValue(); List<Vector2f> uvs = entry.getValue();
VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]); 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -324,7 +324,7 @@ public final class Vector3d implements Savable, Cloneable, Serializable {
* the vector to take the cross product of with this. * the vector to take the cross product of with this.
* @param result * @param result
* the vector to store the cross product 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) { public Vector3d cross(Vector3d v, Vector3d result) {
return this.cross(v.x, v.y, v.z, 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. * z component of the vector to take the cross product of with this.
* @param result * @param result
* the vector to store the cross product 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) { public Vector3d cross(double otherX, double otherY, double otherZ, Vector3d result) {
if (result == null) { 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 * internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned. * calls. If the provided vector is null, null is returned.
* *
* @param vec * @param vec
* the vector to mult to this vector. * the vector to multiply by this vector.
* @return this * @return this
*/ */
public Vector3d multLocal(Vector3d vec) { 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 * internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned. * 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 * internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned. * 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 * internally, and returns a handle to this vector for easy chaining of
* calls. If the provided vector is null, null is returned. * 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 * <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. * the same hash code value.
* @return the hash code value of this vector. * @return the hash code value of this vector.
*/ */

@ -291,27 +291,30 @@ public class MeshHelper extends AbstractBlenderHelper {
Structure defbase = (Structure) parent.getFieldValue("defbase"); Structure defbase = (Structure) parent.getFieldValue("defbase");
List<String> groupNames = new ArrayList<String>(); List<String> groupNames = new ArrayList<String>();
List<Structure> defs = defbase.evaluateListBase(); 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 Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
if (pDvert.isNotNull()) {// assigning weights and bone indices if (pDvert.isNotNull()) {// assigning weights and bone indices
List<Structure> dverts = pDvert.fetchData(); List<Structure> dverts = pDvert.fetchData();
for (Structure dvert : dverts) { for (Structure dvert : dverts) {
Map<String, Float> weightsForVertex = new HashMap<String, Float>(); Map<String, Float> weightsForVertex = new HashMap<String, Float>();
Pointer pDW = (Pointer) dvert.getFieldValue("dw"); Pointer pDW = (Pointer) dvert.getFieldValue("dw");
if (pDW.isNotNull()) { if (pDW.isNotNull()) {
List<Structure> dw = pDW.fetchData(); List<Structure> dw = pDW.fetchData();
for (Structure deformWeight : dw) { for (Structure deformWeight : dw) {
int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue(); int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue();
float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue(); float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
String groupName = groupNames.get(groupIndex); 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>(); private Set<Integer> verticesOnOriginalEdges = new HashSet<Integer>();
/** /**
* Constructor loads all neccessary modifier data. * Constructor loads all necessary modifier data.
* @param modifierStructure * @param modifierStructure
* the modifier structure * the modifier structure
* @param blenderContext * @param blenderContext
@ -193,7 +193,7 @@ public class SubdivisionSurfaceModifier extends Modifier {
// moving the vertex // moving the vertex
v.addLocal(t); v.addLocal(t);
// applying crease weight if neccessary // applying crease weight if necessary
CreasePoint creasePoint = creasePoints.get(i); CreasePoint creasePoint = creasePoints.get(i);
if (creasePoint.getTarget() != null && creasePoint.getWeight() != 0) { if (creasePoint.getTarget() != null && creasePoint.getWeight() != 0) {
t = creasePoint.getTarget().subtractLocal(v).multLocal(creasePoint.getWeight()); t = creasePoint.getTarget().subtractLocal(v).multLocal(creasePoint.getWeight());

@ -31,12 +31,14 @@
*/ */
package com.jme3.scene.plugins.blender.textures; 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.scene.plugins.blender.file.BlenderInputStream;
import com.jme3.texture.Image; import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import com.jme3.texture.plugins.AWTLoader; import com.jme3.texture.plugins.AWTLoader;
import com.jme3.texture.plugins.DDSLoader; import com.jme3.texture.plugins.HDRLoader;
import com.jme3.texture.plugins.TGALoader; import java.util.logging.Level;
import java.io.InputStream;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
@ -47,11 +49,29 @@ import java.util.logging.Logger;
*/ */
/* package */class ImageLoader extends AWTLoader { /* package */class ImageLoader extends AWTLoader {
private static final Logger LOGGER = Logger.getLogger(ImageLoader.class.getName()); private static final Logger LOGGER = Logger.getLogger(ImageLoader.class.getName());
private static final Logger hdrLogger = Logger.getLogger(HDRLoader.class.getName()); // Used to silence HDR Errors
protected DDSLoader ddsLoader = new DDSLoader(); // DirectX image loader
/**
* 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 * @param inputStream
* blender input stream * blender input stream
@ -60,76 +80,57 @@ import java.util.logging.Logger;
* @param flipY * @param flipY
* if the image should be flipped (does not work with DirectX image) * 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 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) { public Image loadImage(AssetManager assetManager, BlenderInputStream inputStream, int startPosition, boolean flipY) {
// loading using AWT loader Texture tex = loadTexture(assetManager, inputStream, startPosition, flipY);
inputStream.setPosition(startPosition);
Image result = this.loadImage(inputStream, ImageType.AWT, flipY); if (tex == null) {
// loading using TGA loader return null;
if (result == null) { } else {
inputStream.setPosition(startPosition); return tex.getImage();
result = this.loadImage(inputStream, ImageType.TGA, flipY);
}
// loading using DDS loader
if (result == null) {
inputStream.setPosition(startPosition);
result = this.loadImage(inputStream, ImageType.DDS, flipY);
} }
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 * @param inputStream
* the input stream we read the image from * blender input stream
* @param imageType * @param startPosition
* the type of the image {@link ImageType} * position in the stream where the image data starts
* @param flipY * @param flipY
* if the image should be flipped (does not work with DirectX image) * 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) { public Texture loadTexture(AssetManager assetManager, BlenderInputStream inputStream, int startPosition, boolean flipY) {
Image result = null; inputStream.setPosition(startPosition);
switch (imageType) { TextureKey tKey;
case AWT: Texture result = null;
try {
result = this.load(inputStream, flipY); hdrLogger.setLevel(Level.SEVERE); // When we bruteforce try HDR on a non hdr file, it prints unreadable chars
} catch (Exception e) {
LOGGER.warning("Unable to load image using AWT loader!"); for (String ext: extensions) {
} tKey = new TextureKey("dummy" + ext, flipY);
break; try {
case DDS: result = assetManager.loadAssetFromStream(tKey, inputStream);
try { } catch (Exception e) {
result = ddsLoader.load(inputStream); continue;
} catch (Exception e) { }
LOGGER.warning("Unable to load image using DDS loader!");
} if (result != null) {
break; break; // Could locate a possible asset
case TGA: }
try { }
result = TGALoader.load(inputStream, flipY);
} catch (Exception e) { if (result == null) {
LOGGER.warning("Unable to load image using TGA loader!"); 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"
break; + "way for us to tell you which texture it was.");
default:
throw new IllegalStateException("Unknown image type: " + imageType);
} }
return result; 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.z = 1;
N.divideLocal(den); 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)); bumpMap.setRGB(x, y, ImageUtils.vectorToColor(N.x, N.y, N.z));
} }
} }
@ -422,7 +422,7 @@ public final class ImageUtils {
* pixel's X coordinate * pixel's X coordinate
* @param y * @param y
* pixel's Y coordinate * 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) { private static int getHeight(BufferedImage image, int x, int y) {
if (x < 0) { if (x < 0) {

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -72,6 +72,7 @@ import com.jme3.texture.Texture.WrapMode;
import com.jme3.texture.Texture2D; import com.jme3.texture.Texture2D;
import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ColorSpace;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import com.jme3.util.PlaceholderAssets;
/** /**
* A class that is used in texture calculations. * A class that is used in texture calculations.
@ -251,7 +252,11 @@ public class TextureHelper extends AbstractBlenderHelper {
blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition()); blenderContext.getInputStream().setPosition(dataFileBlock.getBlockPosition());
// Should the texture be flipped? It works for sinbad .. // 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 { //} else {
@ -310,7 +315,7 @@ public class TextureHelper extends AbstractBlenderHelper {
* @param pos * @param pos
* the relative position (value of range <0, 1> (both inclusive)) * the relative position (value of range <0, 1> (both inclusive))
* @param size * @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) * depth)
* @return the integer index of the pixel on the line of the specified width * @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 * AssetManager that the blend file was loaded with. It returns a texture
* with a full assetKey that references the original texture so it later * 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 * 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 * 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 * 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(); int texflag = ((Number) textureData.mtex.getFieldValue("texflag")).intValue();
boolean negateTexture = (texflag & 0x04) != 0; boolean negateTexture = (texflag & 0x04) != 0;
boolean colorSet = false;
for (int i = 0; i < mappings.length; ++i) { for (int i = 0; i < mappings.length; ++i) {
if ((mappings[i] & mapto.intValue()) != 0) { 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); CombinedTexture combinedTexture = new CombinedTexture(mappings[i], !skyTexture);
int blendType = ((Number) textureData.mtex.getFieldValue("blendtype")).intValue(); 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() }; 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>>(); Map<Number, List<TextureData>> result = new HashMap<Number, List<TextureData>>();
for (TextureData data : textures) { for (TextureData data : textures) {
Number mapto = (Number) data.mtex.getFieldValue("mapto"); Number mapto = (Number) data.mtex.getFieldValue("mapto");
boolean colorSet = false;
for (int i = 0; i < mappings.length; ++i) { for (int i = 0; i < mappings.length; ++i) {
if ((mappings[i] & mapto.intValue()) != 0) { 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]); List<TextureData> datas = result.get(mappings[i]);
if (datas == null) { if (datas == null) {
datas = new ArrayList<TextureData>(); 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. */ /** The name of the user's UV coordinates that are used for this texture. */
public String uvCoordinatesName; public String uvCoordinatesName;
} }
} }

@ -163,9 +163,19 @@ public class TextureBlenderAWT extends AbstractTextureBlender {
* the blender context * the blender context
*/ */
protected void blendPixel(float[] result, float[] materialColor, float[] pixelColor, BlenderContext blenderContext) { 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 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) { switch (blendType) {
case MTEX_BLEND: case MTEX_BLEND:
result[0] = blendFactor * pixelColor[0] + oneMinusFactor * materialColor[0]; 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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> * 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 * 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> * collisionGroup of the other in its collideWithGroups set.<br>
* @param nodeA CollisionObject #1 * @param nodeA CollisionObject #1
* @param nodeB CollisionObject #2 * @param nodeB CollisionObject #2

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,6 +41,7 @@ import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; 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 ) { public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial); this.spatial = cloner.clone(spatial);
createSpatialData(this.spatial); createSpatialData(this.spatial);

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -89,21 +89,10 @@ public class CharacterControl extends PhysicsCharacter implements PhysicsControl
return spatial.getWorldTranslation(); return spatial.getWorldTranslation();
} }
@Deprecated
@Override @Override
public Control cloneForSpatial(Spatial spatial) { public Control cloneForSpatial(Spatial spatial) {
CharacterControl control = new CharacterControl(collisionShape, stepHeight); throw new UnsupportedOperationException();
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;
} }
@Override @Override

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -59,9 +59,7 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@ -73,7 +71,7 @@ import java.util.logging.Logger;
* use this control you need a model with an AnimControl and a * use this control you need a model with an AnimControl and a
* SkeletonControl.<br> This should be the case if you imported an animated * SkeletonControl.<br> This should be the case if you imported an animated
* model from Ogre or blender.<br> Note enabling/disabling the control * 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 * shapes for each bones of the skeleton when you call
* spatial.addControl(ragdollControl). <ul> <li>The shape is HullCollision shape * spatial.addControl(ragdollControl). <ul> <li>The shape is HullCollision shape
* based on the vertices associated with each bone and based on a tweakable * 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 * </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 * 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 * 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 * skeleton (for example animated by a key framed animation) this mode is
* enabled by calling setKinematicMode(); </li> <li><strong>The ragdoll modes * enabled by calling setKinematicMode(); </li> <li><strong>The ragdoll modes
* :</strong><br> To enable this behavior, you need to call setRagdollMode() * :</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> * will fall under the gravity and move if any force is applied to it. </li>
* </ul> </p> * </ul> </p>
* *
@ -171,7 +169,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
} }
/** /**
* contruct a KinematicRagdollControl * construct a KinematicRagdollControl
*/ */
public KinematicRagdollControl() { public KinematicRagdollControl() {
baseRigidBody = new PhysicsRigidBody(new BoxCollisionShape(Vector3f.UNIT_XYZ.mult(0.1f)), 1); 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){ if(mode == Mode.IK){
ikUpdate(tpf); ikUpdate(tpf);
} else if (mode == mode.Ragdoll && targetModel.getLocalTranslation().equals(modelPosition)) { } 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); ragDollUpdate(tpf);
} else { } else {
kinematicUpdate(tpf); kinematicUpdate(tpf);
@ -217,12 +215,12 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
Vector3f position = vars.vect1; Vector3f position = vars.vect1;
//retrieving bone position in physic world space //retrieving bone position in physics world space
Vector3f p = link.rigidBody.getMotionState().getWorldLocation(); Vector3f p = link.rigidBody.getMotionState().getWorldLocation();
//transforming this position with inverse transforms of the model //transforming this position with inverse transforms of the model
targetModel.getWorldTransform().transformInverseVector(p, position); 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(); Quaternion q = link.rigidBody.getMotionState().getWorldRotationQuat();
//multiplying this rotation by the initialWorld rotation of the bone, //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); link.bone.setUserTransformsInModelSpace(position, tmpRot1);
} else { } else {
//boneList is not empty, this means some bones of the skeleton might not be associated with a collision shape. //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); RagdollUtils.setTransform(link.bone, position, tmpRot1, false, boneList);
} }
} }
@ -264,7 +262,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
} }
protected void kinematicUpdate(float tpf) { 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(); TempVars vars = TempVars.get();
Quaternion tmpRot1 = vars.quat1; Quaternion tmpRot1 = vars.quat1;
Quaternion tmpRot2 = vars.quat2; Quaternion tmpRot2 = vars.quat2;
@ -420,7 +418,7 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
targetModel.getWorldRotation().mult(tmpRot1, tmpRot1); targetModel.getWorldRotation().mult(tmpRot1, tmpRot1);
tmpRot1.normalizeLocal(); tmpRot1.normalizeLocal();
//updating physic location/rotation of the physic bone //updating physics location/rotation of the physics bone
link.rigidBody.setPhysicsLocation(position); link.rigidBody.setPhysicsLocation(position);
link.rigidBody.setPhysicsRotation(tmpRot1); 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 * 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 * be animated by the keyframe animation, but will be able to physically
* interact with its physic environnement * interact with its physics environment
* *
* @param ragdollEnabled * @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 * follow the movements of the skeleton, and can interact with physical
* environement * environment
*/ */
public void setKinematicMode() { public void setKinematicMode() {
if (mode != Mode.Kinematic) { 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 * @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 rm
* @param vp * @param vp
@ -912,16 +910,6 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
public void render(RenderManager rm, ViewPort vp) { 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 @Override
public Object jmeClone() { public Object jmeClone() {
KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold); KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -53,7 +53,6 @@ import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere; import com.jme3.scene.shape.Sphere;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
/** /**
@ -92,31 +91,10 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
super(shape, mass); super(shape, mass);
} }
@Deprecated
@Override @Override
public Control cloneForSpatial(Spatial spatial) { public Control cloneForSpatial(Spatial spatial) {
RigidBodyControl control = new RigidBodyControl(collisionShape, mass); throw new UnsupportedOperationException();
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;
} }
@Override @Override

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -43,7 +43,6 @@ import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control; import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
@ -108,54 +107,10 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl, Jm
return spatial.getWorldRotation(); return spatial.getWorldRotation();
} }
@Deprecated
@Override @Override
public Control cloneForSpatial(Spatial spatial) { public Control cloneForSpatial(Spatial spatial) {
VehicleControl control = new VehicleControl(collisionShape, mass); throw new UnsupportedOperationException();
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;
} }
@Override @Override

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -123,7 +123,7 @@ public class RagdollUtils {
/** /**
* Create a hull collision shape from linked vertices to this bone. * 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 pointsMap
* @param boneIndices * @param boneIndices
@ -160,7 +160,7 @@ public class RagdollUtils {
return new HullCollisionShape(p); 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) { public static List<Integer> getBoneIndices(Bone bone, Skeleton skeleton, Set<String> boneList) {
List<Integer> list = new LinkedList<Integer>(); List<Integer> list = new LinkedList<Integer>();
if (boneList.isEmpty()) { if (boneList.isEmpty()) {
@ -266,7 +266,7 @@ public class RagdollUtils {
/** /**
* Updates a bone position and rotation. * 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 * So they have to be updated
* @param bone the bone * @param bone the bone
* @param pos the position * @param pos the position

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -235,7 +235,7 @@ public class PhysicsSpace {
// collides = (bp1.collisionFilterGroup & bp.collisionFilterMask) != 0; // collides = (bp1.collisionFilterGroup & bp.collisionFilterMask) != 0;
// } // }
// if (collides) { // 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 colOb = (com.bulletphysics.collision.dispatch.CollisionObject) bp.clientObject;
// com.bulletphysics.collision.dispatch.CollisionObject colOb1 = (com.bulletphysics.collision.dispatch.CollisionObject) bp1.clientObject; // com.bulletphysics.collision.dispatch.CollisionObject colOb1 = (com.bulletphysics.collision.dispatch.CollisionObject) bp1.clientObject;
// assert (colOb.getUserPointer() != null && colOb1.getUserPointer() != null); // 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 * 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 * 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 * 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. * @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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -96,7 +96,7 @@ public abstract class PhysicsCollisionObject implements Savable {
* Sets the collision group number for this physics object. <br> * 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. * 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> * 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. * collisionGroup of the other in its collideWithGroups set.
* @param collisionGroup the collisionGroup to 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> * 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> * collisionGroup of the other in its collideWithGroups set.<br>
* @param collisionGroup * @param collisionGroup
*/ */

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -121,7 +121,7 @@ public class HingeJoint extends PhysicsJoint {
* @param high the high limit in radians. * @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 _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 _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) { public void setLimit(float low, float high, float _softness, float _biasFactor, float _relaxationFactor) {
biasFactor = _biasFactor; biasFactor = _biasFactor;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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 * 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. * of movement it is exposed to and its weight.
* @param kinematic * @param kinematic
*/ */

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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 * This value caps 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 maxSuspensionForce * @param maxSuspensionForce
*/ */
public void setMaxSuspensionForce(float 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 * This value caps 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 wheel * @param wheel
* @param maxSuspensionForce * @param maxSuspensionForce
*/ */

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2017 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,6 +35,7 @@ import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.collision.shapes.CompoundCollisionShape; import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape;
import com.jme3.math.Matrix3f; import com.jme3.math.Matrix3f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry; import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
import com.jme3.scene.Node; import com.jme3.scene.Node;
@ -111,9 +112,16 @@ public class DebugShapeFactory {
public static Mesh getDebugMesh(CollisionShape shape) { public static Mesh getDebugMesh(CollisionShape shape) {
Mesh mesh = new Mesh(); Mesh mesh = new Mesh();
mesh = new Mesh();
DebugMeshCallback callback = new DebugMeshCallback(); 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); getVertices(shape.getObjectId(), callback);
shape.setScale(savedScale);
mesh.setBuffer(Type.Position, 3, callback.getVertices()); mesh.setBuffer(Type.Position, 3, callback.getVertices());
mesh.getFloatBuffer(Type.Position).clear(); mesh.getFloatBuffer(Type.Position).clear();
return mesh; return mesh;

@ -15,7 +15,7 @@ import java.lang.annotation.Target;
* annotations of the same name at a single location. * annotations of the same name at a single location.
* *
* Example: * 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> * <code><pre>
* &nbsp; @DefaultQualifiers({ * &nbsp; @DefaultQualifiers({
* &nbsp; @DefaultQualifier("NonNull"), * &nbsp; @DefaultQualifier("NonNull"),

@ -1,365 +1,369 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.animation; package com.jme3.animation;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import java.util.BitSet; import java.util.BitSet;
/** /**
* <code>AnimChannel</code> provides controls, such as play, pause, * <code>AnimChannel</code> provides controls, such as play, pause,
* fast forward, etc, for an animation. The animation * fast forward, etc, for an animation. The animation
* channel may influence the entire model or specific bones of the model's * channel may influence the entire model or specific bones of the model's
* skeleton. A single model may have multiple animation channels influencing * skeleton. A single model may have multiple animation channels influencing
* various parts of its body. For example, a character model may have an * various parts of its body. For example, a character model may have an
* animation channel for its feet, and another for its torso, and * animation channel for its feet, and another for its torso, and
* the animations for each channel are controlled independently. * the animations for each channel are controlled independently.
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public final class AnimChannel { public final class AnimChannel {
private static final float DEFAULT_BLEND_TIME = 0.15f; private static final float DEFAULT_BLEND_TIME = 0.15f;
private AnimControl control; private AnimControl control;
private BitSet affectedBones; private BitSet affectedBones;
private Animation animation; private Animation animation;
private Animation blendFrom; private Animation blendFrom;
private float time; private float time;
private float speed; private float speed;
private float timeBlendFrom; private float timeBlendFrom;
private float blendTime; private float blendTime;
private float speedBlendFrom; private float speedBlendFrom;
private boolean notified=false; private boolean notified=false;
private LoopMode loopMode, loopModeBlendFrom; private LoopMode loopMode, loopModeBlendFrom;
private float blendAmount = 1f; private float blendAmount = 1f;
private float blendRate = 0; private float blendRate = 0;
AnimChannel(AnimControl control){ public AnimChannel(){
this.control = control;
} }
/** public AnimChannel(AnimControl control){
* Returns the parent control of this AnimChannel. this.control = control;
* }
* @return the parent control of this AnimChannel.
* @see AnimControl /**
*/ * Returns the parent control of this AnimChannel.
public AnimControl getControl() { *
return control; * @return the parent control of this AnimChannel.
} * @see AnimControl
*/
/** public AnimControl getControl() {
* @return The name of the currently playing animation, or null if return control;
* none is assigned. }
*
* @see AnimChannel#setAnim(java.lang.String) /**
*/ * @return The name of the currently playing animation, or null if
public String getAnimationName() { * none is assigned.
return animation != null ? animation.getName() : null; *
} * @see AnimChannel#setAnim(java.lang.String)
*/
/** public String getAnimationName() {
* @return The loop mode currently set for the animation. The loop mode return animation != null ? animation.getName() : null;
* determines what will happen to the animation once it finishes }
* playing.
* /**
* For more information, see the LoopMode enum class. * @return The loop mode currently set for the animation. The loop mode
* @see LoopMode * determines what will happen to the animation once it finishes
* @see AnimChannel#setLoopMode(com.jme3.animation.LoopMode) * playing.
*/ *
public LoopMode getLoopMode() { * For more information, see the LoopMode enum class.
return loopMode; * @see LoopMode
} * @see AnimChannel#setLoopMode(com.jme3.animation.LoopMode)
*/
/** public LoopMode getLoopMode() {
* @param loopMode Set the loop mode for the channel. The loop mode return loopMode;
* determines what will happen to the animation once it finishes }
* playing.
* /**
* For more information, see the LoopMode enum class. * @param loopMode Set the loop mode for the channel. The loop mode
* @see LoopMode * determines what will happen to the animation once it finishes
*/ * playing.
public void setLoopMode(LoopMode loopMode) { *
this.loopMode = loopMode; * For more information, see the LoopMode enum class.
} * @see LoopMode
*/
/** public void setLoopMode(LoopMode loopMode) {
* @return The speed that is assigned to the animation channel. The speed this.loopMode = loopMode;
* is a scale value starting from 0.0, at 1.0 the animation will play }
* at its default speed.
* /**
* @see AnimChannel#setSpeed(float) * @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
public float getSpeed() { * at its default speed.
return speed; *
} * @see AnimChannel#setSpeed(float)
*/
/** public float getSpeed() {
* @param speed Set the speed of the animation channel. The speed return 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) { * @param speed Set the speed of the animation channel. The speed
this.speed = speed; * is a scale value starting from 0.0, at 1.0 the animation will play
if(blendTime>0){ * at its default speed.
this.speedBlendFrom = speed; */
blendTime = Math.min(blendTime, animation.getLength() / speed); public void setSpeed(float speed) {
blendRate = 1/ blendTime; 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) /**
*/ * @return The time of the currently playing animation. The time
public float getTime() { * starts at 0 and continues on until getAnimMaxTime().
return time; *
} * @see AnimChannel#setTime(float)
*/
/** public float getTime() {
* @param time Set the time of the currently playing animation, the time return time;
* is clamped from 0 to {@link #getAnimMaxTime()}. }
*/
public void setTime(float time) { /**
this.time = FastMath.clamp(time, 0, getAnimMaxTime()); * @param time Set the time of the currently playing animation, the time
} * is clamped from 0 to {@link #getAnimMaxTime()}.
*/
/** public void setTime(float time) {
* @return The length of the currently playing animation, or zero this.time = FastMath.clamp(time, 0, getAnimMaxTime());
* if no animation is playing. }
*
* @see AnimChannel#getTime() /**
*/ * @return The length of the currently playing animation, or zero
public float getAnimMaxTime(){ * if no animation is playing.
return animation != null ? animation.getLength() : 0f; *
} * @see AnimChannel#getTime()
*/
/** public float getAnimMaxTime(){
* Set the current animation that is played by this AnimChannel. return animation != null ? animation.getLength() : 0f;
* <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. * Set the current animation that is played by this AnimChannel.
* * <p>
* @param name The name of the animation to play * This resets the time to zero, and optionally blends the animation
* @param blendTime The blend time over which to blend the new animation * over <code>blendTime</code> seconds with the currently playing animation.
* with the old one. If zero, then no blending will occur and the new * Notice that this method will reset the control's speed to 1.0.
* animation will be applied instantly. *
*/ * @param name The name of the animation to play
public void setAnim(String name, float blendTime){ * @param blendTime The blend time over which to blend the new animation
if (name == null) * with the old one. If zero, then no blending will occur and the new
throw new IllegalArgumentException("name cannot be null"); * animation will be applied instantly.
*/
if (blendTime < 0f) public void setAnim(String name, float blendTime){
throw new IllegalArgumentException("blendTime cannot be less than zero"); if (name == null)
throw new IllegalArgumentException("name cannot be null");
Animation anim = control.animationMap.get(name);
if (anim == null) if (blendTime < 0f)
throw new IllegalArgumentException("Cannot find animation named: '"+name+"'"); throw new IllegalArgumentException("blendTime cannot be less than zero");
control.notifyAnimChange(this, name); Animation anim = control.animationMap.get(name);
if (anim == null)
if (animation != null && blendTime > 0f){ throw new IllegalArgumentException("Cannot find animation named: '"+name+"'");
this.blendTime = blendTime;
// activate blending control.notifyAnimChange(this, name);
blendTime = Math.min(blendTime, anim.getLength() / speed);
blendFrom = animation; if (animation != null && blendTime > 0f){
timeBlendFrom = time; this.blendTime = blendTime;
speedBlendFrom = speed; // activate blending
loopModeBlendFrom = loopMode; blendTime = Math.min(blendTime, anim.getLength() / speed);
blendAmount = 0f; blendFrom = animation;
blendRate = 1f / blendTime; timeBlendFrom = time;
}else{ speedBlendFrom = speed;
blendFrom = null; loopModeBlendFrom = loopMode;
} blendAmount = 0f;
blendRate = 1f / blendTime;
animation = anim; }else{
time = 0; blendFrom = null;
speed = 1f; }
loopMode = LoopMode.Loop;
notified = false; animation = anim;
} time = 0;
speed = 1f;
/** loopMode = LoopMode.Loop;
* Set the current animation that is played by this AnimChannel. notified = false;
* <p> }
* See {@link #setAnim(java.lang.String, float)}.
* The blendTime argument by default is 150 milliseconds. /**
* * Set the current animation that is played by this AnimChannel.
* @param name The name of the animation to play * <p>
*/ * See {@link #setAnim(java.lang.String, float)}.
public void setAnim(String name){ * The blendTime argument by default is 150 milliseconds.
setAnim(name, DEFAULT_BLEND_TIME); *
} * @param name The name of the animation to play
*/
/** public void setAnim(String name){
* Add all the bones of the model's skeleton to be setAnim(name, DEFAULT_BLEND_TIME);
* influenced by this animation channel. }
*/
public void addAllBones() { /**
affectedBones = null; * Add all the bones of the model's skeleton to be
} * influenced by this animation channel.
*/
/** public void addAllBones() {
* Add a single bone to be influenced by this animation channel. affectedBones = null;
*/ }
public void addBone(String name) {
addBone(control.getSkeleton().getBone(name)); /**
} * Add a single bone to be influenced by this animation channel.
*/
/** public void addBone(String name) {
* Add a single bone to be influenced by this animation channel. addBone(control.getSkeleton().getBone(name));
*/ }
public void addBone(Bone bone) {
int boneIndex = control.getSkeleton().getBoneIndex(bone); /**
if(affectedBones == null) { * Add a single bone to be influenced by this animation channel.
affectedBones = new BitSet(control.getSkeleton().getBoneCount()); */
} public void addBone(Bone bone) {
affectedBones.set(boneIndex); int boneIndex = control.getSkeleton().getBoneIndex(bone);
} if(affectedBones == null) {
affectedBones = new BitSet(control.getSkeleton().getBoneCount());
/** }
* Add bones to be influenced by this animation channel starting from the affectedBones.set(boneIndex);
* 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 name and going toward the root bone.
*/
/** public void addToRootBone(String name) {
* Add bones to be influenced by this animation channel starting from the addToRootBone(control.getSkeleton().getBone(name));
* given bone and going toward the root bone. }
*/
public void addToRootBone(Bone bone) { /**
addBone(bone); * Add bones to be influenced by this animation channel starting from the
while (bone.getParent() != null) { * given bone and going toward the root bone.
bone = bone.getParent(); */
addBone(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 named bone and going toward its children.
*/
/** public void addFromRootBone(String name) {
* Add bones to be influenced by this animation channel, starting addFromRootBone(control.getSkeleton().getBone(name));
* from the given bone and going toward its children. }
*/
public void addFromRootBone(Bone bone) { /**
addBone(bone); * Add bones to be influenced by this animation channel, starting
if (bone.getChildren() == null) * from the given bone and going toward its children.
return; */
for (Bone childBone : bone.getChildren()) { public void addFromRootBone(Bone bone) {
addBone(childBone); addBone(bone);
addFromRootBone(childBone); if (bone.getChildren() == null)
} return;
} for (Bone childBone : bone.getChildren()) {
addBone(childBone);
BitSet getAffectedBones(){ addFromRootBone(childBone);
return affectedBones; }
} }
public void reset(boolean rewind){ BitSet getAffectedBones(){
if(rewind){ return affectedBones;
setTime(0); }
if(control.getSkeleton()!=null){
control.getSkeleton().resetAndUpdate(); public void reset(boolean rewind){
}else{ if(rewind){
TempVars vars = TempVars.get(); setTime(0);
update(0, vars); if(control.getSkeleton()!=null){
vars.release(); control.getSkeleton().resetAndUpdate();
} }else{
} TempVars vars = TempVars.get();
animation = null; update(0, vars);
notified = false; vars.release();
} }
}
void update(float tpf, TempVars vars) { animation = null;
if (animation == null) notified = false;
return; }
if (blendFrom != null && blendAmount != 1.0f){ void update(float tpf, TempVars vars) {
// The blendFrom anim is set, the actual animation if (animation == null)
// playing will be set return;
// blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars); if (blendFrom != null && blendAmount != 1.0f){
// The blendFrom anim is set, the actual animation
timeBlendFrom += tpf * speedBlendFrom; // playing will be set
timeBlendFrom = AnimationUtils.clampWrapTime(timeBlendFrom, // blendFrom.setTime(timeBlendFrom, 1f, control, this, vars);
blendFrom.getLength(), blendFrom.setTime(timeBlendFrom, 1f - blendAmount, control, this, vars);
loopModeBlendFrom);
if (timeBlendFrom < 0){ timeBlendFrom += tpf * speedBlendFrom;
timeBlendFrom = -timeBlendFrom; timeBlendFrom = AnimationUtils.clampWrapTime(timeBlendFrom,
speedBlendFrom = -speedBlendFrom; blendFrom.getLength(),
} loopModeBlendFrom);
if (timeBlendFrom < 0){
blendAmount += tpf * blendRate; timeBlendFrom = -timeBlendFrom;
if (blendAmount > 1f){ speedBlendFrom = -speedBlendFrom;
blendAmount = 1f; }
blendFrom = null;
} blendAmount += tpf * blendRate;
} if (blendAmount > 1f){
blendAmount = 1f;
animation.setTime(time, blendAmount, control, this, vars); blendFrom = null;
time += tpf * speed; }
if (animation.getLength() > 0){ }
if (!notified && (time >= animation.getLength() || time < 0)) {
if (loopMode == LoopMode.DontLoop) { animation.setTime(time, blendAmount, control, this, vars);
// Note that this flag has to be set before calling the notify time += tpf * speed;
// since the notify may start a new animation and then unset if (animation.getLength() > 0){
// the flag. if (!notified && (time >= animation.getLength() || time < 0)) {
notified = true; if (loopMode == LoopMode.DontLoop) {
} // Note that this flag has to be set before calling the notify
control.notifyAnimCycleDone(this, animation.getName()); // since the notify may start a new animation and then unset
} // the flag.
} notified = true;
time = AnimationUtils.clampWrapTime(time, animation.getLength(), loopMode); }
if (time < 0){ control.notifyAnimCycleDone(this, animation.getName());
// Negative time indicates that speed should be inverted }
// (for cycle loop mode only) }
time = -time; time = AnimationUtils.clampWrapTime(time, animation.getLength(), loopMode);
speed = -speed; 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -34,19 +34,16 @@ package com.jme3.animation;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Mesh;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl; 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.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.TempVars;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
/** /**
* <code>AnimControl</code> is a Spatial control that allows manipulation * <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() { 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 @Override
public Object jmeClone() { public Object jmeClone() {
AnimControl clone = (AnimControl) super.jmeClone(); AnimControl clone = (AnimControl) super.jmeClone();

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2017 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,15 +32,15 @@
package com.jme3.animation; package com.jme3.animation;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.material.MatParamOverride;
import com.jme3.math.*; import com.jme3.math.*;
import com.jme3.scene.Geometry; import com.jme3.scene.*;
import com.jme3.scene.Mesh; import com.jme3.shader.VarType;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.util.SafeArrayList; import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; 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() { public final void update() {
this.updateModelTransforms(); 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() { final void reset() {
if (!userControl) { if (!userControl) {
@ -677,7 +677,7 @@ public final class Bone implements Savable, JmeCloneable {
modelPos.set(translation); modelPos.set(translation);
modelRot.set(rotation); 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){ if(attachNode != null){
attachNode.setLocalTranslation(translation); attachNode.setLocalTranslation(translation);
attachNode.setLocalRotation(rotation); attachNode.setLocalRotation(rotation);
@ -723,6 +723,8 @@ public final class Bone implements Savable, JmeCloneable {
if (attachNode == null) { if (attachNode == null) {
attachNode = new Node(name + "_attachnode"); attachNode = new Node(name + "_attachnode");
attachNode.setUserData("AttachedBone", this); 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; return attachNode;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,6 +35,8 @@ import com.jme3.export.*;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.BitSet; import java.util.BitSet;
@ -43,10 +45,10 @@ import java.util.BitSet;
* *
* @author Kirill Vainer * @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; private int targetBoneIndex;
@ -138,16 +140,23 @@ public final class BoneTrack implements Track {
/** /**
* Set the translations and rotations for this bone 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 times the time of each frame, measured from the start of the track
* @param rotations the rotation of the bone for each frame * (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) { public void setKeyframes(float[] times, Vector3f[] translations, Quaternion[] rotations) {
if (times.length == 0) { if (times.length == 0) {
throw new RuntimeException("BoneTrack with no keyframes!"); 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.times = times;
this.translations = new CompactVector3Array(); this.translations = new CompactVector3Array();
@ -160,15 +169,19 @@ public final class BoneTrack implements Track {
/** /**
* Set the translations, rotations and scales for this bone 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 times the time of each frame, measured from the start of the track
* @param rotations the rotation of the bone for each frame * (not null, length&gt;0)
* @param scales the scale of the bone for each frame * @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) { public void setKeyframes(float[] times, Vector3f[] translations, Quaternion[] rotations, Vector3f[] scales) {
this.setKeyframes(times, translations, rotations); this.setKeyframes(times, translations, rotations);
assert times.length == scales.length;
if (scales != null) { if (scales != null) {
assert times.length == scales.length;
this.scales = new CompactVector3Array(); this.scales = new CompactVector3Array();
this.scales.add(scales); this.scales.add(scales);
this.scales.freeze(); this.scales.freeze();
@ -261,33 +274,48 @@ public final class BoneTrack implements Track {
public float[] getKeyFrameTimes() { public float[] getKeyFrameTimes() {
return times; return times;
} }
/** /**
* This method creates a clone of the current object. * Create a deep clone of this track.
* @return a clone of the current object *
* @return a new track
*/ */
@Override @Override
public BoneTrack clone() { public BoneTrack clone() {
int tablesLength = times.length; return Cloner.deepClone(this);
}
float[] times = this.times.clone();
Vector3f[] sourceTranslations = this.getTranslations();
Quaternion[] sourceRotations = this.getRotations();
Vector3f[] sourceScales = this.getScales();
Vector3f[] translations = new Vector3f[tablesLength]; /**
Quaternion[] rotations = new Quaternion[tablesLength]; * Create a shallow clone for the JME cloner.
Vector3f[] scales = new Vector3f[tablesLength]; *
for (int i = 0; i < tablesLength; ++i) { * @return a new track
translations[i] = sourceTranslations[i].clone(); */
rotations[i] = sourceRotations[i].clone(); @Override
scales[i] = sourceScales != null ? sourceScales[i].clone() : new Vector3f(1.0f, 1.0f, 1.0f); 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 @Override
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,6 +31,8 @@
*/ */
package com.jme3.animation; package com.jme3.animation;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -40,7 +42,7 @@ import java.util.Map;
* @author Lim, YongHoon * @author Lim, YongHoon
* @param <T> * @param <T>
*/ */
public abstract class CompactArray<T> { public abstract class CompactArray<T> implements JmeCloneable {
private Map<T, Integer> indexPool = new HashMap<T, Integer>(); private Map<T, Integer> indexPool = new HashMap<T, Integer>();
protected int[] index; protected int[] index;
@ -68,6 +70,7 @@ public abstract class CompactArray<T> {
* They are serialized automatically when get() method is called. * They are serialized automatically when get() method is called.
* @param objArray * @param objArray
*/ */
@SuppressWarnings("unchecked")
public void add(T... objArray) { public void add(T... objArray) {
if (objArray == null || objArray.length == 0) { if (objArray == null || objArray.length == 0) {
return; 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 * @param objArray
* @return * @return
*/ */
@SuppressWarnings("unchecked")
public final int[] getIndex(T... objArray) { public final int[] getIndex(T... objArray) {
int[] index = new int[objArray.length]; int[] index = new int[objArray.length];
for (int i = 0; i < index.length; i++) { for (int i = 0; i < index.length; i++) {
@ -228,6 +232,7 @@ public abstract class CompactArray<T> {
* decompress and return object array * decompress and return object array
* @return decompress and return object array * @return decompress and return object array
*/ */
@SuppressWarnings("unchecked")
public final T[] toObjectArray() { public final T[] toObjectArray() {
try { try {
T[] compactArr = (T[]) Array.newInstance(getElementClass(), getSerializedSize() / getTupleSize()); 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 * serialize object
* @param compactIndex compacted object index * @param compactIndex compacted object index

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -42,18 +42,16 @@ import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint; import com.jme3.scene.Spatial.CullHint;
import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* EffectTrack is a track to add to an existing animation, to emit particles * EffectTrack is a track to add to an existing animation, to emit particles
* during animations for example : exhausts, dust raised by foot steps, shock * during animations for example: exhaust, dust raised by footsteps, shock
* waves, lightnings etc... * waves, lightning, etc...
* *
* usage is * usage is
* <pre> * <pre>
@ -62,9 +60,9 @@ import java.util.logging.Logger;
* control.getAnim("TheAnim").addTrack(track); * control.getAnim("TheAnim").addTrack(track);
* </pre> * </pre>
* *
* if the emitter has emits 0 particles per seconds emmitAllPArticles will be * if the emitter emits 0 particles per second, emitAllPArticles will be
* called on it at time 0 + startOffset. if it he it has more it will start * called on it at time 0 + startOffset. if it has more it will start
* emit normally at time 0 + startOffset. * emitting normally at time 0 + startOffset.
* *
* *
* @author Nehon * @author Nehon
@ -132,19 +130,6 @@ public class EffectTrack implements ClonableTrack {
@Override @Override
protected void controlRender(RenderManager rm, ViewPort vp) { 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. //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()); control.addListener(new OnEndListener());
initialized = true; initialized = true;
} }
//checking fo time to trigger the effect //checking for time to trigger the effect
if (!emitted && time >= startOffset) { if (!emitted && time >= startOffset) {
emitted = true; emitted = true;
emitter.setCullHint(CullHint.Dynamic); emitter.setCullHint(CullHint.Dynamic);
@ -430,7 +415,7 @@ public class EffectTrack implements ClonableTrack {
*/ */
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule out = ex.getCapsule(this); 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); emitter.setParticlesPerSec(particlesPerSeconds);
out.write(emitter, "emitter", null); out.write(emitter, "emitter", null);
out.write(particlesPerSeconds, "particlesPerSeconds", 0); out.write(particlesPerSeconds, "particlesPerSeconds", 0);
@ -449,7 +434,7 @@ public class EffectTrack implements ClonableTrack {
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
InputCapsule in = im.getCapsule(this); InputCapsule in = im.getCapsule(this);
this.particlesPerSeconds = in.readFloat("particlesPerSeconds", 0); 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. //This also avoid null pointer exception if the model is not loaded via the AssetManager.
emitter = (ParticleEmitter) in.readSavable("emitter", null); emitter = (ParticleEmitter) in.readSavable("emitter", null);
emitter.setParticlesPerSec(0); emitter.setParticlesPerSec(0);

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -53,7 +53,7 @@ public final class Skeleton implements Savable, JmeCloneable {
private Bone[] boneList; 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. * will cause it to go to the animated position.
*/ */
private transient Matrix4f[] skinningMatrixes; 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() { public void setBindingPose() {
for (int i = rootBones.length - 1; i >= 0; i--) { for (int i = rootBones.length - 1; i >= 0; i--) {
@ -304,6 +304,7 @@ public final class Skeleton implements Savable, JmeCloneable {
createSkinningMatrices(); createSkinningMatrices();
for (Bone rootBone : rootBones) { for (Bone rootBone : rootBones) {
rootBone.reset();
rootBone.update(); rootBone.update();
rootBone.setBindingPose(); rootBone.setBindingPose();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2017 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,21 +35,18 @@ import com.jme3.export.*;
import com.jme3.material.MatParamOverride; import com.jme3.material.MatParamOverride;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Matrix4f; import com.jme3.math.Matrix4f;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.*;
import com.jme3.renderer.RendererException;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.*; import com.jme3.scene.*;
import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.scene.mesh.IndexBuffer; import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.shader.VarType; 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.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -145,6 +142,12 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
} }
private boolean testHardwareSupported(RenderManager rm) { private boolean testHardwareSupported(RenderManager rm) {
//Only 255 bones max supported with hardware skinning
if (skeleton.getBoneCount() > 255) {
return false;
}
switchToHardware(); switchToHardware();
try { try {
@ -158,7 +161,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
/** /**
* Specifies if hardware skinning is preferred. If it is preferred and * 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. * supported by GPU, then it shall be disabled.
* *
* @param preferred * @param preferred
@ -326,7 +329,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl
bpb.clear(); bpb.clear();
bnb.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); VertexBuffer bindTangents = mesh.getBuffer(Type.BindPoseTangent);
if (bindTangents != null) { if (bindTangents != null) {
VertexBuffer tangents = mesh.getBuffer(Type.Tangent); 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 @Override
public Object jmeClone() { public Object jmeClone() {
return super.jmeClone(); return super.jmeClone();

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,16 +41,14 @@ import com.jme3.scene.Spatial;
import com.jme3.util.TempVars; import com.jme3.util.TempVars;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
/** /**
* This class represents the track for spatial animation. * This class represents the track for spatial animation.
* *
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
public class SpatialTrack implements Track, JmeCloneable { public class SpatialTrack implements JmeCloneable, Track {
/** /**
* Translations of the 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]; return times == null ? 0 : times[times.length - 1] - times[0];
} }
/**
* Create a clone with the same track spatial.
*
* @return a new track
*/
@Override @Override
public Track clone() { public SpatialTrack clone() {
return (Track) jmeClone(); Cloner cloner = new Cloner();
cloner.setClonedValue(trackSpatial, trackSpatial);
return cloner.clone(this);
} }
@Override @Override
@ -268,24 +273,38 @@ public class SpatialTrack implements Track, JmeCloneable {
return trackSpatial; return trackSpatial;
} }
/**
* Create a shallow clone for the JME cloner.
*
* @return a new track
*/
@Override @Override
public Object jmeClone() { public SpatialTrack jmeClone() {
int tablesLength = times.length; try {
return (SpatialTrack) super.clone();
float[] timesCopy = this.times.clone(); } catch (CloneNotSupportedException exception) {
Vector3f[] translationsCopy = this.getTranslations() == null ? null : Arrays.copyOf(this.getTranslations(), tablesLength); throw new RuntimeException("Can't clone track", exception);
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);
} }
/**
* 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 @Override
public void cloneFields(Cloner cloner, Object original) { 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 @Override
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -44,9 +44,9 @@ public interface Track extends Savable, Cloneable {
* given parameters. * given parameters.
* *
* @param time The time in the animation * @param time The time in the animation
* @param weight The weight from 0 to 1 on how much to apply the track * @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 control The control which the track should affect
* @param channel The channel which the track should effect * @param channel The channel which the track should affect
*/ */
public void setTime(float time, float weight, AnimControl control, AnimChannel channel, TempVars vars); 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 dimmedOrange = ColorRGBA.Orange.mult(0.7f);
private ColorRGBA dimmedRed = ColorRGBA.Red.mult(0.7f); private ColorRGBA dimmedRed = ColorRGBA.Red.mult(0.7f);
private ProfilerInputListener inputListener = new ProfilerInputListener();
public DetailedProfilerState() { public DetailedProfilerState() {
} }
@ -119,23 +121,17 @@ public class DetailedProfilerState extends BaseAppState {
if (inputManager != null) { if (inputManager != null) {
inputManager.addMapping(TOGGLE_KEY, new KeyTrigger(KeyInput.KEY_F6)); inputManager.addMapping(TOGGLE_KEY, new KeyTrigger(KeyInput.KEY_F6));
inputManager.addMapping(CLICK_KEY, new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); inputManager.addMapping(CLICK_KEY, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(new ActionListener() { inputManager.addListener(inputListener, TOGGLE_KEY, CLICK_KEY);
@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);
} }
} }
@Override @Override
protected void cleanup(Application app) { protected void cleanup(Application app) {
ui.detachAllChildren();
InputManager manager = getApplication().getInputManager();
manager.deleteMapping(TOGGLE_KEY);
manager.deleteMapping(CLICK_KEY);
manager.removeListener(inputListener);
} }
@Override @Override
@ -441,8 +437,18 @@ public class DetailedProfilerState extends BaseAppState {
public String toString() { public String toString() {
return label.getText() + " - " + df.format(getMsFromNs(cpuValue)) + "ms / " + df.format(getMsFromNs(gpuValue)) + "ms"; 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -117,11 +117,12 @@ public class StatsView extends Node implements Control, JmeCloneable {
//statistics.clearFrame(); //statistics.clearFrame();
} }
@Deprecated
@Override @Override
public Control cloneForSpatial(Spatial spatial) { public Control cloneForSpatial(Spatial spatial) {
return (Control) spatial; throw new UnsupportedOperationException();
} }
@Override @Override
public StatsView jmeClone() { public StatsView jmeClone() {
throw new UnsupportedOperationException("Not yet implemented."); throw new UnsupportedOperationException("Not yet implemented.");

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

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

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

@ -112,11 +112,10 @@ public class WeakRefCloneAssetCache implements AssetCache {
// might not even have this asset anymore, it is OK. // might not even have this asset anymore, it is OK.
if (smartCache.remove(key) != null){ if (smartCache.remove(key) != null){
removedAssets ++; removedAssets ++;
//System.out.println("WeakRefAssetCache: The asset " + ref.assetKey + " was purged from the cache");
} }
} }
if (removedAssets >= 1) { 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -221,7 +221,7 @@ public class AudioNode extends Node implements AudioSource {
/** /**
* Start playing an instance of this audio. This method can be used * Start playing an instance of this audio. This method can be used
* to play the same <code>AudioNode</code> multiple times. Note * 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. * instances already playing.
*/ */
public void playInstance(){ 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, * the dry filter will only influence the "dry" portion of the audio,
* e.g. not the reverberated parts of the AudioNode playing. * e.g. not the reverberated parts of the AudioNode playing.
* *
* See the relevent documentation for the {@link Filter} to determine * See the relevant documentation for the {@link Filter} to determine the
* the effect. * effect.
* *
* @param dryFilter The filter to set, or null to disable dry filter. * @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. * 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". * audio nodes. Set to false if the audio node should play in "headspace".
* *
* @param positional True if the audio node should be positional, otherwise * @param positional True if the audio node should be positional, otherwise

@ -12,37 +12,37 @@ public interface AL {
/** /**
* Boolean False. * Boolean False.
*/ */
static final int AL_FALSE = 0; public static final int AL_FALSE = 0;
/** /**
* Boolean True. * Boolean True.
*/ */
static final int AL_TRUE = 1; public static final int AL_TRUE = 1;
/* "no distance model" or "no buffer" */ /* "no distance model" or "no buffer" */
static final int AL_NONE = 0; public static final int AL_NONE = 0;
/** /**
* Indicate Source has relative coordinates. * 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: * Directional source, inner cone angle, in degrees. Range: [0-360] Default:
* 360 * 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: * Directional source, outer cone angle, in degrees. Range: [0-360] Default:
* 360 * 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 * 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 * 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 * coordinate system, flip the sign on the Z coordinate. Listener position
* is always in the world coordinate system. * is always in the world coordinate system.
*/ */
static final int AL_POSITION = 0x1004; public static final int AL_POSITION = 0x1004;
/** /**
* Specify the current direction. * 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. * 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, * Indicate whether source is looping. Type: ALboolean? Range: [AL_TRUE,
* AL_FALSE] Default: FALSE. * 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 * Indicate the buffer to provide sound samples. Type: ALuint. Range: any
* valid Buffer id. * 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: * Indicate the gain (volume amplification) applied. Type: ALfloat. Range:
* ]0.0- ] A value of 1.0 means un-attenuated/unchanged. Each division by 2 * ]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 * 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 * logarithmic scale; it is interpreted as zero volume - the channel is
* effectively disabled. * effectively disabled.
*/ */
static final int AL_GAIN = 0x100A; public static final int AL_GAIN = 0x100A;
/* /*
* Indicate minimum source attenuation * Indicate minimum source attenuation
* Type: ALfloat * Type: ALfloat
* Range: [0.0 - 1.0] * 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] * 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. * Indicate listener orientation.
* *
* at/up * at/up
*/ */
static final int AL_ORIENTATION = 0x100F; public static final int AL_ORIENTATION = 0x100F;
/** /**
* Source state information. * Source state information.
*/ */
static final int AL_SOURCE_STATE = 0x1010; public static final int AL_SOURCE_STATE = 0x1010;
static final int AL_INITIAL = 0x1011; public static final int AL_INITIAL = 0x1011;
static final int AL_PLAYING = 0x1012; public static final int AL_PLAYING = 0x1012;
static final int AL_PAUSED = 0x1013; public static final int AL_PAUSED = 0x1013;
static final int AL_STOPPED = 0x1014; public static final int AL_STOPPED = 0x1014;
/** /**
* Buffer Queue params * Buffer Queue params
*/ */
static final int AL_BUFFERS_QUEUED = 0x1015; public static final int AL_BUFFERS_QUEUED = 0x1015;
static final int AL_BUFFERS_PROCESSED = 0x1016; public static final int AL_BUFFERS_PROCESSED = 0x1016;
/** /**
* Source buffer position information * Source buffer position information
*/ */
static final int AL_SEC_OFFSET = 0x1024; public static final int AL_SEC_OFFSET = 0x1024;
static final int AL_SAMPLE_OFFSET = 0x1025; public static final int AL_SAMPLE_OFFSET = 0x1025;
static final int AL_BYTE_OFFSET = 0x1026; public static final int AL_BYTE_OFFSET = 0x1026;
/* /*
* Source type (Static, Streaming or undetermined) * 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 Streaming if one or more Buffers have been attached using alSourceQueueBuffers
* Source is undetermined when it has the NULL buffer attached * Source is undetermined when it has the NULL buffer attached
*/ */
static final int AL_SOURCE_TYPE = 0x1027; public static final int AL_SOURCE_TYPE = 0x1027;
static final int AL_STATIC = 0x1028; public static final int AL_STATIC = 0x1028;
static final int AL_STREAMING = 0x1029; public static final int AL_STREAMING = 0x1029;
static final int AL_UNDETERMINED = 0x1030; public static final int AL_UNDETERMINED = 0x1030;
/** /**
* Sound samples: format specifier. * Sound samples: format specifier.
*/ */
static final int AL_FORMAT_MONO8 = 0x1100; public static final int AL_FORMAT_MONO8 = 0x1100;
static final int AL_FORMAT_MONO16 = 0x1101; public static final int AL_FORMAT_MONO16 = 0x1101;
static final int AL_FORMAT_STEREO8 = 0x1102; public static final int AL_FORMAT_STEREO8 = 0x1102;
static final int AL_FORMAT_STEREO16 = 0x1103; public static final int AL_FORMAT_STEREO16 = 0x1103;
/** /**
* source specific reference distance Type: ALfloat Range: 0.0 - +inf * source specific reference distance Type: ALfloat Range: 0.0 - +inf
* *
* At 0.0, no distance attenuation occurs. Default is 1.0. * 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 * 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. * Directional source, outer cone gain.
* *
* Default: 0.0 Range: [0.0 - 1.0] Logarithmic * 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 * 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 * 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 * Sound samples: frequency, in units of Hertz [Hz]. This is the number of
* samples per second. Half of the sample frequency marks the maximum * samples per second. Half of the sample frequency marks the maximum
* significant frequency component. * significant frequency component.
*/ */
static final int AL_FREQUENCY = 0x2001; public static final int AL_FREQUENCY = 0x2001;
static final int AL_BITS = 0x2002; public static final int AL_BITS = 0x2002;
static final int AL_CHANNELS = 0x2003; public static final int AL_CHANNELS = 0x2003;
static final int AL_SIZE = 0x2004; public static final int AL_SIZE = 0x2004;
/** /**
* Buffer state. * Buffer state.
* *
* Not supported for public use (yet). * Not supported for public use (yet).
*/ */
static final int AL_UNUSED = 0x2010; public static final int AL_UNUSED = 0x2010;
static final int AL_PENDING = 0x2011; public static final int AL_PENDING = 0x2011;
static final int AL_PROCESSED = 0x2012; public static final int AL_PROCESSED = 0x2012;
/** /**
* Errors: No Error. * 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. * 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. * Invalid enum parameter value.
*/ */
static final int AL_INVALID_VALUE = 0xA003; public static final int AL_INVALID_VALUE = 0xA003;
/** /**
* Illegal call. * Illegal call.
*/ */
static final int AL_INVALID_OPERATION = 0xA004; public static final int AL_INVALID_OPERATION = 0xA004;
/** /**
* No mojo. * No mojo.
*/ */
static final int AL_OUT_OF_MEMORY = 0xA005; public static final int AL_OUT_OF_MEMORY = 0xA005;
/** /**
* Context strings: Vendor Name. * Context strings: Vendor Name.
*/ */
static final int AL_VENDOR = 0xB001; public static final int AL_VENDOR = 0xB001;
static final int AL_VERSION = 0xB002; public static final int AL_VERSION = 0xB002;
static final int AL_RENDERER = 0xB003; public static final int AL_RENDERER = 0xB003;
static final int AL_EXTENSIONS = 0xB004; public static final int AL_EXTENSIONS = 0xB004;
/** /**
* Global tweakage. * Global tweakage.
@ -241,56 +241,241 @@ public interface AL {
/** /**
* Doppler scale. Default 1.0 * Doppler scale. Default 1.0
*/ */
static final int AL_DOPPLER_FACTOR = 0xC000; public static final int AL_DOPPLER_FACTOR = 0xC000;
/** /**
* Tweaks speed of propagation. * 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 * 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 * Distance models
* *
* used in conjunction with DistanceModel * used in conjunction with DistanceModel
* *
* implicit: NONE, which disances distance attenuation. * implicit: NONE, which disables distance attenuation.
*/ */
static final int AL_DISTANCE_MODEL = 0xD000; public static final int AL_DISTANCE_MODEL = 0xD000;
static final int AL_INVERSE_DISTANCE = 0xD001; public static final int AL_INVERSE_DISTANCE = 0xD001;
static final int AL_INVERSE_DISTANCE_CLAMPED = 0xD002; public static final int AL_INVERSE_DISTANCE_CLAMPED = 0xD002;
static final int AL_LINEAR_DISTANCE = 0xD003; public static final int AL_LINEAR_DISTANCE = 0xD003;
static final int AL_LINEAR_DISTANCE_CLAMPED = 0xD004; public static final int AL_LINEAR_DISTANCE_CLAMPED = 0xD004;
static final int AL_EXPONENT_DISTANCE = 0xD005; public static final int AL_EXPONENT_DISTANCE = 0xD005;
static final int AL_EXPONENT_DISTANCE_CLAMPED = 0xD006; public static final int AL_EXPONENT_DISTANCE_CLAMPED = 0xD006;
//
///* Listener parameter value ranges and defaults. */ //
//#define AL_MIN_METERS_PER_UNIT FLT_MIN ///* Listener parameter value ranges and defaults. */
//#define AL_MAX_METERS_PER_UNIT FLT_MAX //#define AL_MIN_METERS_PER_UNIT FLT_MIN
//#define AL_DEFAULT_METERS_PER_UNIT (1.0f) //#define AL_MAX_METERS_PER_UNIT FLT_MAX
//#define AL_DEFAULT_METERS_PER_UNIT (1.0f)
public String alGetString(int parameter); public String alGetString(int parameter);
/**
* Requests a number of source names.
*
* @return the number of source names.
*/
public int alGenSources(); 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(); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); public void alSource3i(int source, int param, int value1, int value2, int value3);
} }

@ -7,67 +7,120 @@ public interface ALC {
/** /**
* No error * No error
*/ */
static final int ALC_NO_ERROR = 0; public static final int ALC_NO_ERROR = 0;
/** /**
* No device * No device
*/ */
static final int ALC_INVALID_DEVICE = 0xA001; public static final int ALC_INVALID_DEVICE = 0xA001;
/** /**
* invalid context ID * invalid context ID
*/ */
static final int ALC_INVALID_CONTEXT = 0xA002; public static final int ALC_INVALID_CONTEXT = 0xA002;
/** /**
* bad enum * bad enum
*/ */
static final int ALC_INVALID_ENUM = 0xA003; public static final int ALC_INVALID_ENUM = 0xA003;
/** /**
* bad value * bad value
*/ */
static final int ALC_INVALID_VALUE = 0xA004; public static final int ALC_INVALID_VALUE = 0xA004;
/** /**
* Out of memory. * 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 * The Specifier string for default device
*/ */
static final int ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004; public static final int ALC_DEFAULT_DEVICE_SPECIFIER = 0x1004;
static final int ALC_DEVICE_SPECIFIER = 0x1005; public static final int ALC_DEVICE_SPECIFIER = 0x1005;
static final int ALC_EXTENSIONS = 0x1006; public static final int ALC_EXTENSIONS = 0x1006;
static final int ALC_MAJOR_VERSION = 0x1000; public static final int ALC_MAJOR_VERSION = 0x1000;
static final int ALC_MINOR_VERSION = 0x1001; public static final int ALC_MINOR_VERSION = 0x1001;
static final int ALC_ATTRIBUTES_SIZE = 0x1002; public static final int ALC_ATTRIBUTES_SIZE = 0x1002;
static final int ALC_ALL_ATTRIBUTES = 0x1003; public static final int ALC_ALL_ATTRIBUTES = 0x1003;
/** /**
* Capture extension * Capture extension
*/ */
static final int ALC_CAPTURE_DEVICE_SPECIFIER = 0x310; public static final int ALC_CAPTURE_DEVICE_SPECIFIER = 0x310;
static final int ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311; public static final int ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER = 0x311;
static final int ALC_CAPTURE_SAMPLES = 0x312; public static final int ALC_CAPTURE_SAMPLES = 0x312;
/** /**
* ALC_ENUMERATE_ALL_EXT enums * ALC_ENUMERATE_ALL_EXT enums
*/ */
static final int ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012; public static final int ALC_DEFAULT_ALL_DEVICES_SPECIFIER = 0x1012;
static final int ALC_ALL_DEVICES_SPECIFIER = 0x1013; public static final int ALC_ALL_DEVICES_SPECIFIER = 0x1013;
//public static ALCCapabilities createCapabilities(long device); //public static ALCCapabilities createCapabilities(long device);
/**
* Creates an AL context.
*/
public void createALC(); public void createALC();
/**
* Destroys an AL context.
*/
public void destroyALC(); public void destroyALC();
/**
* Checks of creating an AL context.
*
* @return true if an AL context is created.
*/
public boolean isCreated(); 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); 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); 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); 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(); 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(); 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 * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.cinematic; package com.jme3.cinematic;
import com.jme3.cinematic.events.CinematicEvent; import com.jme3.cinematic.events.CinematicEvent;
import com.jme3.export.*; import com.jme3.export.*;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* *
* @author Nehon * @author Nehon
*/ */
public class KeyFrame implements Savable { public class KeyFrame implements Savable {
List<CinematicEvent> cinematicEvents = new ArrayList<CinematicEvent>(); public KeyFrame(){
private int index;
}
public List<CinematicEvent> getCinematicEvents() {
return cinematicEvents; List<CinematicEvent> cinematicEvents = new ArrayList<>();
} private int index;
public void setCinematicEvents(List<CinematicEvent> cinematicEvents) { public List<CinematicEvent> getCinematicEvents() {
this.cinematicEvents = cinematicEvents; return cinematicEvents;
} }
public List<CinematicEvent> trigger() { public void setCinematicEvents(List<CinematicEvent> cinematicEvents) {
for (CinematicEvent event : cinematicEvents) { this.cinematicEvents = cinematicEvents;
event.play(); }
}
return cinematicEvents; public List<CinematicEvent> trigger() {
} for (CinematicEvent event : cinematicEvents) {
event.play();
public boolean isEmpty(){ }
return cinematicEvents.isEmpty(); return cinematicEvents;
} }
public void write(JmeExporter ex) throws IOException { public boolean isEmpty(){
OutputCapsule oc = ex.getCapsule(this); return cinematicEvents.isEmpty();
oc.writeSavableArrayList((ArrayList) cinematicEvents, "cinematicEvents", null); }
oc.write(index, "index", 0);
} public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
public void read(JmeImporter im) throws IOException { oc.writeSavableArrayList((ArrayList) cinematicEvents, "cinematicEvents", null);
InputCapsule ic = im.getCapsule(this); oc.write(index, "index", 0);
cinematicEvents = ic.readSavableArrayList("cinematicEvents", null); }
index=ic.readInt("index", 0);
} public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
public int getIndex() { cinematicEvents = ic.readSavableArrayList("cinematicEvents", null);
return index; index=ic.readInt("index", 0);
} }
public void setIndex(int index) { public int getIndex() {
this.index = index; 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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 * @param wayPoint a position in world space
*/ */
public void addWayPoint(Vector3f wayPoint) { 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 * @return the length
*/ */
public float getLength() { public float getLength() {

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

@ -41,7 +41,10 @@ import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
@ -80,8 +83,9 @@ public class AnimationEvent extends AbstractCinematicEvent {
* constructors * constructors
*/ */
public AnimationEvent() { public AnimationEvent() {
super();
} }
/** /**
* creates an animation event * creates an animation event
* *
@ -90,6 +94,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
*/ */
public AnimationEvent(Spatial model, String animationName) { public AnimationEvent(Spatial model, String animationName) {
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(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) { public AnimationEvent(Spatial model, String animationName, float initialDuration) {
super(initialDuration); super(initialDuration);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
} }
@ -119,6 +125,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
super(loopMode); super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName); initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
} }
@ -134,6 +141,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode) { public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode); super(initialDuration, loopMode);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
} }
@ -149,6 +157,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, float blendTime) { public AnimationEvent(Spatial model, String animationName, float initialDuration, float blendTime) {
super(initialDuration); super(initialDuration);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.blendTime = blendTime; this.blendTime = blendTime;
} }
@ -167,6 +176,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
super(loopMode); super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName); initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.blendTime = blendTime; this.blendTime = blendTime;
} }
@ -185,6 +195,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, float blendTime) { public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, float blendTime) {
super(initialDuration, loopMode); super(initialDuration, loopMode);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.blendTime = blendTime; this.blendTime = blendTime;
} }
@ -203,6 +214,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
super(loopMode); super(loopMode);
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName); initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.channelIndex = channelIndex; this.channelIndex = channelIndex;
} }
@ -217,6 +229,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
*/ */
public AnimationEvent(Spatial model, String animationName, int channelIndex) { public AnimationEvent(Spatial model, String animationName, int channelIndex) {
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName); initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName);
this.channelIndex = channelIndex; this.channelIndex = channelIndex;
@ -233,6 +246,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
*/ */
public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex, float blendTime) { public AnimationEvent(Spatial model, String animationName, LoopMode loopMode, int channelIndex, float blendTime) {
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.loopMode = loopMode; this.loopMode = loopMode;
initialDuration = model.getControl(AnimControl.class).getAnimationLength(animationName); 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) { public AnimationEvent(Spatial model, String animationName, float initialDuration, int channelIndex) {
super(initialDuration); super(initialDuration);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.channelIndex = channelIndex; this.channelIndex = channelIndex;
} }
@ -270,6 +285,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, int channelIndex) { public AnimationEvent(Spatial model, String animationName, float initialDuration, LoopMode loopMode, int channelIndex) {
super(initialDuration, loopMode); super(initialDuration, loopMode);
this.model = model; this.model = model;
this.modelName = model.getName();
this.animationName = animationName; this.animationName = animationName;
this.channelIndex = channelIndex; this.channelIndex = channelIndex;
} }
@ -299,6 +315,18 @@ public class AnimationEvent extends AbstractCinematicEvent {
model = cinematic.getScene().getChild(modelName); model = cinematic.getScene().getChild(modelName);
} }
if (model != null) { 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(); channel = model.getControl(AnimControl.class).createChannel();
map.put(channelIndex, channel); map.put(channelIndex, channel);
} else { } else {
@ -401,6 +429,7 @@ public class AnimationEvent extends AbstractCinematicEvent {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
oc.write(model, "model", null); oc.write(model, "model", null);
oc.write(modelName, "modelName", null);
oc.write(animationName, "animationName", ""); oc.write(animationName, "animationName", "");
oc.write(blendTime, "blendTime", 0f); oc.write(blendTime, "blendTime", 0f);
oc.write(channelIndex, "channelIndex", 0); oc.write(channelIndex, "channelIndex", 0);
@ -411,9 +440,9 @@ public class AnimationEvent extends AbstractCinematicEvent {
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
super.read(im); super.read(im);
InputCapsule ic = im.getCapsule(this); InputCapsule ic = im.getCapsule(this);
if (im.getFormatVersion() == 0) { // if (im.getFormatVersion() == 0) {
modelName = ic.readString("modelName", ""); modelName = ic.readString("modelName", "");
} // }
//FIXME always the same issue, because of the clonning of assets, this won't work //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 //we have to somehow store userdata in the spatial and then recurse the
//scene sub scenegraph to find the correct instance of the model //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 * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.cinematic.events; package com.jme3.cinematic.events;
import com.jme3.animation.AnimationUtils; import com.jme3.animation.AnimationUtils;
import com.jme3.animation.LoopMode; import com.jme3.animation.LoopMode;
import com.jme3.app.Application; import com.jme3.app.Application;
import com.jme3.cinematic.Cinematic; import com.jme3.cinematic.Cinematic;
import com.jme3.cinematic.MotionPath; import com.jme3.cinematic.MotionPath;
import com.jme3.cinematic.PlayState; import com.jme3.cinematic.PlayState;
import com.jme3.export.InputCapsule; import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager; import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort; import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control; import com.jme3.scene.control.Control;
import com.jme3.util.clone.Cloner; import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable; import com.jme3.util.clone.JmeCloneable;
import java.io.IOException; 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. * 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. * You must first create a MotionPath and then create a MotionEvent to associate a spatial and the path.
* *
* @author Nehon * @author Nehon
*/ */
public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable { public class MotionEvent extends AbstractCinematicEvent implements Control, JmeCloneable {
protected Spatial spatial; protected Spatial spatial;
protected int currentWayPoint; protected int currentWayPoint;
protected float currentValue; protected float currentValue;
protected Vector3f direction = new Vector3f(); protected Vector3f direction = new Vector3f();
protected Vector3f lookAt = null; protected Vector3f lookAt = null;
protected Vector3f upVector = Vector3f.UNIT_Y; protected Vector3f upVector = Vector3f.UNIT_Y;
protected Quaternion rotation = null; protected Quaternion rotation = null;
protected Direction directionType = Direction.None; protected Direction directionType = Direction.None;
protected MotionPath path; protected MotionPath path;
private boolean isControl = true; private boolean isControl = true;
private int travelDirection = 1; private int travelDirection = 1;
/** /**
* the distance traveled by the spatial on the path * the distance traveled by the spatial on the path
*/ */
protected float traveledDistance = 0; protected float traveledDistance = 0;
/** /**
* Enum for the different type of target direction behavior. * Enum for the different type of target direction behavior.
*/ */
public enum Direction { public enum Direction {
/** /**
* The target stays in the starting direction. * The target stays in the starting direction.
*/ */
None, None,
/** /**
* The target rotates with the direction of the path. * The target rotates with the direction of the path.
*/ */
Path, Path,
/** /**
* The target rotates with the direction of the path but with the addition of a rotation. * 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. * You need to use the setRotation method when using this Direction.
*/ */
PathAndRotation, PathAndRotation,
/** /**
* The target rotates with the given rotation. * The target rotates with the given rotation.
*/ */
Rotation, Rotation,
/** /**
* The target looks at a point. * The target looks at a point.
* You need to use the setLookAt method when using this direction. * You need to use the setLookAt method when using this direction.
*/ */
LookAt LookAt
} }
/** /**
* Create MotionEvent, * Create MotionEvent,
* when using this constructor don't forget to assign spatial and path. * when using this constructor don't forget to assign spatial and path.
*/ */
public MotionEvent() { public MotionEvent() {
super(); super();
} }
/** /**
* Creates a MotionPath for the given spatial on the given motion path. * Creates a MotionPath for the given spatial on the given motion path.
* @param spatial * @param spatial
* @param path * @param path
*/ */
public MotionEvent(Spatial spatial, MotionPath path) { public MotionEvent(Spatial spatial, MotionPath path) {
super(); super();
spatial.addControl(this); spatial.addControl(this);
this.path = path; this.path = path;
} }
/** /**
* Creates a MotionPath for the given spatial on the given motion path. * Creates a MotionPath for the given spatial on the given motion path.
* @param spatial * @param spatial
* @param path * @param path
*/ */
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration) { public MotionEvent(Spatial spatial, MotionPath path, float initialDuration) {
super(initialDuration); super(initialDuration);
spatial.addControl(this); spatial.addControl(this);
this.path = path; this.path = path;
} }
/** /**
* Creates a MotionPath for the given spatial on the given motion path. * Creates a MotionPath for the given spatial on the given motion path.
* @param spatial * @param spatial
* @param path * @param path
*/ */
public MotionEvent(Spatial spatial, MotionPath path, LoopMode loopMode) { public MotionEvent(Spatial spatial, MotionPath path, LoopMode loopMode) {
super(); super();
spatial.addControl(this); spatial.addControl(this);
this.path = path; this.path = path;
this.loopMode = loopMode; this.loopMode = loopMode;
} }
/** /**
* Creates a MotionPath for the given spatial on the given motion path. * Creates a MotionPath for the given spatial on the given motion path.
* @param spatial * @param spatial
* @param path * @param path
*/ */
public MotionEvent(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) { public MotionEvent(Spatial spatial, MotionPath path, float initialDuration, LoopMode loopMode) {
super(initialDuration); super(initialDuration);
spatial.addControl(this); spatial.addControl(this);
this.path = path; this.path = path;
this.loopMode = loopMode; this.loopMode = loopMode;
} }
public void update(float tpf) { public void update(float tpf) {
if (isControl) { if (isControl) {
internalUpdate(tpf); internalUpdate(tpf);
} }
} }
@Override @Override
public void internalUpdate(float tpf) { public void internalUpdate(float tpf) {
if (playState == PlayState.Playing) { if (playState == PlayState.Playing) {
time = time + (tpf * speed); time = time + (tpf * speed);
if (loopMode == LoopMode.Loop && time < 0) { if (loopMode == LoopMode.Loop && time < 0) {
time = initialDuration; time = initialDuration;
} }
if ((time >= initialDuration || time < 0) && loopMode == LoopMode.DontLoop) { if ((time >= initialDuration || time < 0) && loopMode == LoopMode.DontLoop) {
if (time >= initialDuration) { if (time >= initialDuration) {
path.triggerWayPointReach(path.getNbWayPoints() - 1, this); path.triggerWayPointReach(path.getNbWayPoints() - 1, this);
} }
stop(); stop();
} else { } else {
time = AnimationUtils.clampWrapTime(time, initialDuration, loopMode); time = AnimationUtils.clampWrapTime(time, initialDuration, loopMode);
if(time<0){ if(time<0){
speed = - speed; speed = - speed;
time = - time; time = - time;
} }
onUpdate(tpf); onUpdate(tpf);
} }
} }
} }
@Override @Override
public void initEvent(Application app, Cinematic cinematic) { public void initEvent(Application app, Cinematic cinematic) {
super.initEvent(app, cinematic); super.initEvent(app, cinematic);
isControl = false; isControl = false;
} }
@Override @Override
public void setTime(float time) { public void setTime(float time) {
super.setTime(time); super.setTime(time);
onUpdate(0); onUpdate(0);
} }
public void onUpdate(float tpf) { public void onUpdate(float tpf) {
traveledDistance = path.interpolatePath(time, this, tpf); traveledDistance = path.interpolatePath(time, this, tpf);
computeTargetDirection(); computeTargetDirection();
} }
@Override @Override
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
super.write(ex); super.write(ex);
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
oc.write(lookAt, "lookAt", null); oc.write(lookAt, "lookAt", null);
oc.write(upVector, "upVector", Vector3f.UNIT_Y); oc.write(upVector, "upVector", Vector3f.UNIT_Y);
oc.write(rotation, "rotation", null); oc.write(rotation, "rotation", null);
oc.write(directionType, "directionType", Direction.None); oc.write(directionType, "directionType", Direction.None);
oc.write(path, "path", null); oc.write(path, "path", null);
oc.write(spatial, "spatial", null); oc.write(spatial, "spatial", null);
} }
@Override @Override
public void read(JmeImporter im) throws IOException { public void read(JmeImporter im) throws IOException {
super.read(im); super.read(im);
InputCapsule in = im.getCapsule(this); InputCapsule in = im.getCapsule(this);
lookAt = (Vector3f) in.readSavable("lookAt", null); lookAt = (Vector3f) in.readSavable("lookAt", null);
upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y); upVector = (Vector3f) in.readSavable("upVector", Vector3f.UNIT_Y);
rotation = (Quaternion) in.readSavable("rotation", null); rotation = (Quaternion) in.readSavable("rotation", null);
directionType = in.readEnum("directionType", Direction.class, Direction.None); directionType = in.readEnum("directionType", Direction.class, Direction.None);
path = (MotionPath) in.readSavable("path", null); path = (MotionPath) in.readSavable("path", null);
spatial = (Spatial) in.readSavable("spatial", null); spatial = (Spatial) in.readSavable("spatial", null);
} }
/** /**
* This method is meant to be called by the motion path only. * This method is meant to be called by the motion path only.
* @return * @return
*/ */
public boolean needsDirection() { public boolean needsDirection() {
return directionType == Direction.Path || directionType == Direction.PathAndRotation; return directionType == Direction.Path || directionType == Direction.PathAndRotation;
} }
private void computeTargetDirection() { private void computeTargetDirection() {
switch (directionType) { switch (directionType) {
case Path: case Path:
Quaternion q = new Quaternion(); Quaternion q = new Quaternion();
q.lookAt(direction, upVector); q.lookAt(direction, upVector);
spatial.setLocalRotation(q); spatial.setLocalRotation(q);
break; break;
case LookAt: case LookAt:
if (lookAt != null) { if (lookAt != null) {
spatial.lookAt(lookAt, upVector); spatial.lookAt(lookAt, upVector);
} }
break; break;
case PathAndRotation: case PathAndRotation:
if (rotation != null) { if (rotation != null) {
Quaternion q2 = new Quaternion(); Quaternion q2 = new Quaternion();
q2.lookAt(direction, upVector); q2.lookAt(direction, upVector);
q2.multLocal(rotation); q2.multLocal(rotation);
spatial.setLocalRotation(q2); spatial.setLocalRotation(q2);
} }
break; break;
case Rotation: case Rotation:
if (rotation != null) { if (rotation != null) {
spatial.setLocalRotation(rotation); spatial.setLocalRotation(rotation);
} }
break; break;
case None: case None:
break; break;
default: default:
break; break;
} }
} }
/** /**
* Clone this control for the given spatial. * Clone this control for the given spatial.
* @param spatial * @param spatial
* @return * @return
*/ */
@Override @Deprecated
public Control cloneForSpatial(Spatial spatial) { @Override
MotionEvent control = new MotionEvent(); public Control cloneForSpatial(Spatial spatial) {
control.setPath(path); throw new UnsupportedOperationException();
control.playState = playState; }
control.currentWayPoint = currentWayPoint;
control.currentValue = currentValue; @Override
control.direction = direction.clone(); public Object jmeClone() {
control.lookAt = lookAt; MotionEvent control = new MotionEvent();
control.upVector = upVector.clone(); control.path = path;
control.rotation = rotation; control.playState = playState;
control.initialDuration = initialDuration; control.currentWayPoint = currentWayPoint;
control.speed = speed; control.currentValue = currentValue;
control.loopMode = loopMode; control.direction = direction.clone();
control.directionType = directionType; control.lookAt = lookAt;
control.upVector = upVector.clone();
return control; control.rotation = rotation;
} control.initialDuration = initialDuration;
control.speed = speed;
@Override control.loopMode = loopMode;
public Object jmeClone() { control.directionType = directionType;
MotionEvent control = new MotionEvent(); control.spatial = spatial;
control.path = path;
control.playState = playState; return control;
control.currentWayPoint = currentWayPoint; }
control.currentValue = currentValue;
control.direction = direction.clone(); @Override
control.lookAt = lookAt; public void cloneFields( Cloner cloner, Object original ) {
control.upVector = upVector.clone(); this.spatial = cloner.clone(spatial);
control.rotation = rotation; }
control.initialDuration = initialDuration;
control.speed = speed; @Override
control.loopMode = loopMode; public void onPlay() {
control.directionType = directionType; traveledDistance = 0;
control.spatial = spatial; }
return control; @Override
} public void onStop() {
currentWayPoint = 0;
@Override }
public void cloneFields( Cloner cloner, Object original ) {
this.spatial = cloner.clone(spatial); @Override
} public void onPause() {
}
@Override
public void onPlay() { /**
traveledDistance = 0; * This method is meant to be called by the motion path only.
} * @return
*/
@Override public float getCurrentValue() {
public void onStop() { return currentValue;
currentWayPoint = 0; }
}
/**
@Override * This method is meant to be called by the motion path only.
public void onPause() { *
} */
public void setCurrentValue(float currentValue) {
/** this.currentValue = currentValue;
* This method is meant to be called by the motion path only. }
* @return
*/ /**
public float getCurrentValue() { * This method is meant to be called by the motion path only.
return currentValue; * @return
} */
public int getCurrentWayPoint() {
/** return currentWayPoint;
* This method is meant to be called by the motion path only. }
*
*/ /**
public void setCurrentValue(float currentValue) { * This method is meant to be called by the motion path only.
this.currentValue = currentValue; *
} */
public void setCurrentWayPoint(int currentWayPoint) {
/** this.currentWayPoint = currentWayPoint;
* This method is meant to be called by the motion path only. }
* @return
*/ /**
public int getCurrentWayPoint() { * Returns the direction the spatial is moving.
return currentWayPoint; * @return
} */
public Vector3f getDirection() {
/** return direction;
* This method is meant to be called by the motion path only. }
*
*/ /**
public void setCurrentWayPoint(int currentWayPoint) { * Sets the direction of the spatial, using the Y axis as the up vector.
this.currentWayPoint = currentWayPoint; * Use MotionEvent#setDirection((Vector3f direction,Vector3f upVector) if
} * you want a custum up vector.
* This method is used by the motion path.
/** * @param direction
* Returns the direction the spatial is moving. */
* @return public void setDirection(Vector3f direction) {
*/ setDirection(direction, Vector3f.UNIT_Y);
public Vector3f getDirection() { }
return direction;
} /**
* Sets the direction of the spatial with the given up vector.
/** * This method is used by the motion path.
* Sets the direction of the spatial, using the Y axis as the up vector. * @param direction
* Use MotionEvent#setDirection((Vector3f direction,Vector3f upVector) if * @param upVector the up vector to consider for this direction.
* you want a custum up vector. */
* This method is used by the motion path. public void setDirection(Vector3f direction,Vector3f upVector) {
* @param direction this.direction.set(direction);
*/ this.upVector.set(upVector);
public void setDirection(Vector3f direction) { }
setDirection(direction, Vector3f.UNIT_Y);
} /**
* Returns the direction type of the target.
/** * @return the direction type.
* Sets the direction of the spatial with the given up vector. */
* This method is used by the motion path. public Direction getDirectionType() {
* @param direction return directionType;
* @param upVector the up vector to consider for this direction. }
*/
public void setDirection(Vector3f direction,Vector3f upVector) { /**
this.direction.set(direction); * Sets the direction type of the target.
this.upVector.set(upVector); * On each update the direction given to the target can have different behavior.
} * See the Direction Enum for explanations.
* @param directionType the direction type.
/** */
* Returns the direction type of the target. public void setDirectionType(Direction directionType) {
* @return the direction type. this.directionType = directionType;
*/ }
public Direction getDirectionType() {
return 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.
* Sets the direction type of the target. * @param upVector the up vector.
* On each update the direction given to the target can have different behavior. */
* See the Direction Enum for explanations. public void setLookAt(Vector3f lookAt, Vector3f upVector) {
* @param directionType the direction type. this.lookAt = lookAt;
*/ this.upVector = upVector;
public void setDirectionType(Direction directionType) { }
this.directionType = directionType;
} /**
* Returns the rotation of the target.
/** * @return the rotation quaternion.
* Set the lookAt for the target. */
* This can be used only if direction Type is Direction.LookAt. public Quaternion getRotation() {
* @param lookAt the position to look at. return rotation;
* @param upVector the up vector. }
*/
public void setLookAt(Vector3f lookAt, Vector3f upVector) { /**
this.lookAt = lookAt; * Sets the rotation of the target.
this.upVector = upVector; * 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.
* Returns the rotation of the target. */
* @return the rotation quaternion. public void setRotation(Quaternion rotation) {
*/ this.rotation = rotation;
public Quaternion getRotation() { }
return rotation;
} /**
* Return the motion path this control follows.
/** * @return
* Sets the rotation of the target. */
* This can be used only if direction Type is Direction.PathAndRotation or Direction.Rotation. public MotionPath getPath() {
* With PathAndRotation the target will face the direction of the path multiplied by the given Quaternion. return path;
* With Rotation the rotation of the target will be set with the given Quaternion. }
* @param rotation the rotation quaternion.
*/ /**
public void setRotation(Quaternion rotation) { * Sets the motion path to follow.
this.rotation = rotation; * @param path
} */
public void setPath(MotionPath path) {
/** this.path = path;
* Return the motion path this control follows. }
* @return
*/ public void setEnabled(boolean enabled) {
public MotionPath getPath() { if (enabled) {
return path; play();
} } else {
pause();
/** }
* Sets the motion path to follow. }
* @param path
*/ public boolean isEnabled() {
public void setPath(MotionPath path) { return playState != PlayState.Stopped;
this.path = path; }
}
public void render(RenderManager rm, ViewPort vp) {
public void setEnabled(boolean enabled) { }
if (enabled) {
play(); public void setSpatial(Spatial spatial) {
} else { this.spatial = spatial;
pause(); }
}
} public Spatial getSpatial() {
return spatial;
public boolean isEnabled() { }
return playState != PlayState.Stopped;
} /**
* Return the distance traveled by the spatial on the path.
public void render(RenderManager rm, ViewPort vp) { * @return
} */
public float getTraveledDistance() {
public void setSpatial(Spatial spatial) { return traveledDistance;
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 * Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are * modification, are permitted provided that the following conditions are
* met: * met:
* *
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* *
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* *
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package com.jme3.cinematic.events; package com.jme3.cinematic.events;
import com.jme3.animation.LoopMode; import com.jme3.animation.LoopMode;
import com.jme3.app.Application; import com.jme3.app.Application;
import com.jme3.audio.AudioNode; import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioSource; import com.jme3.audio.AudioSource;
import com.jme3.cinematic.Cinematic; import com.jme3.cinematic.Cinematic;
import com.jme3.export.InputCapsule; import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import java.io.IOException; import java.io.IOException;
/** /**
* A sound track to be played in a cinematic. * A sound track to be played in a cinematic.
* @author Nehon * @author Nehon
*/ */
public class SoundEvent extends AbstractCinematicEvent { public class SoundEvent extends AbstractCinematicEvent {
protected String path; protected String path;
protected AudioNode audioNode; protected AudioNode audioNode;
protected boolean stream = false; protected boolean stream = false;
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
*/ */
public SoundEvent(String path) { public SoundEvent(String path) {
this.path = path; this.path = path;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed * @param stream true to make the audio data streamed
*/ */
public SoundEvent(String path, boolean stream) { public SoundEvent(String path, boolean stream) {
this(path); this(path);
this.stream = stream; this.stream = stream;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed * @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event * @param initialDuration the initial duration of the event
*/ */
public SoundEvent(String path, boolean stream, float initialDuration) { public SoundEvent(String path, boolean stream, float initialDuration) {
super(initialDuration); super(initialDuration);
this.path = path; this.path = path;
this.stream = stream; this.stream = stream;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed * @param stream true to make the audio data streamed
* @param loopMode the loopMode * @param loopMode the loopMode
* @see LoopMode * @see LoopMode
*/ */
public SoundEvent(String path, boolean stream, LoopMode loopMode) { public SoundEvent(String path, boolean stream, LoopMode loopMode) {
super(loopMode); super(loopMode);
this.path = path; this.path = path;
this.stream = stream; this.stream = stream;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param stream true to make the audio data streamed * @param stream true to make the audio data streamed
* @param initialDuration the initial duration of the event * @param initialDuration the initial duration of the event
* @param loopMode the loopMode * @param loopMode the loopMode
* @see LoopMode * @see LoopMode
*/ */
public SoundEvent(String path, boolean stream, float initialDuration, LoopMode loopMode) { public SoundEvent(String path, boolean stream, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode); super(initialDuration, loopMode);
this.path = path; this.path = path;
this.stream = stream; this.stream = stream;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event * @param initialDuration the initial duration of the event
*/ */
public SoundEvent(String path, float initialDuration) { public SoundEvent(String path, float initialDuration) {
super(initialDuration); super(initialDuration);
this.path = path; this.path = path;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param loopMode the loopMode * @param loopMode the loopMode
* @see LoopMode * @see LoopMode
*/ */
public SoundEvent(String path, LoopMode loopMode) { public SoundEvent(String path, LoopMode loopMode) {
super(loopMode); super(loopMode);
this.path = path; this.path = path;
} }
/** /**
* creates a sound track from the given resource path * creates a sound track from the given resource path
* @param path the path to an audio file (ie : "Sounds/mySound.wav") * @param path the path to an audio file (ie : "Sounds/mySound.wav")
* @param initialDuration the initial duration of the event * @param initialDuration the initial duration of the event
* @param loopMode the loopMode * @param loopMode the loopMode
* @see LoopMode * @see LoopMode
*/ */
public SoundEvent(String path, float initialDuration, LoopMode loopMode) { public SoundEvent(String path, float initialDuration, LoopMode loopMode) {
super(initialDuration, loopMode); super(initialDuration, loopMode);
this.path = path; this.path = path;
} }
/** /**
* creates a sound event * creates a sound event
* used for serialization * used for serialization
*/ */
public SoundEvent() { public SoundEvent() {
} super();
}
@Override
public void initEvent(Application app, Cinematic cinematic) { @Override
super.initEvent(app, cinematic); public void initEvent(Application app, Cinematic cinematic) {
audioNode = new AudioNode(app.getAssetManager(), path, stream); super.initEvent(app, cinematic);
audioNode.setPositional(false); audioNode = new AudioNode(app.getAssetManager(), path, stream);
setLoopMode(loopMode); audioNode.setPositional(false);
} setLoopMode(loopMode);
}
@Override
public void setTime(float time) { @Override
super.setTime(time); public void setTime(float time) {
//can occur on rewind super.setTime(time);
if (time < 0f) { //can occur on rewind
stop(); if (time < 0f) {
}else{ stop();
audioNode.setTimeOffset(time); }else{
} audioNode.setTimeOffset(time);
} }
}
@Override
public void onPlay() { @Override
audioNode.play(); public void onPlay() {
} audioNode.play();
}
@Override
public void onStop() { @Override
audioNode.stop(); public void onStop() {
audioNode.stop();
}
}
@Override
public void onPause() { @Override
audioNode.pause(); public void onPause() {
} audioNode.pause();
}
@Override
public void onUpdate(float tpf) { @Override
if (audioNode.getStatus() == AudioSource.Status.Stopped) { public void onUpdate(float tpf) {
stop(); if (audioNode.getStatus() == AudioSource.Status.Stopped) {
} stop();
} }
}
/**
* Returns the underlying audio node of this sound track /**
* @return * Returns the underlying audio node of this sound track
*/ * @return
public AudioNode getAudioNode() { */
return audioNode; public AudioNode getAudioNode() {
} return audioNode;
}
@Override
public void setLoopMode(LoopMode loopMode) { @Override
super.setLoopMode(loopMode); public void setLoopMode(LoopMode loopMode) {
super.setLoopMode(loopMode);
if (loopMode != LoopMode.DontLoop) {
audioNode.setLooping(true); if (loopMode != LoopMode.DontLoop) {
} else { audioNode.setLooping(true);
audioNode.setLooping(false); } else {
} audioNode.setLooping(false);
} }
}
@Override
public void write(JmeExporter ex) throws IOException { @Override
super.write(ex); public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); super.write(ex);
oc.write(path, "path", ""); OutputCapsule oc = ex.getCapsule(this);
oc.write(stream, "stream", false); oc.write(path, "path", "");
} oc.write(stream, "stream", false);
}
@Override
public void read(JmeImporter im) throws IOException { @Override
super.read(im); public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this); super.read(im);
path = ic.readString("path", ""); InputCapsule ic = im.getCapsule(this);
stream = ic.readBoolean("stream", false); 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -217,7 +217,7 @@ class SweepSphere implements Collidable {
float signedDistanceToPlane = triPlane.pseudoDistance(sCenter); float signedDistanceToPlane = triPlane.pseudoDistance(sCenter);
if (normalDotVelocity == 0.0f){ 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){ if (FastMath.abs(signedDistanceToPlane) >= 1.0f){
// no collision possible // no collision possible
return null; return null;

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

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -37,7 +37,7 @@ import com.jme3.scene.Mesh;
import java.util.List; 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 * (a geometry that tightly wraps the mesh). So in case of multiple meshes some vertices may appear
* in a space between them. * in a space between them.
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -40,7 +40,7 @@ import java.util.ArrayList;
import java.util.List; 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) * @author Marcin Roguski (Kaelthas)
*/ */
public class EmitterMeshFaceShape extends EmitterMeshVertexShape { public class EmitterMeshFaceShape extends EmitterMeshVertexShape {

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -50,7 +50,7 @@ import java.util.Map;
import java.util.Map.Entry; 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) * @author Marcin Roguski (Kaelthas)
*/ */
public class EmitterMeshVertexShape implements EmitterShape { 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 * @param meshes
* a list of meshes that will form the emitter's shape * a list of meshes that will form the emitter's shape
*/ */

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

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2015 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,13 +31,14 @@
*/ */
package com.jme3.environment; package com.jme3.environment;
import com.jme3.app.Application;
import com.jme3.environment.generation.*; import com.jme3.environment.generation.*;
import com.jme3.light.LightProbe;
import com.jme3.environment.util.EnvMapUtils; 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.Node;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import com.jme3.texture.TextureCubeMap; import com.jme3.texture.TextureCubeMap;
import java.util.concurrent.ScheduledThreadPoolExecutor; 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 * 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. * 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 * 1. Create an EnvironmentCamera
* 2. give it a position in the scene * 2. give it a position in the scene
* 3. call {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} * 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. * 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 * 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 * 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. * 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. * 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 process is thread safe.
* The created lightProbe will only be marked as ready when the rendering process is done. * 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. * 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 process is thread safe.
* The created lightProbe will only be marked as ready when the rendering process is done. * 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 envCam the EnvironmentCamera
* @param scene the Scene * @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 * @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(); final LightProbe probe = new LightProbe();
probe.setPosition(envCam.getPosition()); probe.setPosition(envCam.getPosition());
probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat())); probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat()));
@ -117,33 +119,37 @@ public class LightProbeFactory {
@Override @Override
public void done(TextureCubeMap map) { public void done(TextureCubeMap map) {
generatePbrMaps(map, probe, envCam.getApplication(), listener); generatePbrMaps(map, probe, envCam.getApplication(), genType, listener);
} }
}); });
return probe; return probe;
} }
/** public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) {
* Updates a LightProbe with the giver EnvironmentCamera in the given scene. return makeProbe(envCam, scene, EnvMapUtils.GenerationType.Fast, listener);
* }
* Note that this is an assynchronous process that will run on multiple threads.
/**
* 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 process is thread safe.
* The created lightProbe will only be marked as ready when the rendering process is done. * The created lightProbe will only be marked as ready when the rendering process is done.
* * <p>
* The JobProgressListener will be notified of the progress of the generation. * The JobProgressListener will be notified of the progress of the generation.
* Note that you can also use a {@link JobProgressAdapter}. * 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 LightProbe
* @see EnvironmentCamera * @see EnvironmentCamera
* @see JobProgressListener * @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()); envCam.setPosition(probe.getPosition());
@ -159,23 +165,27 @@ public class LightProbeFactory {
@Override @Override
public void done(TextureCubeMap map) { public void done(TextureCubeMap map) {
generatePbrMaps(map, probe, envCam.getApplication(), listener); generatePbrMaps(map, probe, envCam.getApplication(), genType, listener);
} }
}); });
return probe; 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. * 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). * 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 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 app the Application
* @param listener a progress listener. (can be null if no progress reporting is needed) * @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; IrradianceSphericalHarmonicsGenerator irrShGenerator;
PrefilteredEnvMapFaceGenerator[] pemGenerators = new PrefilteredEnvMapFaceGenerator[6]; PrefilteredEnvMapFaceGenerator[] pemGenerators = new PrefilteredEnvMapFaceGenerator[6];
@ -189,7 +199,7 @@ public class LightProbeFactory {
for (int i = 0; i < pemGenerators.length; i++) { for (int i = 0; i < pemGenerators.length; i++) {
pemGenerators[i] = new PrefilteredEnvMapFaceGenerator(app, i, new JobListener(listener, jobState, probe, 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]); 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> { private static class JobListener extends JobProgressAdapter<Integer> {

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2015 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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 * @param sourceMap the source cube map
* {@link EnvMapUtils.FixSeamsMethod} * {@link EnvMapUtils.FixSeamsMethod}

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2015 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -31,30 +31,22 @@
*/ */
package com.jme3.environment.generation; package com.jme3.environment.generation;
import com.jme3.app.Application;
import com.jme3.environment.util.CubeMapWrapper; import com.jme3.environment.util.CubeMapWrapper;
import com.jme3.environment.util.EnvMapUtils; import com.jme3.environment.util.EnvMapUtils;
import com.jme3.app.Application;
import com.jme3.math.*; 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 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.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger; 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 * Generates one face of the prefiltered environment map for PBR. This job can
* be lauched from a separate thread. * be launched from a separate thread.
* <p> * <p>
* TODO there is a lot of duplicate code here with the EnvMapUtils. * 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 int targetMapSize;
private EnvMapUtils.FixSeamsMethod fixSeamsMethod; private EnvMapUtils.FixSeamsMethod fixSeamsMethod;
private EnvMapUtils.GenerationType genType;
private TextureCubeMap sourceMap; private TextureCubeMap sourceMap;
private TextureCubeMap store; private TextureCubeMap store;
private final Application app; 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 sourceMap the source cube map
* @param targetMapSize the size of the generated map (width or height in * @param targetMapSize the size of the generated map (width or height in
@ -107,11 +100,12 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
* {@link EnvMapUtils.FixSeamsMethod} * {@link EnvMapUtils.FixSeamsMethod}
* @param store The cube map to store the result in. * @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.sourceMap = sourceMap;
this.targetMapSize = targetMapSize; this.targetMapSize = targetMapSize;
this.fixSeamsMethod = fixSeamsMethod; this.fixSeamsMethod = fixSeamsMethod;
this.store = store; this.store = store;
this.genType = genType;
init(); init();
} }
@ -162,68 +156,105 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
* @return The irradiance cube map for the given coefficients * @return The irradiance cube map for the given coefficients
*/ */
private TextureCubeMap generatePrefilteredEnvMap(TextureCubeMap sourceEnvMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) { 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 sourceWrapper = new CubeMapWrapper(sourceEnvMap);
CubeMapWrapper targetWrapper = new CubeMapWrapper(pem); CubeMapWrapper targetWrapper = new CubeMapWrapper(pem);
Vector3f texelVect = new Vector3f(); Vector3f texelVect = new Vector3f();
Vector3f color = new Vector3f(); Vector3f color = new Vector3f();
ColorRGBA outColor = new ColorRGBA(); ColorRGBA outColor = new ColorRGBA();
for (int mipLevel = 0; mipLevel < nbMipMap; mipLevel++) { int targetMipMapSize = targetMapSize;
float roughness = getRoughnessFromMip(mipLevel, nbMipMap); for (int mipLevel = 0; mipLevel < nbMipMap; mipLevel++) {
int nbSamples = getSampleFromMip(mipLevel, nbMipMap); float roughness = getRoughnessFromMip(mipLevel, nbMipMap);
int targetMipMapSize = (int) pow(2, nbMipMap + 1 - mipLevel); int nbSamples = getSampleFromMip(mipLevel, nbMipMap);
for (int y = 0; y < targetMipMapSize; y++) { for (int y = 0; y < targetMipMapSize; y++) {
for (int x = 0; x < targetMipMapSize; x++) { for (int x = 0; x < targetMipMapSize; x++) {
color.set(0, 0, 0); color.set(0, 0, 0);
getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, fixSeamsMethod); getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, fixSeamsMethod);
prefilterEnvMapTexel(sourceWrapper, roughness, texelVect, nbSamples, color); 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); 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);
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; Vector3f prefilteredColor = store;
float totalWeight = 0.0f; 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² // a = roughness² and a2 = a²
float a2 = roughness * roughness; float a2 = roughness * roughness;
a2 *= a2; 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++) { for (int i = 0; i < numSamples; i++) {
Xi = getHammersleyPoint(i, numSamples, Xi); Xi = getHammersleyPoint(i, numSamples, Xi);
H = importanceSampleGGX(Xi, a2, N, H); H = importanceSampleGGX(Xi, a2, H);
H.normalizeLocal(); H.normalizeLocal();
tmp.set(H); float VoH = H.z;
float NoH = N.dot(tmp); Vector3f L = H.multLocal(VoH * 2f).subtractLocal(V);
float NoL = L.z;
Vector3f L = tmp.multLocal(NoH * 2).subtractLocal(N);
float NoL = clamp(N.dot(L), 0.0f, 1.0f); float computedMipLevel = mipLevel;
if (NoL > 0) { if (mipLevel != 0) {
envMapReader.getPixel(L, c); computedMipLevel = computeMipLevel(roughness, numSamples, this.targetMapSize, VoH);
prefilteredColor.setX(prefilteredColor.x + c.r * NoL); }
prefilteredColor.setY(prefilteredColor.y + c.g * NoL);
prefilteredColor.setZ(prefilteredColor.z + c.b * NoL); toWorld(L, N, tangentX, tangentY, lWorld);
totalWeight += samplePixel(envMapReader, lWorld, NoL, computedMipLevel, prefilteredColor);
totalWeight += NoL;
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) { if (totalWeight > 0) {
prefilteredColor.divideLocal(totalWeight); prefilteredColor.divideLocal(totalWeight);
@ -232,7 +263,78 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
return prefilteredColor; 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) { if (store == null) {
store = new Vector3f(); store = new Vector3f();
} }
@ -243,22 +345,9 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress {
float sinThetaCosPhi = sinTheta * xi.z;//xi.z is cos(phi) float sinThetaCosPhi = sinTheta * xi.z;//xi.z is cos(phi)
float sinThetaSinPhi = sinTheta * xi.w;//xi.w is sin(phi) float sinThetaSinPhi = sinTheta * xi.w;//xi.w is sin(phi)
Vector3f upVector = Vector3f.UNIT_X; store.x = sinThetaCosPhi;
store.y = sinThetaSinPhi;
if (abs(normal.z) < 0.999) { store.z = cosTheta;
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);
return store; return store;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2015 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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 * @return
*/ */

@ -31,17 +31,15 @@
*/ */
package com.jme3.environment.util; package com.jme3.environment.util;
import com.jme3.environment.util.EnvMapUtils; import com.jme3.math.*;
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.texture.Image; import com.jme3.texture.Image;
import com.jme3.texture.TextureCubeMap; import com.jme3.texture.TextureCubeMap;
import com.jme3.texture.image.DefaultImageRaster; import com.jme3.texture.image.DefaultImageRaster;
import com.jme3.texture.image.MipMapImageRaster; import com.jme3.texture.image.MipMapImageRaster;
import com.jme3.util.BufferUtils; 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. * 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 Vector2f uvs = new Vector2f();
private final Image image; private final Image image;
private final ColorRGBA tmpColor = new ColorRGBA();
/** /**
* Creates a CubeMapWrapper for the given cube map * Creates a CubeMapWrapper for the given cube map
* Note that the cube map must be initialized, and the mipmaps sizes should * 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. * @param store the color in which to store the pixel color read.
* @return the color of the pixel 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) { if (mipMapRaster == null) {
throw new IllegalArgumentException("This cube map has no mip maps"); throw new IllegalArgumentException("This cube map has no mip maps");
} }
@ -113,10 +113,26 @@ public class CubeMapWrapper {
store = new ColorRGBA(); 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.setSlice(face);
mipMapRaster.setMipLevel(mipLevel); mipMapRaster.setMipLevel(lowerMipLevel);
return mipMapRaster.getPixel((int) uvs.x, (int) uvs.y, store); 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.Geometry;
import com.jme3.scene.Node; import com.jme3.scene.Node;
import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Quad;
import com.jme3.texture.Image; import com.jme3.texture.*;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.TextureCubeMap;
import com.jme3.texture.image.ColorSpace; import com.jme3.texture.image.ColorSpace;
import com.jme3.ui.Picture; import com.jme3.ui.Picture;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import com.jme3.util.TempVars;
import java.nio.ByteBuffer; 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 None
} }
public static enum GenerationType {
Fast,
HighQuality
}
/** /**
* Creates a cube map from 6 images * Creates a cube map from 6 images
* *
@ -117,6 +119,8 @@ public class EnvMapUtils {
cubeImage.addData(backImg.getData(0)); cubeImage.addData(backImg.getData(0));
cubeImage.addData(frontImg.getData(0)); cubeImage.addData(frontImg.getData(0));
cubeImage.setMipMapSizes(rightImg.getMipMapSizes());
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
cubeMap.setAnisotropicFilter(0); cubeMap.setAnisotropicFilter(0);
cubeMap.setMagFilter(Texture.MagFilter.Bilinear); cubeMap.setMagFilter(Texture.MagFilter.Bilinear);
@ -148,6 +152,8 @@ public class EnvMapUtils {
cubeImage.addData(d.duplicate()); cubeImage.addData(d.duplicate());
} }
cubeImage.setMipMapSizes(srcImg.getMipMapSizes());
TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); TextureCubeMap cubeMap = new TextureCubeMap(cubeImage);
cubeMap.setAnisotropicFilter(sourceMap.getAnisotropicFilter()); cubeMap.setAnisotropicFilter(sourceMap.getAnisotropicFilter());
cubeMap.setMagFilter(sourceMap.getMagFilter()); cubeMap.setMagFilter(sourceMap.getMagFilter());
@ -730,7 +736,7 @@ public class EnvMapUtils {
pem.setMagFilter(Texture.MagFilter.Bilinear); pem.setMagFilter(Texture.MagFilter.Bilinear);
pem.setMinFilter(Texture.MinFilter.Trilinear); pem.setMinFilter(Texture.MinFilter.Trilinear);
pem.getImage().setColorSpace(ColorSpace.Linear); 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); CubeMapWrapper targetWrapper = new CubeMapWrapper(pem);
targetWrapper.initMipMaps(nbMipMap); targetWrapper.initMipMaps(nbMipMap);
return pem; return pem;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2015 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -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 * @param scene
*/ */
public void setScene(Spatial scene) { public void setScene(Spatial scene) {

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -423,15 +423,22 @@ public class InputManager implements RawInputListener {
/** /**
* Callback from RawInputListener. Do not use. * Callback from RawInputListener. Do not use.
*
* @param evt event to add to the input queue (not null)
*/ */
@Override @Override
public void onMouseMotionEvent(MouseMotionEvent evt) { 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()); cursorPos.set(evt.getX(), evt.getY());
inputQueue.add(evt); if (eventsPermitted) {
inputQueue.add(evt);
}
} }
private void onMouseButtonEventQueued(MouseButtonEvent evt) { private void onMouseButtonEventQueued(MouseButtonEvent evt) {
@ -867,7 +874,7 @@ public class InputManager implements RawInputListener {
// larynx, 2011.06.10 - flag event as reusable because // larynx, 2011.06.10 - flag event as reusable because
// the android input uses a non-allocating ringbuffer which // the android input uses a non-allocating ringbuffer which
// needs to know when the event is not anymore in inputQueue // needs to know when the event is not anymore in inputQueue
// and therefor can be reused. // and therefore can be reused.
event.setConsumed(); event.setConsumed();
} }

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

@ -445,6 +445,16 @@ public interface KeyInput extends Input {
* (J3100). * (J3100).
*/ */
public static final int KEY_UNLABELED = 0x97; 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). * Enter key (num pad).
*/ */

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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2015 jMonkeyEngine * Copyright (c) 2009-2018 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -48,7 +48,7 @@ public interface LightProbeBlendingStrategy {
public void registerProbe(LightProbe probe); public void registerProbe(LightProbe probe);
/** /**
* Populates the resulting light probes into the given light list. * 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 * @param lightList the result light list
*/ */
public void populateProbes(Geometry g, LightList lightList); 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -54,7 +54,7 @@ import java.io.IOException;
* <p> * <p>
* In addition to a position, point lights also have a radius which * 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 * 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 { 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. * Setting a non-zero radius indicates the light should use attenuation.
* If a pixel's distance to this light's position * If a pixel's distance to this light's position
* is greater than the light's radius, then the pixel will not be * 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. * the magnitude of the influence is equal to distance / radius.
* *
* @param radius the radius of the light influence. * @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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -337,7 +337,7 @@ public class SpotLight extends Light {
* Setting a non-zero range indicates the light should use attenuation. * Setting a non-zero range indicates the light should use attenuation.
* If a pixel's distance to this light's position * If a pixel's distance to this light's position
* is greater than the light's range, then the pixel will not be * 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. * the magnitude of the influence is equal to distance / range.
* *
* @param spotRange the range of the light influence. * @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.vertexUniforms.add(uniform.clone());
} }
clone.vertexGlobal = vertexGlobal.clone(); if (vertexGlobal != null) {
clone.vertexGlobal = vertexGlobal.clone();
}
for (ShaderNodeVariable varying : varyings) { for (ShaderNodeVariable varying : varyings) {
clone.varyings.add(varying.clone()); clone.varyings.add(varying.clone());

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

Loading…
Cancel
Save