Merge remote-tracking branch 'doktharFork/sdk_scenecomposer' into sdk_scenecomposer

experimental
Dokthar 9 years ago
commit c9230d370a
  1. 15
      .gitignore
  2. 38
      .travis.yml
  3. 7
      CONTRIBUTING.md
  4. 4
      README.md
  5. 83
      build.gradle
  6. 13
      common-android-app.gradle
  7. 73
      common.gradle
  8. 5
      gradle.properties
  9. 40
      jme3-android-examples/build.gradle
  10. 20
      jme3-android-examples/src/main/AndroidManifest.xml
  11. 12
      jme3-android-examples/src/main/java/jme3test/android/TestChooserAndroid.java
  12. 6
      jme3-android-examples/src/main/res/values/strings.xml
  13. 5
      jme3-android/src/main/java/com/jme3/audio/android/AndroidMediaPlayerAudioRenderer.java
  14. 2549
      jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java
  15. 5
      jme3-blender/build.gradle
  16. 13
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/Ipo.java
  17. 4
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/Constraint.java
  18. 69
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/SimulationNode.java
  19. 6
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinition.java
  20. 12
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionFactory.java
  21. 290
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/constraints/definitions/ConstraintDefinitionIK.java
  22. 25
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/file/FileBlockHeader.java
  23. 128
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DQuaternion.java
  24. 26
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/DTransform.java
  25. 214
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/math/Matrix.java
  26. BIN
      jme3-bullet-native/libs/native/windows/x86/bulletjme.dll
  27. BIN
      jme3-bullet-native/libs/native/windows/x86_64/bulletjme.dll
  28. 57
      jme3-bullet-native/src/native/cpp/com_jme3_bullet_objects_PhysicsRigidBody.cpp
  29. 27
      jme3-bullet-native/src/native/cpp/com_jme3_bullet_objects_PhysicsRigidBody.h
  30. 4
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CapsuleCollisionShape.java
  31. 52
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsRigidBody.java
  32. 62
      jme3-core/build.gradle
  33. 1
      jme3-core/src/main/java/com/jme3/animation/Bone.java
  34. 19
      jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java
  35. 24
      jme3-core/src/main/java/com/jme3/app/StatsView.java
  36. 10
      jme3-core/src/main/java/com/jme3/audio/AudioNode.java
  37. 1
      jme3-core/src/main/java/com/jme3/audio/AudioRenderer.java
  38. 5
      jme3-core/src/main/java/com/jme3/audio/AudioSource.java
  39. 13
      jme3-core/src/main/java/com/jme3/audio/AudioStream.java
  40. 60
      jme3-core/src/main/java/com/jme3/audio/openal/ALAudioRenderer.java
  41. 4
      jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java
  42. 20
      jme3-core/src/main/java/com/jme3/cinematic/events/AnimationEvent.java
  43. 8
      jme3-core/src/main/java/com/jme3/collision/bih/BIHTree.java
  44. 8
      jme3-core/src/main/java/com/jme3/export/JmeExporter.java
  45. 6
      jme3-core/src/main/java/com/jme3/input/DefaultJoystickAxis.java
  46. 10
      jme3-core/src/main/java/com/jme3/light/AmbientLight.java
  47. 29
      jme3-core/src/main/java/com/jme3/light/DirectionalLight.java
  48. 11
      jme3-core/src/main/java/com/jme3/light/Light.java
  49. 59
      jme3-core/src/main/java/com/jme3/light/PointLight.java
  50. 110
      jme3-core/src/main/java/com/jme3/light/SpotLight.java
  51. 153
      jme3-core/src/main/java/com/jme3/material/Material.java
  52. 135
      jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
  53. 36
      jme3-core/src/main/java/com/jme3/math/ColorRGBA.java
  54. 73
      jme3-core/src/main/java/com/jme3/math/Matrix4f.java
  55. 44
      jme3-core/src/main/java/com/jme3/math/Transform.java
  56. 6
      jme3-core/src/main/java/com/jme3/post/FilterPostProcessor.java
  57. 2
      jme3-core/src/main/java/com/jme3/renderer/Limits.java
  58. 5
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
  59. 13
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL3.java
  60. 2
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL4.java
  61. 21
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormat.java
  62. 28
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java
  63. 379
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
  64. 42
      jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java
  65. 45
      jme3-core/src/main/java/com/jme3/scene/BatchNode.java
  66. 1
      jme3-core/src/main/java/com/jme3/scene/shape/AbstractBox.java
  67. 4
      jme3-core/src/main/java/com/jme3/shadow/AbstractShadowRenderer.java
  68. 2
      jme3-core/src/main/java/com/jme3/shadow/BasicShadowRenderer.java
  69. 2
      jme3-core/src/main/java/com/jme3/shadow/DirectionalLightShadowRenderer.java
  70. 2
      jme3-core/src/main/java/com/jme3/shadow/PointLightShadowRenderer.java
  71. 2
      jme3-core/src/main/java/com/jme3/shadow/PssmShadowRenderer.java
  72. 2
      jme3-core/src/main/java/com/jme3/shadow/SpotLightShadowRenderer.java
  73. 2
      jme3-core/src/main/java/com/jme3/system/AppSettings.java
  74. 9
      jme3-core/src/main/java/com/jme3/system/JmeSystem.java
  75. 5
      jme3-core/src/main/java/com/jme3/system/JmeSystemDelegate.java
  76. 66
      jme3-core/src/main/java/com/jme3/system/JmeVersion.java
  77. 8
      jme3-core/src/main/java/com/jme3/texture/Image.java
  78. 51
      jme3-core/src/main/java/com/jme3/texture/image/DefaultImageRaster.java
  79. 25
      jme3-core/src/main/java/com/jme3/texture/image/ImageRaster.java
  80. 15
      jme3-core/src/main/java/com/jme3/util/BufferUtils.java
  81. 4
      jme3-core/src/main/java/com/jme3/util/LittleEndien.java
  82. 140
      jme3-core/src/main/java/com/jme3/util/MipMapGenerator.java
  83. 6
      jme3-core/src/main/java/com/jme3/util/TangentBinormalGenerator.java
  84. 9
      jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.frag
  85. 16
      jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert
  86. 12
      jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag
  87. 18
      jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert
  88. 3
      jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTextured.j3md
  89. 2
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.frag
  90. 25
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
  91. 1
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.vert
  92. 216
      jme3-core/src/main/resources/Common/MatDefs/Misc/UnshadedNodes.j3md
  93. 5
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn
  94. 2
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/texture.frag
  95. 3
      jme3-core/src/main/resources/Common/MatDefs/ShaderNodes/Basic/texture15.frag
  96. 34
      jme3-core/src/main/resources/Common/ShaderLib/GLSLCompat.glsllib
  97. 39
      jme3-core/src/main/resources/Common/ShaderLib/MultiSample.glsllib
  98. 22
      jme3-core/src/main/resources/com/jme3/asset/Desktop.cfg
  99. 2
      jme3-core/src/main/resources/com/jme3/asset/General.cfg
  100. 11
      jme3-core/src/main/resources/com/jme3/system/version.properties
  101. Some files were not shown because too many files have changed in this diff Show More

15
.gitignore vendored

@ -4,12 +4,14 @@
/dist/ /dist/
/build/ /build/
/netbeans/ /netbeans/
/sdk/jdks/local/
/jme3-core/build/ /jme3-core/build/
/jme3-core/src/main/java/com/jme3/system/JmeVersion.java /jme3-core/src/main/resources/com/jme3/system/version.properties
/jme3-plugins/build/ /jme3-plugins/build/
/jme3-desktop/build/ /jme3-desktop/build/
/jme3-android-native/build/ /jme3-android-native/build/
/jme3-android/build/ /jme3-android/build/
/jme3-android-examples/build/
/jme3-blender/build/ /jme3-blender/build/
/jme3-effects/build/ /jme3-effects/build/
/jme3-bullet/build/ /jme3-bullet/build/
@ -79,6 +81,7 @@
/sdk/jme3-vehicle-creator/build/ /sdk/jme3-vehicle-creator/build/
/sdk/jme3-welcome-screen/build/ /sdk/jme3-welcome-screen/build/
/sdk/jme3-glsl-support/build/ /sdk/jme3-glsl-support/build/
/sdk/jme3-dark-laf/build/
/sdk/nbproject/private/ /sdk/nbproject/private/
/sdk/jme3-scenecomposer/nbproject/private/ /sdk/jme3-scenecomposer/nbproject/private/
/sdk/jme3-core/nbproject/private/ /sdk/jme3-core/nbproject/private/
@ -131,3 +134,13 @@
!/jme3-bullet-native/libs/native/osx/x86_64/libbulletjme.dylib !/jme3-bullet-native/libs/native/osx/x86_64/libbulletjme.dylib
!/jme3-bullet-native/libs/native/linux/x86/libbulletjme.so !/jme3-bullet-native/libs/native/linux/x86/libbulletjme.so
!/jme3-bullet-native/libs/native/linux/x86_64/libbulletjme.so !/jme3-bullet-native/libs/native/linux/x86_64/libbulletjme.so
/.nb-gradle/
/sdk/ant-jme/nbproject/private/
/sdk/nbi/stub/ext/engine/nbproject/private/
/sdk/nbi/stub/ext/components/products/jdk/nbproject/private/
/sdk/nbi/stub/ext/components/products/blender/nbproject/private/
/sdk/nbi/stub/ext/components/products/helloworld/nbproject/private/
/sdk/BasicGameTemplate/nbproject/private/
/sdk/nbi/stub/ext/components/products/jdk/build/
/sdk/nbi/stub/ext/components/products/jdk/dist/
/sdk/jme3-dark-laf/nbproject/private/

@ -8,15 +8,45 @@ cache:
- gradle-cache - gradle-cache
- netbeans - netbeans
branches: # branches:
only: # only:
- master # - master
notifications: notifications:
slack: slack:
secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s=" on_success: change
on_failure: always
rooms:
secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s="
install:
- ./gradlew assemble
script:
- ./gradlew check
- ./gradlew createZipDistribution
- "[ $TRAVIS_BRANCH == 'master' ] && [ $TRAVIS_PULL_REQUEST == 'false' ] && ./gradlew uploadArchives || :"
before_deploy:
- export RELEASE_DIST=$(ls build/distributions/*.zip)
deploy:
provider: releases
api_key:
secure: PuEsJd6juXBH29ByITW3ntSAyrwWs0IeFvXJ5Y2YlhojhSMtTwkoWeB6YmDJWP4fhzbajk4TQ1HlOX2IxJXSW/8ShOEIUlGXz9fHiST0dkSM+iRAUgC5enCLW5ITPTiem7eY9ZhS9miIam7ngce9jHNMh75PTzZrEJtezoALT9w=
file_glob: true
file: "${RELEASE_DIST}"
skip_cleanup: true
on:
repo: jMonkeyEngine/jmonkeyengine
tags: true
before_install: before_install:
- git fetch --unshallow
- openssl aes-256-cbc -K $encrypted_a1949b55824a_key -iv $encrypted_a1949b55824a_iv
-in private/www-updater.key.enc -out private/www-updater.key -d
# before_install:
# required libs for android build tools # required libs for android build tools
# sudo apt-get update # sudo apt-get update
# sudo apt-get install -qq p7zip-full # sudo apt-get install -qq p7zip-full

@ -16,13 +16,6 @@ When you're ready to submit your code, just make a [pull request](https://help.g
- When committing, always be sure to run an update before you commit. If there is a conflict between the latest revision and your patch after the update, then it is your responsibility to track down the update that caused the conflict and determine the issue (and fix it). In the case where the breaking commit has no thread linked (and one cannot be found in the forum), then the contributor should contact an administrator and wait for feedback before committing. - When committing, always be sure to run an update before you commit. If there is a conflict between the latest revision and your patch after the update, then it is your responsibility to track down the update that caused the conflict and determine the issue (and fix it). In the case where the breaking commit has no thread linked (and one cannot be found in the forum), then the contributor should contact an administrator and wait for feedback before committing.
- If your code is committed and it introduces new functionality, please edit the wiki accordingly. We can easily roll back to previous revisions, so just do your best; point us to it and we’ll see if it sticks! - If your code is committed and it introduces new functionality, please edit the wiki accordingly. We can easily roll back to previous revisions, so just do your best; point us to it and we’ll see if it sticks!
**Note to Eclipse users:** The Eclipse [git client does not support https](http://hub.jmonkeyengine.org/forum/topic/problem-cloning-the-new-git-repository/#post-265594). The current workaround is to use the command line to clone the repository.
To import the local repository as a project follow these steps:
1. Add a line 'apply plugin: eclipse' to your common.gradle file in the main project directory.
2. Navigate to the project directory in command line and execute command 'gradle eclipse'. This will load all the dependancies for eclipse.
3. In Eclipse, add the repository as an existing Java Project.
p.s. We will try hold ourselves to a [certain standard](http://www.defmacro.org/2013/04/03/issue-etiquette.html) when it comes to GitHub etiquette. If at any point we fail to uphold this standard, let us know. p.s. We will try hold ourselves to a [certain standard](http://www.defmacro.org/2013/04/03/issue-etiquette.html) when it comes to GitHub etiquette. If at any point we fail to uphold this standard, let us know.
#### Core Contributors #### Core Contributors

@ -1,6 +1,8 @@
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. And it is all beautifully documented. The 3.0 branch is the latest stable version of the jMonkeyEngine 3 SDK, a complete game development suite. We'll be frequently submitting stable 3.0.x updates until the major 3.1 version arrives. jMonkeyEngine is a 3D game engine for adventurous Java developers. It’s open source, cross platform and cutting edge. And it is all beautifully documented. The 3.0 branch is the latest stable version of the jMonkeyEngine 3 SDK, a complete game development suite. We'll be frequently submitting stable 3.0.x updates until the major 3.1 version 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:

@ -1,14 +1,25 @@
import org.gradle.api.artifacts.* import org.gradle.api.artifacts.*
apply plugin: 'base' // To add "clean" task to the root project. buildscript {
//apply plugin: 'java-library-distribution' repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.1.0'
}
}
apply plugin: 'base'
apply from: file('version.gradle')
apply from: file('upload.gradle')
// This is applied to all sub projects // This is applied to all sub projects
subprojects { subprojects {
// Don't add to native builds if(!project.name.equals('jme3-android-examples')) {
// if(!project.name.endsWith('native')){ apply from: rootProject.file('common.gradle')
apply from: rootProject.file('common.gradle') } else {
// } apply from: rootProject.file('common-android-app.gradle')
}
} }
task run(dependsOn: ':jme3-examples:run') { task run(dependsOn: ':jme3-examples:run') {
@ -49,15 +60,14 @@ task libDist(dependsOn: subprojects.build) << {
} }
} }
task createZipDistribution(type:Zip,dependsOn:["dist","libDist"], description:"Package the nightly zip distribution"){ task createZipDistribution(type:Zip,dependsOn:["dist","libDist"], description:"Package the nightly zip distribution"){
archiveName "jME"+jmeVersion+"_"+jmeVersionTag+"_"+new Date().format("yyyy-MM-dd")+".zip" archiveName "jME" + jmeFullVersion + ".zip"
into("/") {
into("/") { from {"./dist"}
from {"./dist"} }
} into("/sources") {
into("/sources") { from {"$buildDir/libDist/sources"}
from {"$buildDir/libDist/sources"} }
}
} }
task copyLibs(type: Copy){ task copyLibs(type: Copy){
@ -105,7 +115,12 @@ task wrapper(type: Wrapper, description: 'Creates and deploys the Gradle wrapper
gradleVersion = '2.2.1' gradleVersion = '2.2.1'
} }
String findNDK() { ext {
ndkCommandPath = ""
ndkExists = false
}
task configureAndroidNDK {
def ndkBuildFile = "ndk-build" def ndkBuildFile = "ndk-build"
// if windows, use ndk-build.cmd instead // if windows, use ndk-build.cmd instead
if (System.properties['os.name'].toLowerCase().contains('windows')) { if (System.properties['os.name'].toLowerCase().contains('windows')) {
@ -118,27 +133,13 @@ String findNDK() {
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()) {
return ndkBuildPath ndkExists = true
} else { ndkCommandPath = ndkBuildPath
return null
}
}
boolean checkNdkExists(String ndkCommandPath) {
// String ndkCommandPath = findNDK()
if (ndkCommandPath != null && new File(ndkCommandPath).exists()) {
return true
} else {
return false
} }
} }
ext {
ndkCommandPath = findNDK()
ndkExists = checkNdkExists(ndkCommandPath)
}
//class IncrementalReverseTask extends DefaultTask { //class IncrementalReverseTask extends DefaultTask {
// @InputDirectory // @InputDirectory
// def File inputDir // def File inputDir
@ -166,11 +167,11 @@ ext {
// } // }
//} //}
allprojects { //allprojects {
tasks.withType(JavaExec) { // tasks.withType(JavaExec) {
enableAssertions = true // false by default // enableAssertions = true // false by default
} // }
tasks.withType(Test) { // tasks.withType(Test) {
enableAssertions = true // true by default // enableAssertions = true // true by default
} // }
} //}

@ -0,0 +1,13 @@
apply plugin: 'com.android.application'
group = 'com.jme3'
version = jmeVersion + '-' + jmeVersionTag
sourceCompatibility = '1.6'
repositories {
mavenCentral()
maven {
url "http://nifty-gui.sourceforge.net/nifty-maven-repo"
}
}

@ -4,10 +4,9 @@
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'maven' apply plugin: 'maven'
apply plugin: 'maven-publish'
group = 'com.jme3' group = 'com.jme3'
version = jmeVersion + '-' + jmeVersionTag version = jmePomVersion
sourceCompatibility = '1.6' sourceCompatibility = '1.6'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
@ -19,9 +18,21 @@ repositories {
} }
} }
configurations {
deployerJars
}
dependencies { dependencies {
// Adding dependencies here will add the dependencies to each subproject. // Adding dependencies here will add the dependencies to each subproject.
testCompile group: 'junit', name: 'junit', version: '4.10' testCompile group: 'junit', name: 'junit', version: '4.10'
deployerJars "org.apache.maven.wagon:wagon-ssh:2.9"
}
jar {
manifest {
attributes 'Implementation-Title': 'jMonkeyEngine',
'Implementation-Version': jmeFullVersion
}
} }
javadoc { javadoc {
@ -56,41 +67,35 @@ artifacts {
} }
} }
publishing { uploadArchives {
publications { repositories.mavenDeployer {
maven(MavenPublication) { configuration = configurations.deployerJars
from components.java
artifact sourcesJar // disable this otherwise it will fill up the server with stale jars
artifact javadocJar uniqueVersion = false
pom.withXml { repository(url: "scp://updates.jmonkeyengine.org/var/www/updates/maven") {
asNode().children().last() + { authentication(userName: "www-updater", privateKey: "private/www-updater.key")
resolveStrategy = Closure.DELEGATE_FIRST }
name POM_NAME
description POM_DESCRIPTION pom.project {
url POM_URL name POM_NAME
scm { description POM_DESCRIPTION
url POM_SCM_URL url POM_URL
connection POM_SCM_CONNECTION scm {
developerConnection POM_SCM_DEVELOPER_CONNECTION url POM_SCM_URL
} connection POM_SCM_CONNECTION
licenses { developerConnection POM_SCM_DEVELOPER_CONNECTION
license { }
name POM_LICENSE_NAME licenses {
url POM_LICENSE_URL license {
distribution POM_LICENSE_DISTRIBUTION name POM_LICENSE_NAME
} url POM_LICENSE_URL
} distribution POM_LICENSE_DISTRIBUTION
} }
} }
} }
} }
repositories {
maven {
url "${rootProject.buildDir}/repo" // change to point to your repo, e.g. http://my.org/repo
}
}
} }
task createFolders(description: 'Creates the source folders if they do not exist.') doLast { task createFolders(description: 'Creates the source folders if they do not exist.') doLast {

@ -3,7 +3,9 @@ jmeVersion = 3.1.0
# Version used for application and settings folder, no spaces! # Version used for application and settings folder, no spaces!
jmeMainVersion = 3.1 jmeMainVersion = 3.1
# Version addition pre-alpha-svn, Stable, Beta # Version addition pre-alpha-svn, Stable, Beta
jmeVersionTag = snapshot-github jmeVersionTag = SNAPSHOT
# Increment this each time jmeVersionTag changes but jmeVersion stays the same
jmeVersionTagID = 0
# specify if JavaDoc should be built # specify if JavaDoc should be built
buildJavaDoc = true buildJavaDoc = true
@ -11,6 +13,7 @@ buildJavaDoc = true
# specify if SDK and Native libraries get built # specify if SDK and Native libraries get built
buildSdkProject = true buildSdkProject = true
buildNativeProjects = false buildNativeProjects = false
buildAndroidExamples = false
# Path to android NDK for building native libraries # Path to android NDK for building native libraries
#ndkPath=/Users/normenhansen/Documents/Code-Import/android-ndk-r7 #ndkPath=/Users/normenhansen/Documents/Code-Import/android-ndk-r7

@ -0,0 +1,40 @@
dependencies {
compile project(':jme3-core')
compile project(':jme3-android')
compile project(':jme3-effects')
compile project(':jme3-bullet')
compile project(':jme3-bullet-native-android')
compile project(':jme3-networking')
compile project(':jme3-niftygui')
compile project(':jme3-plugins')
compile project(':jme3-terrain')
compile project(':jme3-testdata')
}
android {
compileSdkVersion 10
buildToolsVersion "22.0.1"
lintOptions {
// Fix nifty gui referencing "java.awt" package.
disable 'InvalidPackage'
}
defaultConfig {
applicationId "com.jme3.android"
minSdkVersion 10 // Android 2.3 GINGERBREAD
targetSdkVersion 22 // Android 5.1 LOLLIPOP
versionCode 1
versionName "1.0" // TODO: from settings.gradle
}
buildTypes {
release {
minifyEnabled false
}
debug {
applicationIdSuffix ".debug"
debuggable true
}
}
}

@ -0,0 +1,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jme3.android">
<!-- Tell the system that you need ES 2.0. -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- Tell the system that you need distinct touches (for the zoom gesture). -->
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="true" />
<application android:label="@string/app_name" android:allowBackup="true">
<activity android:name="jme3test.android.TestChooserAndroid"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

@ -0,0 +1,12 @@
package jme3test.android;
import android.content.pm.ActivityInfo;
import android.app.*;
import android.os.Bundle;
public class TestChooserAndroid extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">JMEAndroidTest</string>
<string name="about">About</string>
<string name="quit">Quit</string>
</resources>

@ -525,4 +525,9 @@ public class AndroidMediaPlayerAudioRenderer implements AudioRenderer,
@Override @Override
public void deleteFilter(Filter filter) { public void deleteFilter(Filter filter) {
} }
@Override
public float getSourcePlaybackTime(AudioSource src) {
throw new UnsupportedOperationException("Not supported yet.");
}
} }

@ -6,4 +6,7 @@ dependencies {
compile project(':jme3-core') compile project(':jme3-core')
compile project(':jme3-desktop') compile project(':jme3-desktop')
compile project(':jme3-effects') compile project(':jme3-effects')
} compile ('org.ejml:core:0.27')
compile ('org.ejml:dense64:0.27')
compile ('org.ejml:simple:0.27')
}

@ -145,7 +145,7 @@ public class Ipo {
float[] times = new float[framesAmount + 1]; float[] times = new float[framesAmount + 1];
Vector3f[] translations = new Vector3f[framesAmount + 1]; Vector3f[] translations = new Vector3f[framesAmount + 1];
float[] translation = new float[] { localTranslation.x, localTranslation.y, localTranslation.z }; float[] translation = new float[3];
Quaternion[] rotations = new Quaternion[framesAmount + 1]; Quaternion[] rotations = new Quaternion[framesAmount + 1];
float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW(), }; float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW(), };
float[] eulerRotation = localRotation.toAngles(null); float[] eulerRotation = localRotation.toAngles(null);
@ -165,6 +165,8 @@ public class Ipo {
// calculating track data // calculating track data
for (int frame = startFrame; frame <= stopFrame; ++frame) { for (int frame = startFrame; frame <= stopFrame; ++frame) {
boolean translationSet = false;
translation[0] = translation[1] = translation[2] = 0;
int index = frame - startFrame; int index = frame - startFrame;
times[index] = index * timeBetweenFrames;// start + (frame - 1) * timeBetweenFrames; times[index] = index * timeBetweenFrames;// start + (frame - 1) * timeBetweenFrames;
for (int j = 0; j < bezierCurves.length; ++j) { for (int j = 0; j < bezierCurves.length; ++j) {
@ -173,15 +175,18 @@ public class Ipo {
// LOCATION // LOCATION
case AC_LOC_X: case AC_LOC_X:
translation[0] = (float) value; translation[0] = (float) value;
translationSet = true;
break; break;
case AC_LOC_Y: case AC_LOC_Y:
if (swapAxes && value != 0) { if (swapAxes && value != 0) {
value = -value; value = -value;
} }
translation[yIndex] = (float) value; translation[yIndex] = (float) value;
translationSet = true;
break; break;
case AC_LOC_Z: case AC_LOC_Z:
translation[zIndex] = (float) value; translation[zIndex] = (float) value;
translationSet = true;
break; break;
// EULER ROTATION // EULER ROTATION
@ -235,7 +240,11 @@ public class Ipo {
LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType()); LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType());
} }
} }
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2])); if(translationSet) {
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
} else {
translations[index] = new Vector3f();
}
if(boneContext != null) { if(boneContext != null) {
if(boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) { if(boneContext.getBone().getParent() == null && boneContext.is(BoneContext.NO_LOCAL_LOCATION)) {

@ -64,7 +64,7 @@ public abstract class Constraint {
Pointer pData = (Pointer) constraintStructure.getFieldValue("data"); Pointer pData = (Pointer) constraintStructure.getFieldValue("data");
if (pData.isNotNull()) { if (pData.isNotNull()) {
Structure data = pData.fetchData().get(0); Structure data = pData.fetchData().get(0);
constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(data, ownerOMA, blenderContext); constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(data, name, ownerOMA, blenderContext);
Pointer pTar = (Pointer) data.getFieldValue("tar"); Pointer pTar = (Pointer) data.getFieldValue("tar");
if (pTar != null && pTar.isNotNull()) { if (pTar != null && pTar.isNotNull()) {
targetOMA = pTar.getOldMemoryAddress(); targetOMA = pTar.getOldMemoryAddress();
@ -77,7 +77,7 @@ public abstract class Constraint {
} }
} else { } else {
// Null constraint has no data, so create it here // Null constraint has no data, so create it here
constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(null, null, blenderContext); constraintDefinition = ConstraintDefinitionFactory.createConstraintDefinition(null, name, null, blenderContext);
} }
ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue()); ownerSpace = Space.valueOf(((Number) constraintStructure.getFieldValue("ownspace")).byteValue());
ipo = influenceIpo; ipo = influenceIpo;

@ -7,6 +7,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.Stack;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.animation.AnimChannel; import com.jme3.animation.AnimChannel;
@ -38,9 +39,9 @@ import com.jme3.util.TempVars;
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
public class SimulationNode { public class SimulationNode {
private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName()); private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName());
private Long featureOMA; private Long featureOMA;
/** The blender context. */ /** The blender context. */
private BlenderContext blenderContext; private BlenderContext blenderContext;
/** The name of the node (for debugging purposes). */ /** The name of the node (for debugging purposes). */
@ -51,11 +52,11 @@ public class SimulationNode {
private List<Animation> animations; private List<Animation> animations;
/** The nodes spatial (if null then the boneContext should be set). */ /** The nodes spatial (if null then the boneContext should be set). */
private Spatial spatial; private Spatial spatial;
/** The skeleton of the bone (not null if the node simulated the bone). */ /** The skeleton of the bone (not null if the node simulated the bone). */
private Skeleton skeleton; private Skeleton skeleton;
/** Animation controller for the node's feature. */ /** Animation controller for the node's feature. */
private AnimControl animControl; private AnimControl animControl;
/** /**
* The star transform of a spatial. Needed to properly reset the spatial to * The star transform of a spatial. Needed to properly reset the spatial to
@ -64,7 +65,7 @@ public class SimulationNode {
private Transform spatialStartTransform; private Transform spatialStartTransform;
/** Star transformations for bones. Needed to properly reset the bones. */ /** Star transformations for bones. Needed to properly reset the bones. */
private Map<Bone, Transform> boneStartTransforms; private Map<Bone, Transform> boneStartTransforms;
/** /**
* Builds the nodes tree for the given feature. The feature (bone or * Builds the nodes tree for the given feature. The feature (bone or
* spatial) is found by its OMA. The feature must be a root bone or a root * spatial) is found by its OMA. The feature must be a root bone or a root
@ -208,8 +209,7 @@ public class SimulationNode {
if (animations != null) { if (animations != null) {
TempVars vars = TempVars.get(); TempVars vars = TempVars.get();
AnimChannel animChannel = animControl.createChannel(); AnimChannel animChannel = animControl.createChannel();
// List<Bone> bonesWithConstraints = this.collectBonesWithConstraints(skeleton);
for (Animation animation : animations) { for (Animation animation : animations) {
float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation); float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
int maxFrame = (int) animationTimeBoundaries[0]; int maxFrame = (int) animationTimeBoundaries[0];
@ -233,7 +233,7 @@ public class SimulationNode {
for (Bone rootBone : skeleton.getRoots()) { for (Bone rootBone : skeleton.getRoots()) {
// ignore the 0-indexed bone // ignore the 0-indexed bone
if (skeleton.getBoneIndex(rootBone) > 0) { if (skeleton.getBoneIndex(rootBone) > 0) {
this.applyConstraints(rootBone, alteredOmas, applied, frame); this.applyConstraints(rootBone, alteredOmas, applied, frame, new Stack<Bone>());
} }
} }
@ -294,34 +294,39 @@ public class SimulationNode {
* the set of OMAS of the altered bones (is populated if necessary) * the set of OMAS of the altered bones (is populated if necessary)
* @param frame * @param frame
* the current frame of the animation * the current frame of the animation
* @param bonesStack
* the stack of bones used to avoid infinite loops while applying constraints
*/ */
private void applyConstraints(Bone bone, Set<Long> alteredOmas, Set<Long> applied, int frame) { private void applyConstraints(Bone bone, Set<Long> alteredOmas, Set<Long> applied, int frame, Stack<Bone> bonesStack) {
BoneContext boneContext = blenderContext.getBoneContext(bone); if (!bonesStack.contains(bone)) {
if(!applied.contains(boneContext.getBoneOma())) { bonesStack.push(bone);
List<Constraint> constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext); BoneContext boneContext = blenderContext.getBoneContext(bone);
if (constraints != null && constraints.size() > 0) { if (!applied.contains(boneContext.getBoneOma())) {
// TODO: BEWARE OF INFINITE LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!! List<Constraint> constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext);
for (Constraint constraint : constraints) { if (constraints != null && constraints.size() > 0) {
if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) { for (Constraint constraint : constraints) {
// first apply constraints of the target bone if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) {
BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA()); // first apply constraints of the target bone
this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame); BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA());
} this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame, bonesStack);
constraint.apply(frame); }
if (constraint.getAlteredOmas() != null) { constraint.apply(frame);
alteredOmas.addAll(constraint.getAlteredOmas()); if (constraint.getAlteredOmas() != null) {
alteredOmas.addAll(constraint.getAlteredOmas());
}
alteredOmas.add(boneContext.getBoneOma());
} }
alteredOmas.add(boneContext.getBoneOma());
} }
applied.add(boneContext.getBoneOma());
} }
applied.add(boneContext.getBoneOma());
} List<Bone> children = bone.getChildren();
if (children != null && children.size() > 0) {
List<Bone> children = bone.getChildren(); for (Bone child : bone.getChildren()) {
if (children != null && children.size() > 0) { this.applyConstraints(child, alteredOmas, applied, frame, bonesStack);
for (Bone child : bone.getChildren()) { }
this.applyConstraints(child, alteredOmas, applied, frame);
} }
bonesStack.pop();
} }
} }

@ -30,6 +30,8 @@ public abstract class ConstraintDefinition {
protected Set<Long> alteredOmas; protected Set<Long> alteredOmas;
/** The variable that determines if the constraint will alter the track in any way. */ /** The variable that determines if the constraint will alter the track in any way. */
protected boolean trackToBeChanged = true; protected boolean trackToBeChanged = true;
/** The name of the constraint. */
protected String constraintName;
/** /**
* Loads a constraint definition based on the constraint definition * Loads a constraint definition based on the constraint definition
@ -53,6 +55,10 @@ public abstract class ConstraintDefinition {
constraintHelper = (ConstraintHelper) (blenderContext == null ? null : blenderContext.getHelper(ConstraintHelper.class)); constraintHelper = (ConstraintHelper) (blenderContext == null ? null : blenderContext.getHelper(ConstraintHelper.class));
this.ownerOMA = ownerOMA; this.ownerOMA = ownerOMA;
} }
public void setConstraintName(String constraintName) {
this.constraintName = constraintName;
}
/** /**
* @return determines if the definition of the constraint will change the bone in any way; in most cases * @return determines if the definition of the constraint will change the bone in any way; in most cases

@ -92,7 +92,7 @@ public class ConstraintDefinitionFactory {
* this exception is thrown when the blender file is somehow * this exception is thrown when the blender file is somehow
* corrupted * corrupted
*/ */
public static ConstraintDefinition createConstraintDefinition(Structure constraintStructure, Long ownerOMA, BlenderContext blenderContext) throws BlenderFileException { public static ConstraintDefinition createConstraintDefinition(Structure constraintStructure, String constraintName, Long ownerOMA, BlenderContext blenderContext) throws BlenderFileException {
if (constraintStructure == null) { if (constraintStructure == null) {
return new ConstraintDefinitionNull(null, ownerOMA, blenderContext); return new ConstraintDefinitionNull(null, ownerOMA, blenderContext);
} }
@ -100,7 +100,9 @@ public class ConstraintDefinitionFactory {
Class<? extends ConstraintDefinition> constraintDefinitionClass = CONSTRAINT_CLASSES.get(constraintClassName); Class<? extends ConstraintDefinition> constraintDefinitionClass = CONSTRAINT_CLASSES.get(constraintClassName);
if (constraintDefinitionClass != null) { if (constraintDefinitionClass != null) {
try { try {
return (ConstraintDefinition) constraintDefinitionClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, blenderContext); ConstraintDefinition def = (ConstraintDefinition) constraintDefinitionClass.getDeclaredConstructors()[0].newInstance(constraintStructure, ownerOMA, blenderContext);
def.setConstraintName(constraintName);
return def;
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new BlenderFileException(e.getLocalizedMessage(), e); throw new BlenderFileException(e.getLocalizedMessage(), e);
} catch (SecurityException e) { } catch (SecurityException e) {
@ -113,9 +115,9 @@ public class ConstraintDefinitionFactory {
throw new BlenderFileException(e.getLocalizedMessage(), e); throw new BlenderFileException(e.getLocalizedMessage(), e);
} }
} else { } else {
String constraintName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName); String unsupportedConstraintClassName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName);
if (constraintName != null) { if (unsupportedConstraintClassName != null) {
return new UnsupportedConstraintDefinition(constraintName); return new UnsupportedConstraintDefinition(unsupportedConstraintClassName);
} else { } else {
throw new BlenderFileException("Unknown constraint type: " + constraintClassName); throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
} }

@ -1,40 +1,44 @@
package com.jme3.scene.plugins.blender.constraints.definitions; package com.jme3.scene.plugins.blender.constraints.definitions;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import org.ejml.simple.SimpleMatrix;
import com.jme3.animation.Bone; import com.jme3.animation.Bone;
import com.jme3.math.Transform; import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.animations.BoneContext; import com.jme3.scene.plugins.blender.animations.BoneContext;
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space; import com.jme3.scene.plugins.blender.constraints.ConstraintHelper.Space;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.math.DQuaternion; import com.jme3.scene.plugins.blender.math.DQuaternion;
import com.jme3.scene.plugins.blender.math.DTransform; import com.jme3.scene.plugins.blender.math.DTransform;
import com.jme3.scene.plugins.blender.math.Matrix;
import com.jme3.scene.plugins.blender.math.Vector3d; import com.jme3.scene.plugins.blender.math.Vector3d;
/** /**
* The Inverse Kinematics constraint. * A definiotion of a Inverse Kinematics constraint. This implementation uses Jacobian pseudoinverse algorithm.
* *
* @author Wesley Shillingford (wezrule)
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
public class ConstraintDefinitionIK extends ConstraintDefinition { public class ConstraintDefinitionIK extends ConstraintDefinition {
private static final float MIN_DISTANCE = 0.0001f; private static final float MIN_DISTANCE = 0.001f;
private static final int FLAG_USE_TAIL = 0x01; private static final float MIN_ANGLE_CHANGE = 0.001f;
private static final int FLAG_POSITION = 0x20; private static final int FLAG_USE_TAIL = 0x01;
private static final int FLAG_POSITION = 0x20;
private BonesChain bones;
/** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */ /** The number of affected bones. Zero means that all parent bones of the current bone should take part in baking. */
private int bonesAffected; private int bonesAffected;
/** The total length of the bone chain. Useful for optimisation of computations speed in some cases. */
private double chainLength;
/** Indicates if the tail of the bone should be used or not. */ /** Indicates if the tail of the bone should be used or not. */
private boolean useTail; private boolean useTail;
/** The amount of iterations of the algorithm. */ /** The amount of iterations of the algorithm. */
private int iterations; private int iterations;
/** The count of bones' chain. */
private int bonesCount = -1;
public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) { public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext blenderContext) {
super(constraintData, ownerOMA, blenderContext); super(constraintData, ownerOMA, blenderContext);
@ -51,122 +55,104 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
} }
} }
/**
* Below are the variables that only need to be allocated once for IK constraint instance.
*/
/** Temporal quaternion. */
private DQuaternion tempDQuaternion = new DQuaternion();
/** Temporal matrix column. */
private Vector3d col = new Vector3d();
/** Effector's position change. */
private Matrix deltaP = new Matrix(3, 1);
/** The current target position. */
private Vector3d target = new Vector3d();
/** Rotation vectors for each joint (allocated when we know the size of a bones' chain. */
private Vector3d[] rotationVectors;
/** The Jacobian matrix. Allocated when the bones' chain size is known. */
private Matrix J;
@Override @Override
public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) { public void bake(Space ownerSpace, Space targetSpace, Transform targetTransform, float influence) {
if (influence == 0 || !trackToBeChanged || targetTransform == null) { if (influence == 0 || !trackToBeChanged || targetTransform == null || bonesCount == 0) {
return;// no need to do anything return;// no need to do anything
} }
DQuaternion q = new DQuaternion();
Vector3d t = new Vector3d(targetTransform.getTranslation()); if (bones == null) {
List<BoneContext> bones = this.loadBones(); bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, alteredOmas, blenderContext);
}
if (bones.size() == 0) { if (bones.size() == 0) {
bonesCount = 0;
return;// no need to do anything return;// no need to do anything
} }
double distanceFromTarget = Double.MAX_VALUE; double distanceFromTarget = Double.MAX_VALUE;
target.set(targetTransform.getTranslation().x, targetTransform.getTranslation().y, targetTransform.getTranslation().z);
int iterations = this.iterations; if (bonesCount < 0) {
if (bones.size() == 1) { bonesCount = bones.size();
iterations = 1;// if only one bone is in the chain then only one iteration that will properly rotate it will be needed rotationVectors = new Vector3d[bonesCount];
} else { for (int i = 0; i < bonesCount; ++i) {
// if the target cannot be rached by the bones' chain then the chain will become straight and point towards the target rotationVectors[i] = new Vector3d();
// in this case only one iteration will be needed, computed from the root to top bone
BoneContext rootBone = bones.get(bones.size() - 1);
Transform rootBoneTransform = constraintHelper.getTransform(rootBone.getArmatureObjectOMA(), rootBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
if (t.distance(new Vector3d(rootBoneTransform.getTranslation())) >= chainLength) {
Collections.reverse(bones);
for (BoneContext boneContext : bones) {
Bone bone = boneContext.getBone();
DTransform boneTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD));
Vector3d e = boneTransform.getTranslation().add(boneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(boneContext.getLength()));// effector
Vector3d j = boneTransform.getTranslation(); // current join position
Vector3d currentDir = e.subtractLocal(j).normalizeLocal();
Vector3d target = t.subtract(j).normalizeLocal();
double angle = currentDir.angleBetween(target);
if (angle != 0) {
Vector3d cross = currentDir.crossLocal(target).normalizeLocal();
q.fromAngleAxis(angle, cross);
if(bone.equals(this.getOwner())) {
if (boneContext.isLockX()) {
q.set(0, q.getY(), q.getZ(), q.getW());
}
if (boneContext.isLockY()) {
q.set(q.getX(), 0, q.getZ(), q.getW());
}
if (boneContext.isLockZ()) {
q.set(q.getX(), q.getY(), 0, q.getW());
}
}
boneTransform.getRotation().set(q.multLocal(boneTransform.getRotation()));
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneTransform.toTransform());
}
}
iterations = 0;
} }
J = new Matrix(3, bonesCount);
} }
List<Transform> bestSolution = new ArrayList<Transform>(bones.size());
double bestSolutionDistance = Double.MAX_VALUE;
BoneContext topBone = bones.get(0); BoneContext topBone = bones.get(0);
for (int i = 0; i < iterations && distanceFromTarget > MIN_DISTANCE; ++i) { for (int i = 0; i < iterations; ++i) {
for (BoneContext boneContext : bones) { DTransform topBoneTransform = bones.getWorldTransform(topBone);
Bone bone = boneContext.getBone(); Vector3d e = topBoneTransform.getTranslation().add(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); distanceFromTarget = e.distance(target);
DTransform boneWorldTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD)); if (distanceFromTarget <= MIN_DISTANCE) {
break;
}
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector deltaP.setColumn(0, 0, target.x - e.x, target.y - e.y, target.z - e.z);
int column = 0;
for (BoneContext boneContext : bones) {
DTransform boneWorldTransform = bones.getWorldTransform(boneContext);
Vector3d j = boneWorldTransform.getTranslation(); // current join position Vector3d j = boneWorldTransform.getTranslation(); // current join position
Vector3d vectorFromJointToEffector = e.subtract(j);
vectorFromJointToEffector.cross(target.subtract(j), rotationVectors[column]).normalizeLocal();
rotationVectors[column].cross(vectorFromJointToEffector, col);
J.setColumn(col, column++);
}
Matrix J_1 = J.pseudoinverse();
Vector3d currentDir = e.subtractLocal(j).normalizeLocal(); SimpleMatrix deltaThetas = J_1.mult(deltaP);
Vector3d target = t.subtract(j).normalizeLocal(); if (deltaThetas.elementMaxAbs() < MIN_ANGLE_CHANGE) {
double angle = currentDir.angleBetween(target); break;
if (angle != 0) {
Vector3d cross = currentDir.crossLocal(target).normalizeLocal();
q.fromAngleAxis(angle, cross);
if(bone.equals(this.getOwner())) {
if (boneContext.isLockX()) {
q.set(0, q.getY(), q.getZ(), q.getW());
}
if (boneContext.isLockY()) {
q.set(q.getX(), 0, q.getZ(), q.getW());
}
if (boneContext.isLockZ()) {
q.set(q.getX(), q.getY(), 0, q.getW());
}
}
boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation()));
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform.toTransform());
} else {
iterations = 0;
break;
}
} }
for (int j = 0; j < deltaThetas.numRows(); ++j) {
double angle = deltaThetas.get(j, 0);
Vector3d rotationVector = rotationVectors[j];
DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); tempDQuaternion.fromAngleAxis(angle, rotationVector);
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector BoneContext boneContext = bones.get(j);
distanceFromTarget = e.distance(t); Bone bone = boneContext.getBone();
if (bone.equals(this.getOwner())) {
if(distanceFromTarget < bestSolutionDistance) { if (boneContext.isLockX()) {
bestSolutionDistance = distanceFromTarget; tempDQuaternion.set(0, tempDQuaternion.getY(), tempDQuaternion.getZ(), tempDQuaternion.getW());
bestSolution.clear(); }
for(BoneContext boneContext : bones) { if (boneContext.isLockY()) {
bestSolution.add(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD)); tempDQuaternion.set(tempDQuaternion.getX(), 0, tempDQuaternion.getZ(), tempDQuaternion.getW());
}
if (boneContext.isLockZ()) {
tempDQuaternion.set(tempDQuaternion.getX(), tempDQuaternion.getY(), 0, tempDQuaternion.getW());
}
} }
DTransform boneTransform = bones.getWorldTransform(boneContext);
boneTransform.getRotation().set(tempDQuaternion.mult(boneTransform.getRotation()));
bones.setWorldTransform(boneContext, boneTransform);
} }
} }
// applying best solution // applying the results
for(int i=0;i<bestSolution.size();++i) { for (int i = bonesCount - 1; i >= 0; --i) {
BoneContext boneContext = bones.get(i); BoneContext boneContext = bones.get(i);
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, bestSolution.get(i)); DTransform transform = bones.getWorldTransform(boneContext);
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform.toTransform());
} }
bones = null;// need to reload them again
} }
@Override @Override
@ -174,56 +160,68 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
return "Inverse kinematics"; return "Inverse kinematics";
} }
@Override
public boolean isTargetRequired() {
return true;
}
/** /**
* @return the bone contexts of all bones that will be used in this constraint computations * Loaded bones' chain. This class allows to operate on transform matrices that use double precision in computations.
* Only the final result is being transformed to single precision numbers.
*
* @author Marcin Roguski (Kaelthas)
*/ */
private List<BoneContext> loadBones() { private static class BonesChain extends ArrayList<BoneContext> {
List<BoneContext> bones = new ArrayList<BoneContext>(); private static final long serialVersionUID = -1850524345643600718L;
Bone bone = (Bone) this.getOwner();
if (bone == null) {
return bones;
}
if (!useTail) {
bone = bone.getParent();
}
chainLength = 0;
while (bone != null) {
BoneContext boneContext = blenderContext.getBoneContext(bone);
chainLength += boneContext.getLength();
bones.add(boneContext);
alteredOmas.add(boneContext.getBoneOma());
if (bonesAffected != 0 && bones.size() >= bonesAffected) {
break;
}
// need to add spaces between bones to the chain length
Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
Vector3f boneWorldTranslation = boneWorldTransform.getTranslation();
bone = bone.getParent(); private List<Matrix> bonesMatrices = new ArrayList<Matrix>();
public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection<Long> alteredOmas, BlenderContext blenderContext) {
if (bone != null) { if (bone != null) {
boneContext = blenderContext.getBoneContext(bone); ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
Transform parentWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD); if (!useTail) {
Vector3f parentWorldTranslation = parentWorldTransform.getTranslation(); bone = bone.getParent();
chainLength += boneWorldTranslation.distance(parentWorldTranslation); }
while (bone != null && (bonesAffected <= 0 || this.size() < bonesAffected)) {
BoneContext boneContext = blenderContext.getBoneContext(bone);
this.add(boneContext);
alteredOmas.add(boneContext.getBoneOma());
Space space = this.size() < bonesAffected ? Space.CONSTRAINT_SPACE_LOCAL : Space.CONSTRAINT_SPACE_WORLD;
Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), space);
bonesMatrices.add(new DTransform(transform).toMatrix());
bone = bone.getParent();
}
} }
} }
return bones;
}
@Override public DTransform getWorldTransform(BoneContext bone) {
public boolean isTrackToBeChanged() { int index = this.indexOf(bone);
if (trackToBeChanged) { return this.getWorldMatrix(index).toTransform();
// need to check the bone structure too (when constructor was called not all of the bones might have been loaded yet)
// that is why it is also checked here
List<BoneContext> bones = this.loadBones();
trackToBeChanged = bones.size() > 0;
} }
return trackToBeChanged;
}
@Override public void setWorldTransform(BoneContext bone, DTransform transform) {
public boolean isTargetRequired() { int index = this.indexOf(bone);
return true; Matrix boneMatrix = transform.toMatrix();
if (index < this.size() - 1) {
// computing the current bone local transform
Matrix parentWorldMatrix = this.getWorldMatrix(index + 1);
SimpleMatrix m = parentWorldMatrix.invert().mult(boneMatrix);
boneMatrix = new Matrix(m);
}
bonesMatrices.set(index, boneMatrix);
}
public Matrix getWorldMatrix(int index) {
if (index == this.size() - 1) {
return new Matrix(bonesMatrices.get(this.size() - 1));
}
SimpleMatrix result = this.getWorldMatrix(index + 1);
result = result.mult(bonesMatrices.get(index));
return new Matrix(result);
}
} }
} }

@ -31,6 +31,7 @@
*/ */
package com.jme3.scene.plugins.blender.file; package com.jme3.scene.plugins.blender.file;
import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.jme3.scene.plugins.blender.BlenderContext; import com.jme3.scene.plugins.blender.BlenderContext;
@ -171,8 +172,21 @@ public class FileBlockHeader {
BLOCK_IP00('I' << 24 | 'P' << 16), // ipo BLOCK_IP00('I' << 24 | 'P' << 16), // ipo
BLOCK_AC00('A' << 24 | 'C' << 16), // action BLOCK_AC00('A' << 24 | 'C' << 16), // action
BLOCK_IM00('I' << 24 | 'M' << 16), // image BLOCK_IM00('I' << 24 | 'M' << 16), // image
BLOCK_TE00('T' << 24 | 'E' << 16), BLOCK_WM00('W' << 24 | 'M' << 16), BLOCK_SR00('S' << 24 | 'R' << 16), BLOCK_SN00('S' << 24 | 'N' << 16), BLOCK_BR00('B' << 24 | 'R' << 16), BLOCK_LS00('L' << 24 | 'S' << 16), BLOCK_GLOB('G' << 24 | 'L' << 16 | 'O' << 8 | 'B'), BLOCK_REND('R' << 24 | 'E' << 16 | 'N' << 8 | 'D'), BLOCK_DATA('D' << 24 | 'A' << 16 | 'T' << 8 | 'A'), BLOCK_DNA1('D' << 24 | 'N' << 16 | 'A' << 8 | '1'), BLOCK_ENDB('E' << 24 | 'N' << 16 | 'D' << 8 | 'B'), BLOCK_TEST('T' << 24 | 'E' << 16 BLOCK_TE00('T' << 24 | 'E' << 16),
| 'S' << 8 | 'T'), BLOCK_UNKN(0); BLOCK_WM00('W' << 24 | 'M' << 16),
BLOCK_SR00('S' << 24 | 'R' << 16),
BLOCK_SN00('S' << 24 | 'N' << 16),
BLOCK_BR00('B' << 24 | 'R' << 16),
BLOCK_LS00('L' << 24 | 'S' << 16),
BLOCK_GR00('G' << 24 | 'R' << 16),
BLOCK_AR00('A' << 24 | 'R' << 16),
BLOCK_GLOB('G' << 24 | 'L' << 16 | 'O' << 8 | 'B'),
BLOCK_REND('R' << 24 | 'E' << 16 | 'N' << 8 | 'D'),
BLOCK_DATA('D' << 24 | 'A' << 16 | 'T' << 8 | 'A'),
BLOCK_DNA1('D' << 24 | 'N' << 16 | 'A' << 8 | '1'),
BLOCK_ENDB('E' << 24 | 'N' << 16 | 'D' << 8 | 'B'),
BLOCK_TEST('T' << 24 | 'E' << 16 | 'S' << 8 | 'T'),
BLOCK_UNKN(0);
private int code; private int code;
@ -187,7 +201,12 @@ public class FileBlockHeader {
} }
} }
byte[] codeBytes = new byte[] { (byte) (code >> 24 & 0xFF), (byte) (code >> 16 & 0xFF), (byte) (code >> 8 & 0xFF), (byte) (code & 0xFF) }; byte[] codeBytes = new byte[] { (byte) (code >> 24 & 0xFF), (byte) (code >> 16 & 0xFF), (byte) (code >> 8 & 0xFF), (byte) (code & 0xFF) };
LOGGER.warning("Unknown block header: " + new String(codeBytes)); for (int i = 0; i < codeBytes.length; ++i) {
if (codeBytes[i] == 0) {
codeBytes[i] = '0';
}
}
LOGGER.log(Level.WARNING, "Unknown block header: {0}", new String(codeBytes));
return BLOCK_UNKN; return BLOCK_UNKN;
} }
} }

@ -164,6 +164,134 @@ public final class DQuaternion implements Savable, Cloneable, java.io.Serializab
w = 1; w = 1;
} }
/**
* <code>norm</code> returns the norm of this quaternion. This is the dot
* product of this quaternion with itself.
*
* @return the norm of the quaternion.
*/
public double norm() {
return w * w + x * x + y * y + z * z;
}
public DQuaternion fromRotationMatrix(double m00, double m01, double m02,
double m10, double m11, double m12, double m20, double m21, double m22) {
// first normalize the forward (F), up (U) and side (S) vectors of the rotation matrix
// so that the scale does not affect the rotation
double lengthSquared = m00 * m00 + m10 * m10 + m20 * m20;
if (lengthSquared != 1f && lengthSquared != 0f) {
lengthSquared = 1.0 / Math.sqrt(lengthSquared);
m00 *= lengthSquared;
m10 *= lengthSquared;
m20 *= lengthSquared;
}
lengthSquared = m01 * m01 + m11 * m11 + m21 * m21;
if (lengthSquared != 1 && lengthSquared != 0f) {
lengthSquared = 1.0 / Math.sqrt(lengthSquared);
m01 *= lengthSquared;
m11 *= lengthSquared;
m21 *= lengthSquared;
}
lengthSquared = m02 * m02 + m12 * m12 + m22 * m22;
if (lengthSquared != 1f && lengthSquared != 0f) {
lengthSquared = 1.0 / Math.sqrt(lengthSquared);
m02 *= lengthSquared;
m12 *= lengthSquared;
m22 *= lengthSquared;
}
// Use the Graphics Gems code, from
// ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z
// *NOT* the "Matrix and Quaternions FAQ", which has errors!
// the trace is the sum of the diagonal elements; see
// http://mathworld.wolfram.com/MatrixTrace.html
double t = m00 + m11 + m22;
// we protect the division by s by ensuring that s>=1
if (t >= 0) { // |w| >= .5
double s = Math.sqrt(t + 1); // |s|>=1 ...
w = 0.5f * s;
s = 0.5f / s; // so this division isn't bad
x = (m21 - m12) * s;
y = (m02 - m20) * s;
z = (m10 - m01) * s;
} else if (m00 > m11 && m00 > m22) {
double s = Math.sqrt(1.0 + m00 - m11 - m22); // |s|>=1
x = s * 0.5f; // |x| >= .5
s = 0.5f / s;
y = (m10 + m01) * s;
z = (m02 + m20) * s;
w = (m21 - m12) * s;
} else if (m11 > m22) {
double s = Math.sqrt(1.0 + m11 - m00 - m22); // |s|>=1
y = s * 0.5f; // |y| >= .5
s = 0.5f / s;
x = (m10 + m01) * s;
z = (m21 + m12) * s;
w = (m02 - m20) * s;
} else {
double s = Math.sqrt(1.0 + m22 - m00 - m11); // |s|>=1
z = s * 0.5f; // |z| >= .5
s = 0.5f / s;
x = (m02 + m20) * s;
y = (m21 + m12) * s;
w = (m10 - m01) * s;
}
return this;
}
/**
* <code>toRotationMatrix</code> converts this quaternion to a rotational
* matrix. The result is stored in result. 4th row and 4th column values are
* untouched. Note: the result is created from a normalized version of this quat.
*
* @param result
* The Matrix4f to store the result in.
* @return the rotation matrix representation of this quaternion.
*/
public Matrix toRotationMatrix(Matrix result) {
Vector3d originalScale = new Vector3d();
result.toScaleVector(originalScale);
result.setScale(1, 1, 1);
double norm = this.norm();
// we explicitly test norm against one here, saving a division
// at the cost of a test and branch. Is it worth it?
double s = norm == 1f ? 2f : norm > 0f ? 2f / norm : 0;
// compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
// will be used 2-4 times each.
double xs = x * s;
double ys = y * s;
double zs = z * s;
double xx = x * xs;
double xy = x * ys;
double xz = x * zs;
double xw = w * xs;
double yy = y * ys;
double yz = y * zs;
double yw = w * ys;
double zz = z * zs;
double zw = w * zs;
// using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
result.set(0, 0, 1 - (yy + zz));
result.set(0, 1, xy - zw);
result.set(0, 2, xz + yw);
result.set(1, 0, xy + zw);
result.set(1, 1, 1 - (xx + zz));
result.set(1, 2, yz - xw);
result.set(2, 0, xz - yw);
result.set(2, 1, yz + xw);
result.set(2, 2, 1 - (xx + yy));
result.setScale(originalScale);
return result;
}
/** /**
* <code>fromAngleAxis</code> sets this quaternion to the values specified * <code>fromAngleAxis</code> sets this quaternion to the values specified
* by an angle and an axis of rotation. This method creates an object, so * by an angle and an axis of rotation. This method creates an object, so

@ -31,11 +31,15 @@
*/ */
package com.jme3.scene.plugins.blender.math; package com.jme3.scene.plugins.blender.math;
import com.jme3.export.*;
import com.jme3.math.Transform;
import java.io.IOException; import java.io.IOException;
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.math.Transform;
/** /**
* Started Date: Jul 16, 2004<br> * Started Date: Jul 16, 2004<br>
* <br> * <br>
@ -57,6 +61,12 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
private Vector3d translation; private Vector3d translation;
private Vector3d scale; private Vector3d scale;
public DTransform() {
translation = new Vector3d();
rotation = new DQuaternion();
scale = new Vector3d();
}
public DTransform(Transform transform) { public DTransform(Transform transform) {
translation = new Vector3d(transform.getTranslation()); translation = new Vector3d(transform.getTranslation());
rotation = new DQuaternion(transform.getRotation()); rotation = new DQuaternion(transform.getRotation());
@ -66,7 +76,15 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
public Transform toTransform() { public Transform toTransform() {
return new Transform(translation.toVector3f(), rotation.toQuaternion(), scale.toVector3f()); return new Transform(translation.toVector3f(), rotation.toQuaternion(), scale.toVector3f());
} }
public Matrix toMatrix() {
Matrix m = Matrix.identity(4);
m.setTranslation(translation);
m.setRotationQuaternion(rotation);
m.setScale(scale);
return m;
}
/** /**
* Sets this translation to the given value. * Sets this translation to the given value.
* @param trans * @param trans

@ -0,0 +1,214 @@
package com.jme3.scene.plugins.blender.math;
import java.text.DecimalFormat;
import org.ejml.ops.CommonOps;
import org.ejml.simple.SimpleMatrix;
import org.ejml.simple.SimpleSVD;
import com.jme3.math.FastMath;
/**
* Encapsulates a 4x4 matrix
*
*
*/
public class Matrix extends SimpleMatrix {
private static final long serialVersionUID = 2396600537315902559L;
public Matrix(int rows, int cols) {
super(rows, cols);
}
/**
* Copy constructor
*/
public Matrix(SimpleMatrix m) {
super(m);
}
public Matrix(double[][] data) {
super(data);
}
public static Matrix identity(int size) {
Matrix result = new Matrix(size, size);
CommonOps.setIdentity(result.mat);
return result;
}
public Matrix pseudoinverse() {
return this.pseudoinverse(1);
}
@SuppressWarnings("unchecked")
public Matrix pseudoinverse(double lambda) {
SimpleSVD<SimpleMatrix> simpleSVD = this.svd();
SimpleMatrix U = simpleSVD.getU();
SimpleMatrix S = simpleSVD.getW();
SimpleMatrix V = simpleSVD.getV();
int N = Math.min(this.numRows(),this.numCols());
double maxSingular = 0;
for( int i = 0; i < N; ++i ) {
if( S.get(i, i) > maxSingular ) {
maxSingular = S.get(i, i);
}
}
double tolerance = FastMath.DBL_EPSILON * Math.max(this.numRows(),this.numCols()) * maxSingular;
for(int i=0;i<Math.min(S.numRows(), S.numCols());++i) {
double a = S.get(i, i);
if(a <= tolerance) {
a = 0;
} else {
a = a/(a * a + lambda * lambda);
}
S.set(i, i, a);
}
return new Matrix(V.mult(S.transpose()).mult(U.transpose()));
}
public void setColumn(Vector3d col, int column) {
this.setColumn(column, 0, col.x, col.y, col.z);
}
/**
* Just for some debug informations in order to compare the results with the scilab computation program.
* @param name the name of the matrix
* @param m the matrix to print out
* @return the String format of the matrix to easily input it to Scilab
*/
public String toScilabString(String name, SimpleMatrix m) {
String result = name + " = [";
for(int i=0;i<m.numRows();++i) {
for(int j=0;j<m.numCols();++j) {
result += m.get(i, j) + " ";
}
result += ";";
}
return result;
}
/**
* @return a String representation of the matrix
*/
@Override
public String toString() {
DecimalFormat df = new DecimalFormat("#.0000");
StringBuilder buf = new StringBuilder();
for (int r = 0; r < this.numRows(); ++r) {
buf.append("\n| ");
for (int c = 0; c < this.numCols(); ++c) {
buf.append(df.format(this.get(r, c))).append(' ');
}
buf.append('|');
}
return buf.toString();
}
public void setTranslation(Vector3d translation) {
this.setColumn(translation, 3);
}
/**
* Sets the scale.
*
* @param scale
* the scale vector to set
*/
public void setScale(Vector3d scale) {
this.setScale(scale.x, scale.y, scale.z);
}
/**
* Sets the scale.
*
* @param x
* the X scale
* @param y
* the Y scale
* @param z
* the Z scale
*/
public void setScale(double x, double y, double z) {
Vector3d vect1 = new Vector3d(this.get(0, 0), this.get(1, 0), this.get(2, 0));
vect1.normalizeLocal().multLocal(x);
this.set(0, 0, vect1.x);
this.set(1, 0, vect1.y);
this.set(2, 0, vect1.z);
vect1.set(this.get(0, 1), this.get(1, 1), this.get(2, 1));
vect1.normalizeLocal().multLocal(y);
this.set(0, 1, vect1.x);
this.set(1, 1, vect1.y);
this.set(2, 1, vect1.z);
vect1.set(this.get(0, 2), this.get(1, 2), this.get(2, 2));
vect1.normalizeLocal().multLocal(z);
this.set(0, 2, vect1.x);
this.set(1, 2, vect1.y);
this.set(2, 2, vect1.z);
}
/**
* <code>setRotationQuaternion</code> builds a rotation from a
* <code>Quaternion</code>.
*
* @param quat
* the quaternion to build the rotation from.
* @throws NullPointerException
* if quat is null.
*/
public void setRotationQuaternion(DQuaternion quat) {
quat.toRotationMatrix(this);
}
public DTransform toTransform() {
DTransform result = new DTransform();
result.setTranslation(this.toTranslationVector());
result.setRotation(this.toRotationQuat());
result.setScale(this.toScaleVector());
return result;
}
public Vector3d toTranslationVector() {
return new Vector3d(this.get(0, 3), this.get(1, 3), this.get(2, 3));
}
public DQuaternion toRotationQuat() {
DQuaternion quat = new DQuaternion();
quat.fromRotationMatrix(this.get(0, 0), this.get(0, 1), this.get(0, 2), this.get(1, 0), this.get(1, 1), this.get(1, 2), this.get(2, 0), this.get(2, 1), this.get(2, 2));
return quat;
}
/**
* Retreives the scale vector from the matrix and stores it into a given
* vector.
*
* @param the
* vector where the scale will be stored
*/
public Vector3d toScaleVector() {
Vector3d result = new Vector3d();
this.toScaleVector(result);
return result;
}
/**
* Retreives the scale vector from the matrix and stores it into a given
* vector.
*
* @param the
* vector where the scale will be stored
*/
public void toScaleVector(Vector3d vector) {
double scaleX = Math.sqrt(this.get(0, 0) * this.get(0, 0) + this.get(1, 0) * this.get(1, 0) + this.get(2, 0) * this.get(2, 0));
double scaleY = Math.sqrt(this.get(0, 1) * this.get(0, 1) + this.get(1, 1) * this.get(1, 1) + this.get(2, 1) * this.get(2, 1));
double scaleZ = Math.sqrt(this.get(0, 2) * this.get(0, 2) + this.get(1, 2) * this.get(1, 2) + this.get(2, 2) * this.get(2, 2));
vector.set(scaleX, scaleY, scaleZ);
}
}

@ -811,39 +811,72 @@ extern "C" {
/* /*
* Class: com_jme3_bullet_objects_PhysicsRigidBody * Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: getAngularFactor * Method: getAngularFactor
* Signature: (J)F * Signature: (JLcom/jme3/math/Vector3f;)V
*/ */
JNIEXPORT jfloat JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor
(JNIEnv *env, jobject object, jlong bodyId) { (JNIEnv *env, jobject object, jlong bodyId, jobject factor) {
btRigidBody* body = reinterpret_cast<btRigidBody*>(bodyId); btRigidBody* body = reinterpret_cast<btRigidBody*>(bodyId);
if (body == NULL) { if (body == NULL) {
jclass newExc = env->FindClass("java/lang/NullPointerException"); jclass newExc = env->FindClass("java/lang/NullPointerException");
env->ThrowNew(newExc, "The native object does not exist."); env->ThrowNew(newExc, "The native object does not exist.");
return 0; return;
} }
return body->getAngularFactor().getX(); jmeBulletUtil::convert(env, &body->getAngularFactor(), factor);
} }
/* /*
* Class: com_jme3_bullet_objects_PhysicsRigidBody * Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: setAngularFactor * Method: setAngularFactor
* Signature: (JF)V * Signature: (JLcom/jme3/math/Vector3f;)V
*/ */
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_setAngularFactor JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_setAngularFactor
(JNIEnv *env, jobject object, jlong bodyId, jfloat value) { (JNIEnv *env, jobject object, jlong bodyId, jobject factor) {
btRigidBody* body = reinterpret_cast<btRigidBody*>(bodyId); btRigidBody* body = reinterpret_cast<btRigidBody*>(bodyId);
if (body == NULL) { if (body == NULL) {
jclass newExc = env->FindClass("java/lang/NullPointerException"); jclass newExc = env->FindClass("java/lang/NullPointerException");
env->ThrowNew(newExc, "The native object does not exist."); env->ThrowNew(newExc, "The native object does not exist.");
return; return;
} }
btVector3 vec1 = btVector3(); btVector3 vec = btVector3();
vec1.setX(value); jmeBulletUtil::convert(env, factor, &vec);
vec1.setY(value); body->setAngularFactor(vec);
vec1.setZ(value);
body->setAngularFactor(vec1);
} }
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: getLinearFactor
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getLinearFactor
(JNIEnv *env, jobject object, jlong bodyId, jobject factor) {
btRigidBody* body = reinterpret_cast<btRigidBody*>(bodyId);
if (body == NULL) {
jclass newExc = env->FindClass("java/lang/NullPointerException");
env->ThrowNew(newExc, "The native object does not exist.");
return;
}
jmeBulletUtil::convert(env, &body->getLinearFactor(), factor);
}
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: setLinearFactor
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_setLinearFactor
(JNIEnv *env, jobject object, jlong bodyId, jobject factor) {
btRigidBody* body = reinterpret_cast<btRigidBody*>(bodyId);
if (body == NULL) {
jclass newExc = env->FindClass("java/lang/NullPointerException");
env->ThrowNew(newExc, "The native object does not exist.");
return;
}
btVector3 vec = btVector3();
jmeBulletUtil::convert(env, factor, &vec);
body->setLinearFactor(vec);
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

@ -396,18 +396,35 @@ JNIEXPORT jfloat JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngula
/* /*
* Class: com_jme3_bullet_objects_PhysicsRigidBody * Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: getAngularFactor * Method: getAngularFactor
* Signature: (J)F * Signature: (JLcom/jme3/math/Vector3f;)V
*/ */
JNIEXPORT jfloat JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor
(JNIEnv *, jobject, jlong); (JNIEnv *, jobject, jlong, jobject);
/* /*
* Class: com_jme3_bullet_objects_PhysicsRigidBody * Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: setAngularFactor * Method: setAngularFactor
* Signature: (JF)V * Signature: (JLcom/jme3/math/Vector3f;)V
*/ */
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_setAngularFactor JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_setAngularFactor
(JNIEnv *, jobject, jlong, jfloat); (JNIEnv *, jobject, jlong, jobject);
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: getLinearFactor
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getLinearFactor
(JNIEnv *, jobject, jlong, jobject);
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: setLinearFactor
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_setLinearFactor
(JNIEnv *, jobject, jlong, jobject);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -93,7 +93,9 @@ public class CapsuleCollisionShape extends CollisionShape{
*/ */
@Override @Override
public void setScale(Vector3f scale) { public void setScale(Vector3f scale) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "CapsuleCollisionShape cannot be scaled"); if (!scale.equals(Vector3f.UNIT_XYZ)) {
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "CapsuleCollisionShape cannot be scaled");
}
} }
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {

@ -627,16 +627,44 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
private native float getAngularSleepingThreshold(long objectId); private native float getAngularSleepingThreshold(long objectId);
public float getAngularFactor() { public float getAngularFactor() {
return getAngularFactor(objectId); return getAngularFactor(null).getX();
} }
private native float getAngularFactor(long objectId); public Vector3f getAngularFactor(Vector3f store) {
// doing like this prevent from breaking the API
if (store == null) {
store = new Vector3f();
}
getAngularFactor(objectId, store);
return store;
}
private native void getAngularFactor(long objectId, Vector3f vec);
public void setAngularFactor(float factor) { public void setAngularFactor(float factor) {
setAngularFactor(objectId, factor); setAngularFactor(objectId, new Vector3f(factor, factor, factor));
}
public void setAngularFactor(Vector3f factor) {
setAngularFactor(objectId, factor);
}
private native void setAngularFactor(long objectId, Vector3f factor);
public Vector3f getLinearFactor() {
Vector3f vec = new Vector3f();
getLinearFactor(objectId, vec);
return vec;
} }
private native void setAngularFactor(long objectId, float factor); private native void getLinearFactor(long objectId, Vector3f vec);
public void setLinearFactor(Vector3f factor) {
setLinearFactor(objectId, factor);
}
private native void setLinearFactor(long objectId, Vector3f factor);
/** /**
* do not use manually, joints are added automatically * do not use manually, joints are added automatically
@ -673,7 +701,13 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
capsule.write(getGravity(), "gravity", Vector3f.ZERO); capsule.write(getGravity(), "gravity", Vector3f.ZERO);
capsule.write(getFriction(), "friction", 0.5f); capsule.write(getFriction(), "friction", 0.5f);
capsule.write(getRestitution(), "restitution", 0); capsule.write(getRestitution(), "restitution", 0);
capsule.write(getAngularFactor(), "angularFactor", 1); Vector3f angularFactor = getAngularFactor(null);
if (angularFactor.x == angularFactor.y && angularFactor.y == angularFactor.z) {
capsule.write(getAngularFactor(), "angularFactor", 1);
} else {
capsule.write(getAngularFactor(null), "angularFactor", Vector3f.UNIT_XYZ);
capsule.write(getLinearFactor(), "linearFactor", Vector3f.UNIT_XYZ);
}
capsule.write(kinematic, "kinematic", false); capsule.write(kinematic, "kinematic", false);
capsule.write(getLinearDamping(), "linearDamping", 0); capsule.write(getLinearDamping(), "linearDamping", 0);
@ -703,7 +737,13 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
setKinematic(capsule.readBoolean("kinematic", false)); setKinematic(capsule.readBoolean("kinematic", false));
setRestitution(capsule.readFloat("restitution", 0)); setRestitution(capsule.readFloat("restitution", 0));
setAngularFactor(capsule.readFloat("angularFactor", 1)); Vector3f angularFactor = (Vector3f) capsule.readSavable("angularFactor", Vector3f.NAN.clone());
if(angularFactor == Vector3f.NAN) {
setAngularFactor(capsule.readFloat("angularFactor", 1));
} else {
setAngularFactor(angularFactor);
setLinearFactor((Vector3f) capsule.readSavable("linearFactor", Vector3f.UNIT_XYZ.clone()));
}
setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0)); setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0));
setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f)); setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f));
setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0)); setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));

@ -12,55 +12,23 @@ sourceSets {
} }
} }
buildscript { task updateVersionPropertiesFile << {
repositories { def verfile = file('src/main/resources/com/jme3/system/version.properties')
mavenCentral() verfile.text = "# THIS IS AN AUTO-GENERATED FILE..\n" +
} "# DO NOT MODIFY!\n" +
dependencies { "build.date=${jmeBuildDate}\n" +
classpath 'org.ajoberstar:gradle-git:1.0.0-rc.1' "git.revision=${jmeRevision}\n" +
} "git.branch=${jmeBranchName}\n" +
} "git.hash=${jmeGitHash}\n" +
"git.hash.short=${jmeShortGitHash}\n" +
import java.text.SimpleDateFormat "git.tag=${jmeGitTag}\n" +
import org.ajoberstar.grgit.* "name.full=jMonkeyEngine ${jmeFullVersion}\n" +
"version.full=${jmeFullVersion}\n" +
task updateVersion << { "version.number=${jmeVersion}\n" +
"version.tag=${jmeVersionTag}"
def verfile = file('src/main/java/com/jme3/system/JmeVersion.java')
def jmeGitHash
def jmeShortGitHash
def jmeBuildDate
def jmeBranchName
try {
def grgit = Grgit.open(project.file('.').parent)
jmeGitHash = grgit.head().id
jmeShortGitHash = grgit.head().abbreviatedId
jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date())
jmeBranchName = grgit.branch.current.name
} catch (ex) {
// Failed to get repo info
logger.warn("Failed to get repository info: " + ex.message + ". " + \
"Only partial build info will be generated.")
jmeGitHash = ""
jmeShortGitHash = ""
jmeBuildDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date())
jmeBranchName = "unknown"
}
verfile.text = "\npackage com.jme3.system;\n\n" +
"/**\n * THIS IS AN AUTO-GENERATED FILE..\n * DO NOT MODIFY!\n */\n" +
"public class JmeVersion {\n" +
" public static final String BUILD_DATE = \"${jmeBuildDate}\";\n" +
" public static final String BRANCH_NAME = \"${jmeBranchName}\";\n" +
" public static final String GIT_HASH = \"${jmeGitHash}\";\n" +
" public static final String GIT_SHORT_HASH = \"${jmeShortGitHash}\";\n" +
" public static final String FULL_NAME = \"jMonkeyEngine ${jmeVersion} (${jmeVersionTag})\";\n" +
"}\n"
} }
compileJava.dependsOn(updateVersion) compileJava.dependsOn(updateVersionPropertiesFile)
dependencies { dependencies {
} }

@ -553,7 +553,6 @@ public final class Bone implements Savable {
Vector3f translate = modelPos.add(rotate.mult(scale.mult(modelBindInversePos, tmp2), tmp2), tmp2); Vector3f translate = modelPos.add(rotate.mult(scale.mult(modelBindInversePos, tmp2), tmp2), tmp2);
// Populating the matrix // Populating the matrix
outTransform.loadIdentity();
outTransform.setTransform(translate, scale, rotate.toRotationMatrix(tmp4)); outTransform.setTransform(translate, scale, rotate.toRotationMatrix(tmp4));
} }

@ -82,7 +82,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
/** /**
* User wishes to use hardware skinning if available. * User wishes to use hardware skinning if available.
*/ */
private transient boolean hwSkinningDesired = false; private transient boolean hwSkinningDesired = true;
/** /**
* Hardware skinning is currently being used. * Hardware skinning is currently being used.
@ -347,11 +347,22 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
public Control cloneForSpatial(Spatial spatial) { public Control cloneForSpatial(Spatial spatial) {
Node clonedNode = (Node) spatial; Node clonedNode = (Node) spatial;
AnimControl ctrl = spatial.getControl(AnimControl.class);
SkeletonControl clone = new SkeletonControl(); SkeletonControl clone = new SkeletonControl();
clone.skeleton = ctrl.getSkeleton(); 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); clone.setSpatial(clonedNode);
// Fix attachments for the cloned node // Fix attachments for the cloned node

@ -60,7 +60,7 @@ import com.jme3.scene.control.Control;
*/ */
public class StatsView extends Node implements Control { public class StatsView extends Node implements Control {
private BitmapText[] labels; private BitmapText statText;
private Statistics statistics; private Statistics statistics;
private String[] statLabels; private String[] statLabels;
@ -81,20 +81,17 @@ public class StatsView extends Node implements Control {
statLabels = statistics.getLabels(); statLabels = statistics.getLabels();
statData = new int[statLabels.length]; statData = new int[statLabels.length];
labels = new BitmapText[statLabels.length];
BitmapFont font = manager.loadFont("Interface/Fonts/Console.fnt"); BitmapFont font = manager.loadFont("Interface/Fonts/Console.fnt");
for (int i = 0; i < labels.length; i++){ statText = new BitmapText(font);
labels[i] = new BitmapText(font); statText.setLocalTranslation(0, statText.getLineHeight() * statLabels.length, 0);
labels[i].setLocalTranslation(0, labels[i].getLineHeight() * (i+1), 0); attachChild(statText);
attachChild(labels[i]);
}
addControl(this); addControl(this);
} }
public float getHeight() { public float getHeight() {
return labels[0].getLineHeight() * statLabels.length; return statText.getLineHeight() * statLabels.length;
} }
public void update(float tpf) { public void update(float tpf) {
@ -103,11 +100,14 @@ public class StatsView extends Node implements Control {
return; return;
statistics.getData(statData); statistics.getData(statData);
for (int i = 0; i < labels.length; i++) { stringBuilder.setLength(0);
stringBuilder.setLength(0);
stringBuilder.append(statLabels[i]).append(" = ").append(statData[i]); // Need to walk through it backwards, as the first label
labels[i].setText(stringBuilder); // should appear at the bottom, not the top.
for (int i = statLabels.length - 1; i >= 0; i--) {
stringBuilder.append(statLabels[i]).append(" = ").append(statData[i]).append('\n');
} }
statText.setText(stringBuilder);
// Moved to ResetStatsState to make sure it is // Moved to ResetStatsState to make sure it is
// done even if there is no StatsView or the StatsView // done even if there is no StatsView or the StatsView

@ -77,7 +77,7 @@ public class AudioNode extends Node implements AudioSource {
protected transient volatile AudioSource.Status status = AudioSource.Status.Stopped; protected transient volatile AudioSource.Status status = AudioSource.Status.Stopped;
protected transient volatile int channel = -1; protected transient volatile int channel = -1;
protected Vector3f velocity = new Vector3f(); protected Vector3f velocity = new Vector3f();
protected boolean reverbEnabled = true; protected boolean reverbEnabled = false;
protected float maxDistance = 200; // 200 meters protected float maxDistance = 200; // 200 meters
protected float refDistance = 10; // 10 meters protected float refDistance = 10; // 10 meters
protected Filter reverbFilter; protected Filter reverbFilter;
@ -409,6 +409,14 @@ public class AudioNode extends Node implements AudioSource {
play(); play();
} }
} }
@Override
public float getPlaybackTime() {
if (channel >= 0)
return getRenderer().getSourcePlaybackTime(this);
else
return 0;
}
public Vector3f getPosition() { public Vector3f getPosition() {
return getWorldTranslation(); return getWorldTranslation();

@ -59,6 +59,7 @@ public interface AudioRenderer {
public void updateSourceParam(AudioSource src, AudioParam param); public void updateSourceParam(AudioSource src, AudioParam param);
public void updateListenerParam(Listener listener, ListenerParam param); public void updateListenerParam(Listener listener, ListenerParam param);
public float getSourcePlaybackTime(AudioSource src);
public void deleteFilter(Filter filter); public void deleteFilter(Filter filter);
public void deleteAudioData(AudioData ad); public void deleteAudioData(AudioData ad);

@ -95,6 +95,11 @@ public interface AudioSource {
* @return the time offset in the sound sample when to start playing. * @return the time offset in the sound sample when to start playing.
*/ */
public float getTimeOffset(); public float getTimeOffset();
/**
* @return the current playback position of the source in seconds.
*/
public float getPlaybackTime();
/** /**
* @return The velocity of the audio source. * @return The velocity of the audio source.

@ -54,6 +54,8 @@ public class AudioStream extends AudioData implements Closeable {
protected boolean eof = false; protected boolean eof = false;
protected int[] ids; protected int[] ids;
protected int unqueuedBuffersBytes = 0;
public AudioStream() { public AudioStream() {
super(); super();
} }
@ -196,10 +198,21 @@ public class AudioStream extends AudioData implements Closeable {
return in instanceof SeekableStream; return in instanceof SeekableStream;
} }
public int getUnqueuedBufferBytes() {
return unqueuedBuffersBytes;
}
public void setUnqueuedBufferBytes(int unqueuedBuffers) {
this.unqueuedBuffersBytes = unqueuedBuffers;
}
public void setTime(float time) { public void setTime(float time) {
if (in instanceof SeekableStream) { if (in instanceof SeekableStream) {
((SeekableStream) in).setTime(time); ((SeekableStream) in).setTime(time);
eof = false; eof = false;
// TODO: when we actually support seeking, this will need to be properly set.
unqueuedBuffersBytes = 0;
} else { } else {
throw new IllegalStateException( throw new IllegalStateException(
"Cannot use setTime on a stream that " "Cannot use setTime on a stream that "

@ -301,6 +301,58 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
f.clearUpdateNeeded(); f.clearUpdateNeeded();
} }
@Override
public float getSourcePlaybackTime(AudioSource src) {
checkDead();
synchronized (threadLock) {
if (audioDisabled) {
return 0;
}
// See comment in updateSourceParam().
if (src.getChannel() < 0) {
return 0;
}
int id = channels[src.getChannel()];
AudioData data = src.getAudioData();
int playbackOffsetBytes = 0;
if (data instanceof AudioStream) {
// Because audio streams are processed in buffer chunks,
// we have to compute the amount of time the stream was already
// been playing based on the number of buffers that were processed.
AudioStream stream = (AudioStream) data;
// NOTE: the assumption is that all enqueued buffers are the same size.
// this is currently enforced by fillBuffer().
// The number of unenqueued bytes that the decoder thread
// keeps track of.
int unqueuedBytes = stream.getUnqueuedBufferBytes();
// Additional processed buffers that the decoder thread
// did not unenqueue yet (it only updates 20 times per second).
int unqueuedBytesExtra = al.alGetSourcei(id, AL_BUFFERS_PROCESSED) * BUFFER_SIZE;
// Total additional bytes that need to be considered.
playbackOffsetBytes = unqueuedBytes; // + unqueuedBytesExtra;
}
// Add byte offset from source (for both streams and buffers)
playbackOffsetBytes += al.alGetSourcei(id, AL_BYTE_OFFSET);
// Compute time value from bytes
// E.g. for 44100 source with 2 channels and 16 bits per sample:
// (44100 * 2 * 16 / 8) = 176400
int bytesPerSecond = (data.getSampleRate() *
data.getChannels() *
data.getBitsPerSample() / 8);
return (float)playbackOffsetBytes / bytesPerSecond;
}
}
public void updateSourceParam(AudioSource src, AudioParam param) { public void updateSourceParam(AudioSource src, AudioParam param) {
checkDead(); checkDead();
synchronized (threadLock) { synchronized (threadLock) {
@ -648,6 +700,7 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
private boolean fillStreamingSource(int sourceId, AudioStream stream, boolean looping) { private boolean fillStreamingSource(int sourceId, AudioStream stream, boolean looping) {
boolean success = false; boolean success = false;
int processed = al.alGetSourcei(sourceId, AL_BUFFERS_PROCESSED); int processed = al.alGetSourcei(sourceId, AL_BUFFERS_PROCESSED);
int unqueuedBufferBytes = 0;
for (int i = 0; i < processed; i++) { for (int i = 0; i < processed; i++) {
int buffer; int buffer;
@ -656,6 +709,11 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
al.alSourceUnqueueBuffers(sourceId, 1, ib); al.alSourceUnqueueBuffers(sourceId, 1, ib);
buffer = ib.get(0); buffer = ib.get(0);
// XXX: assume that reading from AudioStream always
// gives BUFFER_SIZE amount of bytes! This might not always
// be the case...
unqueuedBufferBytes += BUFFER_SIZE;
boolean active = fillBuffer(stream, buffer); boolean active = fillBuffer(stream, buffer);
if (!active && !stream.isEOF()) { if (!active && !stream.isEOF()) {
@ -682,6 +740,8 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
break; break;
} }
} }
stream.setUnqueuedBufferBytes(stream.getUnqueuedBufferBytes() + unqueuedBufferBytes);
return success; return success;
} }

@ -702,7 +702,9 @@ public class Cinematic extends AbstractCinematicEvent implements AppState {
dispose(); dispose();
cinematicEvents.clear(); cinematicEvents.clear();
timeLine.clear(); timeLine.clear();
eventsData.clear(); if (eventsData != null) {
eventsData.clear();
}
} }
/** /**

@ -43,7 +43,7 @@ import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -431,15 +431,17 @@ public class AnimationEvent extends AbstractCinematicEvent {
@Override @Override
public void dispose() { public void dispose() {
super.dispose(); super.dispose();
Object o = cinematic.getEventData(MODEL_CHANNELS, model); if (cinematic != null) {
if (o != null) { Object o = cinematic.getEventData(MODEL_CHANNELS, model);
ArrayList<AnimChannel> list = (ArrayList<AnimChannel>) o; if (o != null) {
list.remove(channel); Collection<AnimChannel> values = ((HashMap<Integer, AnimChannel>) o).values();
if (list.isEmpty()) { while (values.remove(channel));
cinematic.removeEventData(MODEL_CHANNELS, model); if (values.isEmpty()) {
cinematic.removeEventData(MODEL_CHANNELS, model);
}
} }
cinematic = null;
channel = null;
} }
cinematic = null;
channel = null;
} }
} }

@ -48,6 +48,7 @@ import com.jme3.math.Vector3f;
import com.jme3.scene.CollisionData; import com.jme3.scene.CollisionData;
import com.jme3.scene.Mesh; import com.jme3.scene.Mesh;
import com.jme3.scene.Mesh.Mode; import com.jme3.scene.Mesh.Mode;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type; import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.mesh.IndexBuffer; import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.scene.mesh.VirtualIndexBuffer; import com.jme3.scene.mesh.VirtualIndexBuffer;
@ -114,8 +115,13 @@ public class BIHTree implements CollisionData {
bihSwapTmp = new float[9]; bihSwapTmp = new float[9];
FloatBuffer vb = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); VertexBuffer vBuffer = mesh.getBuffer(Type.Position);
if(vBuffer == null){
throw new IllegalArgumentException("A mesh should at least contain a Position buffer");
}
IndexBuffer ib = mesh.getIndexBuffer(); IndexBuffer ib = mesh.getIndexBuffer();
FloatBuffer vb = (FloatBuffer) vBuffer.getData();
if (ib == null) { if (ib == null) {
ib = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode()); ib = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode());
} else if (mesh.getMode() != Mode.Triangles) { } else if (mesh.getMode() != Mode.Triangles) {

@ -46,22 +46,18 @@ public interface JmeExporter {
* *
* @param object The savable to export * @param object The savable to export
* @param f The output stream * @param f The output stream
* @return Always returns true. If an error occurs during export,
* an exception is thrown
* @throws IOException If an io exception occurs during export * @throws IOException If an io exception occurs during export
*/ */
public boolean save(Savable object, OutputStream f) throws IOException; public void save(Savable object, OutputStream f) throws IOException;
/** /**
* Export the {@link Savable} to a file. * Export the {@link Savable} to a file.
* *
* @param object The savable to export * @param object The savable to export
* @param f The file to export to * @param f The file to export to
* @return Always returns true. If an error occurs during export,
* an exception is thrown
* @throws IOException If an io exception occurs during export * @throws IOException If an io exception occurs during export
*/ */
public boolean save(Savable object, File f) throws IOException; public void save(Savable object, File f) throws IOException;
/** /**
* Returns the {@link OutputCapsule} for the given savable object. * Returns the {@link OutputCapsule} for the given savable object.

@ -72,8 +72,10 @@ public class DefaultJoystickAxis implements JoystickAxis {
* @param negativeMapping The mapping to receive events when the axis is positive * @param negativeMapping The mapping to receive events when the axis is positive
*/ */
public void assignAxis(String positiveMapping, String negativeMapping){ public void assignAxis(String positiveMapping, String negativeMapping){
inputManager.addMapping(positiveMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, false)); if (axisIndex != -1) {
inputManager.addMapping(negativeMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, true)); inputManager.addMapping(positiveMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, false));
inputManager.addMapping(negativeMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, true));
}
} }
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012, 2015 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,6 +32,7 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
@ -49,6 +50,13 @@ import com.jme3.util.TempVars;
*/ */
public class AmbientLight extends Light { public class AmbientLight extends Light {
public AmbientLight() {
}
public AmbientLight(ColorRGBA color) {
super(color);
}
@Override @Override
public boolean intersectsBox(BoundingBox box, TempVars vars) { public boolean intersectsBox(BoundingBox box, TempVars vars) {
return true; return true;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012, 2015 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
@ -36,6 +36,7 @@ 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.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
@ -53,6 +54,30 @@ public class DirectionalLight extends Light {
protected Vector3f direction = new Vector3f(0f, -1f, 0f); protected Vector3f direction = new Vector3f(0f, -1f, 0f);
/**
* Creates a DirectionalLight
*/
public DirectionalLight() {
}
/**
* Creates a DirectionalLight with the given direction
* @param direction the light's direction
*/
public DirectionalLight(Vector3f direction) {
setDirection(direction);
}
/**
* Creates a DirectionalLight with the given direction and the given color
* @param direction the light's direction
* @param color the light's color
*/
public DirectionalLight(Vector3f direction, ColorRGBA color) {
super(color);
setDirection(direction);
}
@Override @Override
public void computeLastDistance(Spatial owner) { public void computeLastDistance(Spatial owner) {
lastDistance = 0; // directional lights are always closest to their owner lastDistance = 0; // directional lights are always closest to their owner
@ -77,7 +102,7 @@ public class DirectionalLight extends Light {
* *
* @param dir the direction of the light. * @param dir the direction of the light.
*/ */
public void setDirection(Vector3f dir){ public final void setDirection(Vector3f dir){
direction.set(dir); direction.set(dir);
if (!direction.isUnitVector()) { if (!direction.isUnitVector()) {
direction.normalizeLocal(); direction.normalizeLocal();

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012, 2015 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
@ -94,7 +94,7 @@ public abstract class Light implements Savable, Cloneable {
} }
} }
protected ColorRGBA color = new ColorRGBA(1f,1f,1f,1f); protected ColorRGBA color = new ColorRGBA(ColorRGBA.White);
/** /**
* Used in LightList for caching the distance * Used in LightList for caching the distance
@ -115,6 +115,13 @@ public abstract class Light implements Savable, Cloneable {
boolean frustumCheckNeeded = true; boolean frustumCheckNeeded = true;
boolean intersectsFrustum = false; boolean intersectsFrustum = false;
protected Light() {
}
protected Light(ColorRGBA color) {
setColor(color);
}
/** /**
* Returns the color of the light. * Returns the color of the light.
* *

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012, 2015 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,14 +32,13 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume; import com.jme3.bounding.BoundingVolume;
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.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Plane;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial; import com.jme3.scene.Spatial;
@ -62,6 +61,52 @@ public class PointLight extends Light {
protected float radius = 0; protected float radius = 0;
protected float invRadius = 0; protected float invRadius = 0;
/**
* Creates a PointLight
*/
public PointLight() {
}
/**
* Creates a PointLight at the given position
* @param position the position in world space
*/
public PointLight(Vector3f position) {
setPosition(position);
}
/**
* Creates a PointLight at the given position and with the given color
* @param position the position in world space
* @param color the light color
*/
public PointLight(Vector3f position, ColorRGBA color) {
super(color);
setPosition(position);
}
/**
* Creates a PointLight at the given position, with the given color and the
* given radius
* @param position the position in world space
* @param color the light color
* @param radius the light radius
*/
public PointLight(Vector3f position, ColorRGBA color, float radius) {
this(position, color);
setRadius(radius);
}
/**
* Creates a PointLight at the given position, with the given radius
* @param position the position in world space
* @param radius the light radius
*/
public PointLight(Vector3f position, float radius) {
this(position);
setRadius(radius);
}
@Override @Override
public void computeLastDistance(Spatial owner) { public void computeLastDistance(Spatial owner) {
if (owner.getWorldBound() != null) { if (owner.getWorldBound() != null) {
@ -88,7 +133,7 @@ public class PointLight extends Light {
* *
* @param position the world space position of the light. * @param position the world space position of the light.
*/ */
public void setPosition(Vector3f position) { public final void setPosition(Vector3f position) {
this.position.set(position); this.position.set(position);
} }
@ -115,13 +160,13 @@ public class PointLight extends Light {
* *
* @throws IllegalArgumentException If radius is negative * @throws IllegalArgumentException If radius is negative
*/ */
public void setRadius(float radius) { public final void setRadius(float radius) {
if (radius < 0) { if (radius < 0) {
throw new IllegalArgumentException("Light radius cannot be negative"); throw new IllegalArgumentException("Light radius cannot be negative");
} }
this.radius = radius; this.radius = radius;
if (radius != 0) { if (radius != 0f) {
this.invRadius = 1 / radius; this.invRadius = 1f / radius;
} else { } else {
this.invRadius = 0; this.invRadius = 0;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2012 jMonkeyEngine * Copyright (c) 2009-2012, 2015 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,6 +34,7 @@ package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingVolume; import com.jme3.bounding.BoundingVolume;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Plane; import com.jme3.math.Plane;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
@ -44,36 +45,121 @@ import java.io.IOException;
/** /**
* Represents a spot light. * Represents a spot light.
* A spot light emmit a cone of light from a position and in a direction. * A spot light emits a cone of light from a position and in a direction.
* It can be used to fake torch lights or car's lights. * It can be used to fake torch lights or cars' lights.
* <p> * <p>
* In addition to a position and a direction, spot lights also have a range which * In addition to a position and a direction, spot lights also have a range 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.
* Also the angle of the cone can be tweaked by changing the spot inner angle and the spot outer angle. * Also the angle of the cone can be tweaked by changing the spot inner angle and the spot outer angle.
* the spot inner angle determin the cone of light where light has full influence. * the spot inner angle determines the cone of light where light has full influence.
* the spot outer angle determin the cone global cone of light of the spot light. * the spot outer angle determines the cone global cone of light of the spot light.
* the light intensity slowly decrease between the inner cone and the outer cone. * the light intensity slowly decreases between the inner cone and the outer cone.
* @author Nehon * @author Nehon
*/ */
public class SpotLight extends Light { public class SpotLight extends Light {
protected Vector3f position = new Vector3f(); protected Vector3f position = new Vector3f();
protected Vector3f direction = new Vector3f(0,-1,0); protected Vector3f direction = new Vector3f(0, -1, 0);
protected float spotInnerAngle = FastMath.QUARTER_PI / 8; protected float spotInnerAngle = FastMath.QUARTER_PI / 8;
protected float spotOuterAngle = FastMath.QUARTER_PI / 6; protected float spotOuterAngle = FastMath.QUARTER_PI / 6;
protected float spotRange = 100; protected float spotRange = 100;
protected float invSpotRange = 1 / 100; protected float invSpotRange = 1f / 100;
protected float packedAngleCos=0; protected float packedAngleCos = 0;
protected float outerAngleCosSqr, outerAngleSinSqr; protected float outerAngleCosSqr, outerAngleSinSqr;
protected float outerAngleSinRcp, outerAngleSin, outerAngleCos; protected float outerAngleSinRcp, outerAngleSin, outerAngleCos;
/**
* Creates a SpotLight.
*/
public SpotLight() { public SpotLight() {
super(); super();
computeAngleParameters(); computeAngleParameters();
} }
/**
* Creates a SpotLight at the given position and with the given direction.
* @param position the position in world space.
* @param direction the direction of the light.
*/
public SpotLight(Vector3f position, Vector3f direction) {
this();
setPosition(position);
setDirection(direction);
}
/**
* Creates a SpotLight at the given position, with the given direction, and the
* given range.
* @param position the position in world space.
* @param direction the direction of the light.
* @param range the spot light range
*/
public SpotLight(Vector3f position, Vector3f direction, float range) {
this();
setPosition(position);
setDirection(direction);
this.spotRange = range;
}
/**
* Creates a SpotLight at the given position, with the given direction and
* the given color.
* @param position the position in world space.
* @param direction the direction of the light.
* @param color the light's color.
*/
public SpotLight(Vector3f position, Vector3f direction, ColorRGBA color) {
super(color);
computeAngleParameters();
setPosition(position);
setDirection(direction);
}
/**
* Creates a SpotLight at the given position, with the given direction,
* the given range and the given color.
* @param position the position in world space.
* @param direction the direction of the light.
* @param range the spot light range
* @param color the light's color.
*/
public SpotLight(Vector3f position, Vector3f direction, float range, ColorRGBA color) {
super(color);
computeAngleParameters();
setPosition(position);
setDirection(direction);
this.spotRange = range;
}
/**
* Creates a SpotLight at the given position, with the given direction,
* the given color and the given inner and outer angles
* (controls the falloff of the light)
*
* @param position the position in world space.
* @param direction the direction of the light.
* @param range the spot light range
* @param color the light's color.
* @param innerAngle the inner angle of the spot light.
* @param outerAngle the outer angle of the spot light.
*
* @see SpotLight#setSpotInnerAngle(float)
* @see SpotLight#setSpotOuterAngle(float)
*/
public SpotLight(Vector3f position, Vector3f direction, float range, ColorRGBA color, float innerAngle, float outerAngle) {
super(color);
this.spotInnerAngle = innerAngle;
this.spotOuterAngle = outerAngle;
computeAngleParameters();
setPosition(position);
setDirection(direction);
this.spotRange = range;
}
private void computeAngleParameters() { private void computeAngleParameters() {
float innerCos = FastMath.cos(spotInnerAngle); float innerCos = FastMath.cos(spotInnerAngle);
outerAngleCos = FastMath.cos(spotOuterAngle); outerAngleCos = FastMath.cos(spotOuterAngle);
@ -189,7 +275,7 @@ public class SpotLight extends Light {
return direction; return direction;
} }
public void setDirection(Vector3f direction) { public final void setDirection(Vector3f direction) {
this.direction.set(direction); this.direction.set(direction);
} }
@ -197,7 +283,7 @@ public class SpotLight extends Light {
return position; return position;
} }
public void setPosition(Vector3f position) { public final void setPosition(Vector3f position) {
this.position.set(position); this.position.set(position);
} }

@ -69,7 +69,7 @@ import java.util.logging.Logger;
* Setting the parameters can modify the behavior of a * Setting the parameters can modify the behavior of a
* shader. * shader.
* <p/> * <p/>
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public class Material implements CloneableSmartAsset, Cloneable, Savable { public class Material implements CloneableSmartAsset, Cloneable, Savable {
@ -146,7 +146,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* This method sets the name of the material. * This method sets the name of the material.
* The name is not the same as the asset name. * The name is not the same as the asset name.
@ -222,11 +222,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
} }
/** /**
* Compares two materials and returns true if they are equal. * Compares two materials and returns true if they are equal.
* This methods compare definition, parameters, additional render states. * This methods compare definition, parameters, additional render states.
* Since materials are mutable objects, implementing equals() properly is not possible, * Since materials are mutable objects, implementing equals() properly is not possible,
* hence the name contentEquals(). * hence the name contentEquals().
* *
* @param otherObj the material to compare to this material * @param otherObj the material to compare to this material
* @return true if the materials are equal. * @return true if the materials are equal.
*/ */
@ -234,15 +234,15 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
if (!(otherObj instanceof Material)) { if (!(otherObj instanceof Material)) {
return false; return false;
} }
Material other = (Material) otherObj; Material other = (Material) otherObj;
// Early exit if the material are the same object // Early exit if the material are the same object
if (this == other) { if (this == other) {
return true; return true;
} }
// Check material definition // Check material definition
if (this.getMaterialDef() != other.getMaterialDef()) { if (this.getMaterialDef() != other.getMaterialDef()) {
return false; return false;
} }
@ -251,12 +251,12 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
if (this.paramValues.size() != other.paramValues.size()) { if (this.paramValues.size() != other.paramValues.size()) {
return false; return false;
} }
// Checking technique // Checking technique
if (this.technique != null || other.technique != null) { if (this.technique != null || other.technique != null) {
// Techniques are considered equal if their names are the same // Techniques are considered equal if their names are the same
// E.g. if user chose custom technique for one material but // E.g. if user chose custom technique for one material but
// uses default technique for other material, the materials // uses default technique for other material, the materials
// are not equal. // are not equal.
String thisDefName = this.technique != null ? this.technique.getDef().getName() : "Default"; String thisDefName = this.technique != null ? this.technique.getDef().getName() : "Default";
String otherDefName = other.technique != null ? other.technique.getDef().getName() : "Default"; String otherDefName = other.technique != null ? other.technique.getDef().getName() : "Default";
@ -290,7 +290,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
return false; return false;
} }
} }
return true; return true;
} }
@ -305,7 +305,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
hash = 29 * hash + (this.additionalState != null ? this.additionalState.contentHashCode() : 0); hash = 29 * hash + (this.additionalState != null ? this.additionalState.contentHashCode() : 0);
return hash; return hash;
} }
/** /**
* Returns the currently active technique. * Returns the currently active technique.
* <p> * <p>
@ -436,7 +436,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
public Collection<MatParam> getParams() { public Collection<MatParam> getParams() {
return paramValues.values(); return paramValues.values();
} }
/** /**
* Returns the ListMap of all parameters set on this material. * Returns the ListMap of all parameters set on this material.
* *
@ -473,7 +473,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
*/ */
public void setParam(String name, VarType type, Object value) { public void setParam(String name, VarType type, Object value) {
checkSetParam(type, name); checkSetParam(type, name);
if (type.isTextureType()) { if (type.isTextureType()) {
setTextureParam(name, type, (Texture)value); setTextureParam(name, type, (Texture)value);
} else { } else {
@ -501,7 +501,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
if (matParam == null) { if (matParam == null) {
return; return;
} }
paramValues.remove(name); paramValues.remove(name);
if (matParam instanceof MatParamTexture) { if (matParam instanceof MatParamTexture) {
int texUnit = ((MatParamTexture) matParam).getUnit(); int texUnit = ((MatParamTexture) matParam).getUnit();
@ -728,7 +728,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
renderer.renderMesh(mesh, lodLevel, 1, null); renderer.renderMesh(mesh, lodLevel, 1, null);
} }
} }
/** /**
* Uploads the lights in the light list as two uniform arrays.<br/><br/> * * Uploads the lights in the light list as two uniform arrays.<br/><br/> *
* <p> * <p>
@ -747,30 +747,30 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
return 0; return 0;
} }
Uniform lightData = shader.getUniform("g_LightData"); Uniform lightData = shader.getUniform("g_LightData");
lightData.setVector4Length(numLights * 3);//8 lights * max 3 lightData.setVector4Length(numLights * 3);//8 lights * max 3
Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
if (startIndex != 0) {
if (startIndex != 0) {
// apply additive blending for 2nd and future passes // apply additive blending for 2nd and future passes
rm.getRenderer().applyRenderState(additiveLight); rm.getRenderer().applyRenderState(additiveLight);
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black); ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
}else{ }else{
ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList,true)); ambientColor.setValue(VarType.Vector4, getAmbientColor(lightList,true));
} }
int lightDataIndex = 0; int lightDataIndex = 0;
TempVars vars = TempVars.get(); TempVars vars = TempVars.get();
Vector4f tmpVec = vars.vect4f1; Vector4f tmpVec = vars.vect4f1;
int curIndex; int curIndex;
int endIndex = numLights + startIndex; int endIndex = numLights + startIndex;
for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) { for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
Light l = lightList.get(curIndex); Light l = lightList.get(curIndex);
if(l.getType() == Light.Type.Ambient){ if(l.getType() == Light.Type.Ambient){
endIndex++; endIndex++;
continue; continue;
} }
ColorRGBA color = l.getColor(); ColorRGBA color = l.getColor();
@ -781,14 +781,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
l.getType().getId(), l.getType().getId(),
lightDataIndex); lightDataIndex);
lightDataIndex++; lightDataIndex++;
switch (l.getType()) { switch (l.getType()) {
case Directional: case Directional:
DirectionalLight dl = (DirectionalLight) l; DirectionalLight dl = (DirectionalLight) l;
Vector3f dir = dl.getDirection(); Vector3f dir = dl.getDirection();
//Data directly sent in view space to avoid a matrix mult for each pixel //Data directly sent in view space to avoid a matrix mult for each pixel
tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f); tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f);
rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
// tmpVec.divideLocal(tmpVec.w); // tmpVec.divideLocal(tmpVec.w);
// tmpVec.normalizeLocal(); // tmpVec.normalizeLocal();
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex); lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex);
@ -802,7 +802,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
Vector3f pos = pl.getPosition(); Vector3f pos = pl.getPosition();
float invRadius = pl.getInvRadius(); float invRadius = pl.getInvRadius();
tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f); tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f);
rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
//tmpVec.divideLocal(tmpVec.w); //tmpVec.divideLocal(tmpVec.w);
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex); lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex);
lightDataIndex++; lightDataIndex++;
@ -810,37 +810,37 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
lightData.setVector4InArray(0,0,0,0, lightDataIndex); lightData.setVector4InArray(0,0,0,0, lightDataIndex);
lightDataIndex++; lightDataIndex++;
break; break;
case Spot: case Spot:
SpotLight sl = (SpotLight) l; SpotLight sl = (SpotLight) l;
Vector3f pos2 = sl.getPosition(); Vector3f pos2 = sl.getPosition();
Vector3f dir2 = sl.getDirection(); Vector3f dir2 = sl.getDirection();
float invRange = sl.getInvSpotRange(); float invRange = sl.getInvSpotRange();
float spotAngleCos = sl.getPackedAngleCos(); float spotAngleCos = sl.getPackedAngleCos();
tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f); tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f);
rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
// tmpVec.divideLocal(tmpVec.w); // tmpVec.divideLocal(tmpVec.w);
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex); lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex);
lightDataIndex++; lightDataIndex++;
//We transform the spot direction in view space here to save 5 varying later in the lighting shader //We transform the spot direction in view space here to save 5 varying later in the lighting shader
//one vec4 less and a vec4 that becomes a vec3 //one vec4 less and a vec4 that becomes a vec3
//the downside is that spotAngleCos decoding happens now in the frag shader. //the downside is that spotAngleCos decoding happens now in the frag shader.
tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f); tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f);
rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec); rm.getCurrentCamera().getViewMatrix().mult(tmpVec, tmpVec);
tmpVec.normalizeLocal(); tmpVec.normalizeLocal();
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex); lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex);
lightDataIndex++; lightDataIndex++;
break; break;
default: default:
throw new UnsupportedOperationException("Unknown type of light: " + l.getType()); throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
} }
} }
vars.release(); vars.release();
//Padding of unsued buffer space //Padding of unsued buffer space
while(lightDataIndex < numLights * 3) { while(lightDataIndex < numLights * 3) {
lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex); lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
lightDataIndex++; lightDataIndex++;
} }
return curIndex; return curIndex;
} }
@ -887,10 +887,10 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
case Directional: case Directional:
DirectionalLight dl = (DirectionalLight) l; DirectionalLight dl = (DirectionalLight) l;
Vector3f dir = dl.getDirection(); Vector3f dir = dl.getDirection();
//FIXME : there is an inconstency here due to backward //FIXME : there is an inconstency here due to backward
//compatibility of the lighting shader. //compatibility of the lighting shader.
//The directional light direction is passed in the //The directional light direction is passed in the
//LightPosition uniform. The lighting shader needs to be //LightPosition uniform. The lighting shader needs to be
//reworked though in order to fix this. //reworked though in order to fix this.
tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1); tmpLightPosition.set(dir.getX(), dir.getY(), dir.getZ(), -1);
lightPos.setValue(VarType.Vector4, tmpLightPosition); lightPos.setValue(VarType.Vector4, tmpLightPosition);
@ -987,11 +987,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
for (TechniqueDef techDef : techDefs) { for (TechniqueDef techDef : techDefs) {
if (rendererCaps.containsAll(techDef.getRequiredCaps())) { if (rendererCaps.containsAll(techDef.getRequiredCaps())) {
// use the first one that supports all the caps // use the first one that supports all the caps
tech = new Technique(this, techDef); tech = new Technique(this, techDef);
techniques.put(name, tech); techniques.put(name, tech);
if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() || if(tech.getDef().getLightMode() == renderManager.getPreferredLightMode() ||
tech.getDef().getLightMode() == LightMode.Disable){ tech.getDef().getLightMode() == LightMode.Disable){
break; break;
} }
} }
lastTech = techDef; lastTech = techDef;
@ -1078,7 +1078,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
Uniform u = uniforms.getValue(i); Uniform u = uniforms.getValue(i);
if (!u.isSetByCurrentMaterial()) { if (!u.isSetByCurrentMaterial()) {
if (u.getName().charAt(0) != 'g') { if (u.getName().charAt(0) != 'g') {
// Don't reset world globals! // Don't reset world globals!
// The benefits gained from this are very minimal // The benefits gained from this are very minimal
// and cause lots of matrix -> FloatBuffer conversions. // and cause lots of matrix -> FloatBuffer conversions.
u.clearValue(); u.clearValue();
@ -1093,21 +1093,21 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
* <p> * <p>
* The material is rendered as follows: * The material is rendered as follows:
* <ul> * <ul>
* <li>Determine which technique to use to render the material - * <li>Determine which technique to use to render the material -
* either what the user selected via * either what the user selected via
* {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager) * {@link #selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
* Material.selectTechnique()}, * Material.selectTechnique()},
* or the first default technique that the renderer supports * or the first default technique that the renderer supports
* (based on the technique's {@link TechniqueDef#getRequiredCaps() requested rendering capabilities})<ul> * (based on the technique's {@link TechniqueDef#getRequiredCaps() requested rendering capabilities})<ul>
* <li>If the technique has been changed since the last frame, then it is notified via * <li>If the technique has been changed since the last frame, then it is notified via
* {@link Technique#makeCurrent(com.jme3.asset.AssetManager, boolean, java.util.EnumSet) * {@link Technique#makeCurrent(com.jme3.asset.AssetManager, boolean, java.util.EnumSet)
* Technique.makeCurrent()}. * Technique.makeCurrent()}.
* If the technique wants to use a shader to render the model, it should load it at this part - * If the technique wants to use a shader to render the model, it should load it at this part -
* the shader should have all the proper defines as declared in the technique definition, * the shader should have all the proper defines as declared in the technique definition,
* including those that are bound to material parameters. * including those that are bound to material parameters.
* The technique can re-use the shader from the last frame if * The technique can re-use the shader from the last frame if
* no changes to the defines occurred.</li></ul> * no changes to the defines occurred.</li></ul>
* <li>Set the {@link RenderState} to use for rendering. The render states are * <li>Set the {@link RenderState} to use for rendering. The render states are
* applied in this order (later RenderStates override earlier RenderStates):<ol> * applied in this order (later RenderStates override earlier RenderStates):<ol>
* <li>{@link TechniqueDef#getRenderState() Technique Definition's RenderState} * <li>{@link TechniqueDef#getRenderState() Technique Definition's RenderState}
* - i.e. specific renderstate that is required for the shader.</li> * - i.e. specific renderstate that is required for the shader.</li>
@ -1120,22 +1120,22 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
* <li>Uniforms bound to material parameters are updated based on the current material parameter values.</li> * <li>Uniforms bound to material parameters are updated based on the current material parameter values.</li>
* <li>Uniforms bound to world parameters are updated from the RenderManager. * <li>Uniforms bound to world parameters are updated from the RenderManager.
* Internally {@link UniformBindingManager} is used for this task.</li> * Internally {@link UniformBindingManager} is used for this task.</li>
* <li>Uniforms bound to textures will cause the texture to be uploaded as necessary. * <li>Uniforms bound to textures will cause the texture to be uploaded as necessary.
* The uniform is set to the texture unit where the texture is bound.</li></ul> * The uniform is set to the texture unit where the texture is bound.</li></ul>
* <li>If the technique uses a shader, the model is then rendered according * <li>If the technique uses a shader, the model is then rendered according
* to the lighting mode specified on the technique definition.<ul> * to the lighting mode specified on the technique definition.<ul>
* <li>{@link LightMode#SinglePass single pass light mode} fills the shader's light uniform arrays * <li>{@link LightMode#SinglePass single pass light mode} fills the shader's light uniform arrays
* with the first 4 lights and renders the model once.</li> * with the first 4 lights and renders the model once.</li>
* <li>{@link LightMode#MultiPass multi pass light mode} light mode renders the model multiple times, * <li>{@link LightMode#MultiPass multi pass light mode} light mode renders the model multiple times,
* for the first light it is rendered opaque, on subsequent lights it is * for the first light it is rendered opaque, on subsequent lights it is
* rendered with {@link BlendMode#AlphaAdditive alpha-additive} blending and depth writing disabled.</li> * rendered with {@link BlendMode#AlphaAdditive alpha-additive} blending and depth writing disabled.</li>
* </ul> * </ul>
* <li>For techniques that do not use shaders, * <li>For techniques that do not use shaders,
* fixed function OpenGL is used to render the model (see {@link GL1Renderer} interface):<ul> * fixed function OpenGL is used to render the model (see {@link GL1Renderer} interface):<ul>
* <li>OpenGL state ({@link FixedFuncBinding}) that is bound to material parameters is updated. </li> * <li>OpenGL state ({@link FixedFuncBinding}) that is bound to material parameters is updated. </li>
* <li>The texture set on the material is uploaded and bound. * <li>The texture set on the material is uploaded and bound.
* Currently only 1 texture is supported for fixed function techniques.</li> * Currently only 1 texture is supported for fixed function techniques.</li>
* <li>If the technique uses lighting, then OpenGL lighting state is updated * <li>If the technique uses lighting, then OpenGL lighting state is updated
* based on the light list on the geometry, otherwise OpenGL lighting is disabled.</li> * based on the light list on the geometry, otherwise OpenGL lighting is disabled.</li>
* <li>The mesh is uploaded and rendered.</li> * <li>The mesh is uploaded and rendered.</li>
* </ul> * </ul>
@ -1147,10 +1147,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
*/ */
public void render(Geometry geom, LightList lights, RenderManager rm) { public void render(Geometry geom, LightList lights, RenderManager rm) {
autoSelectTechnique(rm); autoSelectTechnique(rm);
TechniqueDef techDef = technique.getDef();
Renderer r = rm.getRenderer(); if (techDef.isNoRender()) return;
TechniqueDef techDef = technique.getDef(); Renderer r = rm.getRenderer();
if (rm.getForcedRenderState() != null) { if (rm.getForcedRenderState() != null) {
r.applyRenderState(rm.getForcedRenderState()); r.applyRenderState(rm.getForcedRenderState());
@ -1169,7 +1170,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
// reset unchanged uniform flag // reset unchanged uniform flag
clearUniformsSetByCurrent(technique.getShader()); clearUniformsSetByCurrent(technique.getShader());
rm.updateUniformBindings(technique.getWorldBindUniforms()); rm.updateUniformBindings(technique.getWorldBindUniforms());
// setup textures and uniforms // setup textures and uniforms
for (int i = 0; i < paramValues.size(); i++) { for (int i = 0; i < paramValues.size(); i++) {
@ -1212,24 +1213,24 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
// any unset uniforms will be set to 0 // any unset uniforms will be set to 0
resetUniformsNotSetByCurrent(shader); resetUniformsNotSetByCurrent(shader);
r.setShader(shader); r.setShader(shader);
renderMeshFromGeometry(r, geom); renderMeshFromGeometry(r, geom);
} }
/** /**
* Called by {@link RenderManager} to render the geometry by * Called by {@link RenderManager} to render the geometry by
* using this material. * using this material.
* *
* Note that this version of the render method * Note that this version of the render method
* does not perform light filtering. * does not perform light filtering.
* *
* @param geom The geometry to render * @param geom The geometry to render
* @param rm The render manager requesting the rendering * @param rm The render manager requesting the rendering
*/ */
public void render(Geometry geom, RenderManager rm) { public void render(Geometry geom, RenderManager rm) {
render(geom, geom.getWorldLightList(), rm); render(geom, geom.getWorldLightList(), rm);
} }
public void write(JmeExporter ex) throws IOException { public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this); OutputCapsule oc = ex.getCapsule(this);
oc.write(def.getAssetName(), "material_def", null); oc.write(def.getAssetName(), "material_def", null);
@ -1304,14 +1305,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
continue; continue;
} }
} }
if (im.getFormatVersion() == 0 && param.getName().startsWith("m_")) { if (im.getFormatVersion() == 0 && param.getName().startsWith("m_")) {
// Ancient version of jME3 ... // Ancient version of jME3 ...
param.setName(param.getName().substring(2)); param.setName(param.getName().substring(2));
} }
if (def.getMaterialParam(param.getName()) == null) { if (def.getMaterialParam(param.getName()) == null) {
logger.log(Level.WARNING, "The material parameter is not defined: {0}. Ignoring..", logger.log(Level.WARNING, "The material parameter is not defined: {0}. Ignoring..",
param.getName()); param.getName());
} else { } else {
checkSetParam(param.getVarType(), param.getName()); checkSetParam(param.getVarType(), param.getName());

@ -40,7 +40,7 @@ import java.util.*;
/** /**
* Describes a technique definition. * Describes a technique definition.
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
public class TechniqueDef implements Savable { public class TechniqueDef implements Savable {
@ -49,7 +49,7 @@ public class TechniqueDef implements Savable {
* Version #1: Separate shader language for each shader source. * Version #1: Separate shader language for each shader source.
*/ */
public static final int SAVABLE_VERSION = 1; public static final int SAVABLE_VERSION = 1;
/** /**
* Describes light rendering mode. * Describes light rendering mode.
*/ */
@ -58,15 +58,15 @@ public class TechniqueDef implements Savable {
* Disable light-based rendering * Disable light-based rendering
*/ */
Disable, Disable,
/** /**
* Enable light rendering by using a single pass. * Enable light rendering by using a single pass.
* <p> * <p>
* An array of light positions and light colors is passed to the shader * An array of light positions and light colors is passed to the shader
* containing the world light list for the geometry being rendered. * containing the world light list for the geometry being rendered.
*/ */
SinglePass, SinglePass,
/** /**
* Enable light rendering by using multi-pass rendering. * Enable light rendering by using multi-pass rendering.
* <p> * <p>
@ -77,7 +77,7 @@ public class TechniqueDef implements Savable {
* passes have it set to black. * passes have it set to black.
*/ */
MultiPass, MultiPass,
/** /**
* @deprecated OpenGL1 is not supported anymore * @deprecated OpenGL1 is not supported anymore
*/ */
@ -96,15 +96,16 @@ public class TechniqueDef implements Savable {
private EnumMap<Shader.ShaderType,String> shaderLanguages; private EnumMap<Shader.ShaderType,String> shaderLanguages;
private EnumMap<Shader.ShaderType,String> shaderNames; private EnumMap<Shader.ShaderType,String> shaderNames;
private DefineList presetDefines; private DefineList presetDefines;
private boolean usesNodes = false; private boolean usesNodes = false;
private List<ShaderNode> shaderNodes; private List<ShaderNode> shaderNodes;
private ShaderGenerationInfo shaderGenerationInfo; private ShaderGenerationInfo shaderGenerationInfo;
private boolean noRender = false;
private RenderState renderState; private RenderState renderState;
private RenderState forcedRenderState; private RenderState forcedRenderState;
private LightMode lightMode = LightMode.Disable; private LightMode lightMode = LightMode.Disable;
private ShadowMode shadowMode = ShadowMode.Disable; private ShadowMode shadowMode = ShadowMode.Disable;
@ -115,7 +116,7 @@ public class TechniqueDef implements Savable {
* Creates a new technique definition. * Creates a new technique definition.
* <p> * <p>
* Used internally by the J3M/J3MD loader. * Used internally by the J3M/J3MD loader.
* *
* @param name The name of the technique, should be set to <code>null</code> * @param name The name of the technique, should be set to <code>null</code>
* for default techniques. * for default techniques.
*/ */
@ -135,7 +136,7 @@ public class TechniqueDef implements Savable {
/** /**
* Returns the name of this technique as specified in the J3MD file. * Returns the name of this technique as specified in the J3MD file.
* Default techniques have the name "Default". * Default techniques have the name "Default".
* *
* @return the name of this technique * @return the name of this technique
*/ */
public String getName(){ public String getName(){
@ -153,9 +154,9 @@ public class TechniqueDef implements Savable {
/** /**
* Set the light mode * Set the light mode
* *
* @param lightMode the light mode * @param lightMode the light mode
* *
* @see LightMode * @see LightMode
*/ */
public void setLightMode(LightMode lightMode) { public void setLightMode(LightMode lightMode) {
@ -172,9 +173,9 @@ public class TechniqueDef implements Savable {
/** /**
* Set the shadow mode. * Set the shadow mode.
* *
* @param shadowMode the shadow mode. * @param shadowMode the shadow mode.
* *
* @see ShadowMode * @see ShadowMode
*/ */
public void setShadowMode(ShadowMode shadowMode) { public void setShadowMode(ShadowMode shadowMode) {
@ -184,7 +185,7 @@ public class TechniqueDef implements Savable {
/** /**
* Returns the render state that this technique is using * Returns the render state that this technique is using
* @return the render state that this technique is using * @return the render state that this technique is using
* @see #setRenderState(com.jme3.material.RenderState) * @see #setRenderState(com.jme3.material.RenderState)
*/ */
public RenderState getRenderState() { public RenderState getRenderState() {
return renderState; return renderState;
@ -192,15 +193,37 @@ public class TechniqueDef implements Savable {
/** /**
* Sets the render state that this technique is using. * Sets the render state that this technique is using.
* *
* @param renderState the render state that this technique is using. * @param renderState the render state that this technique is using.
* *
* @see RenderState * @see RenderState
*/ */
public void setRenderState(RenderState renderState) { public void setRenderState(RenderState renderState) {
this.renderState = renderState; this.renderState = renderState;
} }
/**
* Sets if this technique should not be used to render.
*
* @param noRender not render or render ?
*
* @see NoRender
*/
public void setNoRender(boolean noRender) {
this.noRender = noRender;
}
/**
* Returns true if this technique should not be used to render.
* (eg. to not render a material with default technique)
*
* @return true if this technique should not be rendered, false otherwise.
*
*/
public boolean isNoRender(){
return noRender;
}
/** /**
* @deprecated jME3 always requires shaders now * @deprecated jME3 always requires shaders now
*/ */
@ -208,12 +231,12 @@ public class TechniqueDef implements Savable {
public boolean isUsingShaders(){ public boolean isUsingShaders(){
return true; return true;
} }
/** /**
* Returns true if this technique uses Shader Nodes, false otherwise. * Returns true if this technique uses Shader Nodes, false otherwise.
* *
* @return true if this technique uses Shader Nodes, false otherwise. * @return true if this technique uses Shader Nodes, false otherwise.
* *
*/ */
public boolean isUsingShaderNodes(){ public boolean isUsingShaderNodes(){
return usesNodes; return usesNodes;
@ -222,7 +245,7 @@ public class TechniqueDef implements Savable {
/** /**
* Gets the {@link Caps renderer capabilities} that are required * Gets the {@link Caps renderer capabilities} that are required
* by this technique. * by this technique.
* *
* @return the required renderer capabilities * @return the required renderer capabilities
*/ */
public EnumSet<Caps> getRequiredCaps() { public EnumSet<Caps> getRequiredCaps() {
@ -231,7 +254,7 @@ public class TechniqueDef implements Savable {
/** /**
* Sets the shaders that this technique definition will use. * Sets the shaders that this technique definition will use.
* *
* @param vertexShader The name of the vertex shader * @param vertexShader The name of the vertex shader
* @param fragmentShader The name of the fragment shader * @param fragmentShader The name of the fragment shader
* @param vertLanguage The vertex shader language * @param vertLanguage The vertex shader language
@ -242,7 +265,7 @@ public class TechniqueDef implements Savable {
this.shaderNames.put(Shader.ShaderType.Vertex, vertexShader); this.shaderNames.put(Shader.ShaderType.Vertex, vertexShader);
this.shaderLanguages.put(Shader.ShaderType.Fragment, fragLanguage); this.shaderLanguages.put(Shader.ShaderType.Fragment, fragLanguage);
this.shaderNames.put(Shader.ShaderType.Fragment, fragmentShader); this.shaderNames.put(Shader.ShaderType.Fragment, fragmentShader);
requiredCaps.clear(); requiredCaps.clear();
Caps vertCap = Caps.valueOf(vertLanguage); Caps vertCap = Caps.valueOf(vertLanguage);
requiredCaps.add(vertCap); requiredCaps.add(vertCap);
@ -259,17 +282,17 @@ public class TechniqueDef implements Savable {
*/ */
public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderNames, EnumMap<Shader.ShaderType, String> shaderLanguages) { public void setShaderFile(EnumMap<Shader.ShaderType, String> shaderNames, EnumMap<Shader.ShaderType, String> shaderLanguages) {
requiredCaps.clear(); requiredCaps.clear();
for (Shader.ShaderType shaderType : shaderNames.keySet()) { for (Shader.ShaderType shaderType : shaderNames.keySet()) {
String language = shaderLanguages.get(shaderType); String language = shaderLanguages.get(shaderType);
String shaderFile = shaderNames.get(shaderType); String shaderFile = shaderNames.get(shaderType);
this.shaderLanguages.put(shaderType, language); this.shaderLanguages.put(shaderType, language);
this.shaderNames.put(shaderType, shaderFile); this.shaderNames.put(shaderType, shaderFile);
Caps vertCap = Caps.valueOf(language); Caps vertCap = Caps.valueOf(language);
requiredCaps.add(vertCap); requiredCaps.add(vertCap);
if (shaderType.equals(Shader.ShaderType.Geometry)) { if (shaderType.equals(Shader.ShaderType.Geometry)) {
requiredCaps.add(Caps.GeometryShader); requiredCaps.add(Caps.GeometryShader);
} else if (shaderType.equals(Shader.ShaderType.TessellationControl)) { } else if (shaderType.equals(Shader.ShaderType.TessellationControl)) {
@ -280,11 +303,11 @@ public class TechniqueDef implements Savable {
/** /**
* Returns the define name which the given material parameter influences. * Returns the define name which the given material parameter influences.
* *
* @param paramName The parameter name to look up * @param paramName The parameter name to look up
* @return The define name * @return The define name
* *
* @see #addShaderParamDefine(java.lang.String, java.lang.String) * @see #addShaderParamDefine(java.lang.String, java.lang.String)
*/ */
public String getShaderParamDefine(String paramName){ public String getShaderParamDefine(String paramName){
if (defineParams == null) { if (defineParams == null) {
@ -297,11 +320,11 @@ public class TechniqueDef implements Savable {
* Adds a define linked to a material parameter. * Adds a define linked to a material parameter.
* <p> * <p>
* Any time the material parameter on the parent material is altered, * Any time the material parameter on the parent material is altered,
* the appropriate define on the technique will be modified as well. * the appropriate define on the technique will be modified as well.
* See the method * See the method
* {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) } * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
* on the exact details of how the material parameter changes the define. * on the exact details of how the material parameter changes the define.
* *
* @param paramName The name of the material parameter to link to. * @param paramName The name of the material parameter to link to.
* @param defineName The name of the define parameter, e.g. USE_LIGHTING * @param defineName The name of the define parameter, e.g. USE_LIGHTING
*/ */
@ -314,26 +337,26 @@ public class TechniqueDef implements Savable {
/** /**
* Returns the {@link DefineList} for the preset defines. * Returns the {@link DefineList} for the preset defines.
* *
* @return the {@link DefineList} for the preset defines. * @return the {@link DefineList} for the preset defines.
* *
* @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object) * @see #addShaderPresetDefine(java.lang.String, com.jme3.shader.VarType, java.lang.Object)
*/ */
public DefineList getShaderPresetDefines() { public DefineList getShaderPresetDefines() {
return presetDefines; return presetDefines;
} }
/** /**
* Adds a preset define. * Adds a preset define.
* <p> * <p>
* Preset defines do not depend upon any parameters to be activated, * Preset defines do not depend upon any parameters to be activated,
* they are always passed to the shader as long as this technique is used. * they are always passed to the shader as long as this technique is used.
* *
* @param defineName The name of the define parameter, e.g. USE_LIGHTING * @param defineName The name of the define parameter, e.g. USE_LIGHTING
* @param type The type of the define. See * @param type The type of the define. See
* {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) } * {@link DefineList#set(java.lang.String, com.jme3.shader.VarType, java.lang.Object) }
* to see why it matters. * to see why it matters.
* *
* @param value The value of the define * @param value The value of the define
*/ */
public void addShaderPresetDefine(String defineName, VarType type, Object value){ public void addShaderPresetDefine(String defineName, VarType type, Object value){
@ -346,18 +369,18 @@ public class TechniqueDef implements Savable {
/** /**
* Returns the name of the fragment shader used by the technique, or null * Returns the name of the fragment shader used by the technique, or null
* if no fragment shader is specified. * if no fragment shader is specified.
* *
* @return the name of the fragment shader to be used. * @return the name of the fragment shader to be used.
*/ */
public String getFragmentShaderName() { public String getFragmentShaderName() {
return shaderNames.get(Shader.ShaderType.Fragment); return shaderNames.get(Shader.ShaderType.Fragment);
} }
/** /**
* Returns the name of the vertex shader used by the technique, or null * Returns the name of the vertex shader used by the technique, or null
* if no vertex shader is specified. * if no vertex shader is specified.
* *
* @return the name of the vertex shader to be used. * @return the name of the vertex shader to be used.
*/ */
public String getVertexShaderName() { public String getVertexShaderName() {
@ -370,7 +393,7 @@ public class TechniqueDef implements Savable {
public String getFragmentShaderLanguage() { public String getFragmentShaderLanguage() {
return shaderLanguages.get(Shader.ShaderType.Fragment); return shaderLanguages.get(Shader.ShaderType.Fragment);
} }
/** /**
* Returns the language of the vertex shader used in this technique. * Returns the language of the vertex shader used in this technique.
*/ */
@ -390,10 +413,10 @@ public class TechniqueDef implements Savable {
public String getShaderProgramName(Shader.ShaderType shaderType){ public String getShaderProgramName(Shader.ShaderType shaderType){
return shaderNames.get(shaderType); return shaderNames.get(shaderType);
} }
/** /**
* Adds a new world parameter by the given name. * Adds a new world parameter by the given name.
* *
* @param name The world parameter to add. * @param name The world parameter to add.
* @return True if the world parameter name was found and added * @return True if the world parameter name was found and added
* to the list of world parameters, false otherwise. * to the list of world parameters, false otherwise.
@ -402,7 +425,7 @@ public class TechniqueDef implements Savable {
if (worldBinds == null){ if (worldBinds == null){
worldBinds = new ArrayList<UniformBinding>(); worldBinds = new ArrayList<UniformBinding>();
} }
try { try {
worldBinds.add( UniformBinding.valueOf(name) ); worldBinds.add( UniformBinding.valueOf(name) );
return true; return true;
@ -418,11 +441,11 @@ public class TechniqueDef implements Savable {
public void setForcedRenderState(RenderState forcedRenderState) { public void setForcedRenderState(RenderState forcedRenderState) {
this.forcedRenderState = forcedRenderState; this.forcedRenderState = forcedRenderState;
} }
/** /**
* Returns a list of world parameters that are used by this * Returns a list of world parameters that are used by this
* technique definition. * technique definition.
* *
* @return The list of world parameters * @return The list of world parameters
*/ */
public List<UniformBinding> getWorldBindings() { public List<UniformBinding> getWorldBindings() {
@ -448,10 +471,11 @@ public class TechniqueDef implements Savable {
oc.write(lightMode, "lightMode", LightMode.Disable); oc.write(lightMode, "lightMode", LightMode.Disable);
oc.write(shadowMode, "shadowMode", ShadowMode.Disable); oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
oc.write(renderState, "renderState", null); oc.write(renderState, "renderState", null);
oc.write(noRender, "noRender", false);
oc.write(usesNodes, "usesNodes", false); oc.write(usesNodes, "usesNodes", false);
oc.writeSavableArrayList((ArrayList)shaderNodes,"shaderNodes", null); oc.writeSavableArrayList((ArrayList)shaderNodes,"shaderNodes", null);
oc.write(shaderGenerationInfo, "shaderGenerationInfo", null); oc.write(shaderGenerationInfo, "shaderGenerationInfo", null);
// TODO: Finish this when Map<String, String> export is available // TODO: Finish this when Map<String, String> export is available
// oc.write(defineParams, "defineParams", null); // oc.write(defineParams, "defineParams", null);
// TODO: Finish this when List<Enum> export is available // TODO: Finish this when List<Enum> export is available
@ -470,7 +494,8 @@ public class TechniqueDef implements Savable {
lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable); lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable); shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
renderState = (RenderState) ic.readSavable("renderState", null); renderState = (RenderState) ic.readSavable("renderState", null);
noRender = ic.readBoolean("noRender", false);
if (ic.getSavableVersion(TechniqueDef.class) == 0) { if (ic.getSavableVersion(TechniqueDef.class) == 0) {
// Old version // Old version
shaderLanguages.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null)); shaderLanguages.put(Shader.ShaderType.Vertex,ic.readString("shaderLang", null));
@ -483,7 +508,7 @@ public class TechniqueDef implements Savable {
shaderLanguages.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlLanguage", null)); shaderLanguages.put(Shader.ShaderType.TessellationControl,ic.readString("tsctrlLanguage", null));
shaderLanguages.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalLanguage", null)); shaderLanguages.put(Shader.ShaderType.TessellationEvaluation,ic.readString("tsevalLanguage", null));
} }
usesNodes = ic.readBoolean("usesNodes", false); usesNodes = ic.readBoolean("usesNodes", false);
shaderNodes = ic.readSavableArrayList("shaderNodes", null); shaderNodes = ic.readSavableArrayList("shaderNodes", null);
shaderGenerationInfo = (ShaderGenerationInfo) ic.readSavable("shaderGenerationInfo", null); shaderGenerationInfo = (ShaderGenerationInfo) ic.readSavable("shaderGenerationInfo", null);
@ -525,6 +550,6 @@ public class TechniqueDef implements Savable {
//todo: make toString return something usefull //todo: make toString return something usefull
@Override @Override
public String toString() { public String toString() {
return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name /*+ ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage */+ ", presetDefines=" + presetDefines + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + '}'; return "TechniqueDef{" + "requiredCaps=" + requiredCaps + ", name=" + name /*+ ", vertName=" + vertName + ", fragName=" + fragName + ", vertLanguage=" + vertLanguage + ", fragLanguage=" + fragLanguage */+ ", presetDefines=" + presetDefines + ", usesNodes=" + usesNodes + ", shaderNodes=" + shaderNodes + ", shaderGenerationInfo=" + shaderGenerationInfo + ", renderState=" + renderState + ", forcedRenderState=" + forcedRenderState + ", lightMode=" + lightMode + ", shadowMode=" + shadowMode + ", defineParams=" + defineParams + ", worldBinds=" + worldBinds + ", noRender=" + noRender + '}';
} }
} }

@ -607,28 +607,28 @@ public final class ColorRGBA implements Savable, Cloneable, java.io.Serializable
} }
/** /**
* Get the color in sRGB color space as a Vector4f * Get the color in sRGB color space as a <code>ColorRGBA</code>.
* *
* Note that linear values stored in the ColorRGBA will be gamma corrected * Note that linear values stored in the ColorRGBA will be gamma corrected
* and returned as a Vector4f * and returned as a ColorRGBA.
* the x atribute will be fed with the r channel in sRGB space
* the y atribute will be fed with the g channel in sRGB space
* the z atribute will be fed with the b channel in sRGB space
* the w atribute will be fed with the a channel
* *
* Note that no correction will be performed on the alpha channel as it's * The x attribute will be fed with the r channel in sRGB space.
* conventionnally doesn't represent a color itself * The y attribute will be fed with the g channel in sRGB space.
* The z attribute will be fed with the b channel in sRGB space.
* The w attribute will be fed with the a channel.
* *
* @return the color in sRGB color space as a Vector4f * Note that no correction will be performed on the alpha channel as it
*/ * conventionally doesn't represent a color itself.
public Vector4f getAsSrgb(){ *
Vector4f srgb = new Vector4f(); * @return the color in sRGB color space as a ColorRGBA.
float invGama = 1f/GAMMA; */
srgb.x = (float)Math.pow(r, invGama); public ColorRGBA getAsSrgb() {
srgb.y = (float)Math.pow(g, invGama); ColorRGBA srgb = new ColorRGBA();
srgb.z = (float)Math.pow(b, invGama); float invGama = 1f / GAMMA;
srgb.w = a; srgb.r = (float) Math.pow(r, invGama);
srgb.g = (float) Math.pow(g, invGama);
srgb.b = (float) Math.pow(b, invGama);
srgb.a = a;
return srgb; return srgb;
} }

@ -154,53 +154,34 @@ public final class Matrix4f implements Savable, Cloneable, java.io.Serializable
} }
public void fromFrame(Vector3f location, Vector3f direction, Vector3f up, Vector3f left) { public void fromFrame(Vector3f location, Vector3f direction, Vector3f up, Vector3f left) {
loadIdentity();
TempVars vars = TempVars.get(); TempVars vars = TempVars.get();
try {
Vector3f f = vars.vect1.set(direction); Vector3f fwdVector = vars.vect1.set(direction);
Vector3f s = vars.vect2.set(f).crossLocal(up); Vector3f leftVector = vars.vect2.set(fwdVector).crossLocal(up);
Vector3f u = vars.vect3.set(s).crossLocal(f); Vector3f upVector = vars.vect3.set(leftVector).crossLocal(fwdVector);
// s.normalizeLocal();
// u.normalizeLocal(); m00 = leftVector.x;
m01 = leftVector.y;
m00 = s.x; m02 = leftVector.z;
m01 = s.y; m03 = -leftVector.dot(location);
m02 = s.z;
m10 = upVector.x;
m10 = u.x; m11 = upVector.y;
m11 = u.y; m12 = upVector.z;
m12 = u.z; m13 = -upVector.dot(location);
m20 = -f.x; m20 = -fwdVector.x;
m21 = -f.y; m21 = -fwdVector.y;
m22 = -f.z; m22 = -fwdVector.z;
m23 = fwdVector.dot(location);
// m00 = -left.x;
// m10 = -left.y; m30 = 0f;
// m20 = -left.z; m31 = 0f;
// m32 = 0f;
// m01 = up.x; m33 = 1f;
// m11 = up.y; } finally {
// m21 = up.z; vars.release();
// }
// m02 = -direction.x;
// m12 = -direction.y;
// m22 = -direction.z;
//
Matrix4f transMatrix = vars.tempMat4;
transMatrix.loadIdentity();
transMatrix.m03 = -location.x;
transMatrix.m13 = -location.y;
transMatrix.m23 = -location.z;
this.multLocal(transMatrix);
vars.release();
// transMatrix.multLocal(this);
// set(transMatrix);
} }
/** /**

@ -49,7 +49,7 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
private Quaternion rot = new Quaternion(); private Quaternion rot = new Quaternion();
private Vector3f translation = new Vector3f(); private Vector3f translation = new Vector3f();
private Vector3f scale = new Vector3f(1,1,1); private Vector3f scale = new Vector3f(1, 1, 1);
public Transform(Vector3f translation, Quaternion rot){ public Transform(Vector3f translation, Quaternion rot){
this.translation.set(translation); this.translation.set(translation);
@ -283,9 +283,32 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
* Loads the identity. Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1. * Loads the identity. Equal to translation=0,0,0 scale=1,1,1 rot=0,0,0,1.
*/ */
public void loadIdentity() { public void loadIdentity() {
translation.set(0,0,0); translation.set(0, 0, 0);
scale.set(1,1,1); scale.set(1, 1, 1);
rot.set(0,0,0,1); rot.set(0, 0, 0, 1);
}
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + rot.hashCode();
hash = 89 * hash + translation.hashCode();
hash = 89 * hash + scale.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Transform other = (Transform) obj;
return this.translation.equals(other.translation)
&& this.scale.equals(other.scale)
&& this.rot.equals(other.rot);
} }
@Override @Override
@ -307,22 +330,21 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
return this; return this;
} }
@Override
public void write(JmeExporter e) throws IOException { public void write(JmeExporter e) throws IOException {
OutputCapsule capsule = e.getCapsule(this); OutputCapsule capsule = e.getCapsule(this);
capsule.write(rot, "rot", new Quaternion()); capsule.write(rot, "rot", Quaternion.IDENTITY);
capsule.write(translation, "translation", Vector3f.ZERO); capsule.write(translation, "translation", Vector3f.ZERO);
capsule.write(scale, "scale", Vector3f.UNIT_XYZ); capsule.write(scale, "scale", Vector3f.UNIT_XYZ);
} }
@Override
public void read(JmeImporter e) throws IOException { public void read(JmeImporter e) throws IOException {
InputCapsule capsule = e.getCapsule(this); InputCapsule capsule = e.getCapsule(this);
rot = (Quaternion)capsule.readSavable("rot", new Quaternion()); rot.set((Quaternion)capsule.readSavable("rot", Quaternion.IDENTITY));
translation = (Vector3f)capsule.readSavable("translation", null); translation.set((Vector3f)capsule.readSavable("translation", Vector3f.ZERO));
if( translation == null ) { scale.set((Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ));
translation = new Vector3f();
}
scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ);
} }
@Override @Override

@ -300,7 +300,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
public void postFrame(FrameBuffer out) { public void postFrame(FrameBuffer out) {
FrameBuffer sceneBuffer = renderFrameBuffer; FrameBuffer sceneBuffer = renderFrameBuffer;
if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL31)) { if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL32)) {
renderer.copyFrameBuffer(renderFrameBufferMS, renderFrameBuffer, true); renderer.copyFrameBuffer(renderFrameBufferMS, renderFrameBuffer, true);
} else if (renderFrameBufferMS != null) { } else if (renderFrameBufferMS != null) {
sceneBuffer = renderFrameBufferMS; sceneBuffer = renderFrameBufferMS;
@ -443,7 +443,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
//antialiasing on filters only supported in opengl 3 due to depth read problem //antialiasing on filters only supported in opengl 3 due to depth read problem
if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample)) { if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample)) {
renderFrameBufferMS = new FrameBuffer(width, height, numSamples); renderFrameBufferMS = new FrameBuffer(width, height, numSamples);
if (caps.contains(Caps.OpenGL31)) { if (caps.contains(Caps.OpenGL32)) {
Texture2D msColor = new Texture2D(width, height, numSamples, fbFormat); Texture2D msColor = new Texture2D(width, height, numSamples, fbFormat);
Texture2D msDepth = new Texture2D(width, height, numSamples, Format.Depth); Texture2D msDepth = new Texture2D(width, height, numSamples, Format.Depth);
renderFrameBufferMS.setDepthTexture(msDepth); renderFrameBufferMS.setDepthTexture(msDepth);
@ -456,7 +456,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
} }
} }
if (numSamples <= 1 || !caps.contains(Caps.OpenGL31)) { if (numSamples <= 1 || !caps.contains(Caps.OpenGL32)) {
renderFrameBuffer = new FrameBuffer(width, height, 1); renderFrameBuffer = new FrameBuffer(width, height, 1);
renderFrameBuffer.setDepthBuffer(Format.Depth); renderFrameBuffer.setDepthBuffer(Format.Depth);
filterTexture = new Texture2D(width, height, fbFormat); filterTexture = new Texture2D(width, height, fbFormat);

@ -75,4 +75,6 @@ public enum Limits {
ColorTextureSamples, ColorTextureSamples,
DepthTextureSamples, DepthTextureSamples,
VertexUniformVectors,
} }

@ -74,6 +74,7 @@ public interface GL {
public static final int GL_FRONT_AND_BACK = 0x408; public static final int GL_FRONT_AND_BACK = 0x408;
public static final int GL_GEQUAL = 0x206; public static final int GL_GEQUAL = 0x206;
public static final int GL_GREATER = 0x204; public static final int GL_GREATER = 0x204;
public static final int GL_GREEN = 0x1904;
public static final int GL_INCR = 0x1E02; public static final int GL_INCR = 0x1E02;
public static final int GL_INCR_WRAP = 0x8507; public static final int GL_INCR_WRAP = 0x8507;
public static final int GL_INFO_LOG_LENGTH = 0x8B84; public static final int GL_INFO_LOG_LENGTH = 0x8B84;
@ -99,6 +100,8 @@ public interface GL {
public static final int GL_MAX_TEXTURE_SIZE = 0xD33; public static final int GL_MAX_TEXTURE_SIZE = 0xD33;
public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869; public static final int GL_MAX_VERTEX_ATTRIBS = 0x8869;
public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C; public static final int GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C;
public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
public static final int GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB;
public static final int GL_MIRRORED_REPEAT = 0x8370; public static final int GL_MIRRORED_REPEAT = 0x8370;
public static final int GL_NEAREST = 0x2600; public static final int GL_NEAREST = 0x2600;
public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702; public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
@ -114,6 +117,7 @@ public interface GL {
public static final int GL_OUT_OF_MEMORY = 0x505; public static final int GL_OUT_OF_MEMORY = 0x505;
public static final int GL_POINTS = 0x0; public static final int GL_POINTS = 0x0;
public static final int GL_POLYGON_OFFSET_FILL = 0x8037; public static final int GL_POLYGON_OFFSET_FILL = 0x8037;
public static final int GL_RED = 0x1903;
public static final int GL_RENDERER = 0x1F01; public static final int GL_RENDERER = 0x1F01;
public static final int GL_REPEAT = 0x2901; public static final int GL_REPEAT = 0x2901;
public static final int GL_REPLACE = 0x1E01; public static final int GL_REPLACE = 0x1E01;
@ -157,6 +161,7 @@ public interface GL {
public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519; public static final int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A; public static final int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
public static final int GL_TEXTURE_BASE_LEVEL = 0x813C;
public static final int GL_TEXTURE_MAG_FILTER = 0x2800; public static final int GL_TEXTURE_MAG_FILTER = 0x2800;
public static final int GL_TEXTURE_MAX_LEVEL = 0x813D; public static final int GL_TEXTURE_MAX_LEVEL = 0x813D;
public static final int GL_TEXTURE_MIN_FILTER = 0x2801; public static final int GL_TEXTURE_MIN_FILTER = 0x2801;

@ -34,7 +34,7 @@ package com.jme3.renderer.opengl;
import java.nio.IntBuffer; import java.nio.IntBuffer;
/** /**
* GL functions only available on vanilla desktop OpenGL 3.0. * GL functions only available on vanilla desktop OpenGL 3.0+.
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */
@ -43,6 +43,17 @@ public interface GL3 extends GL2 {
public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A; public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A;
public static final int GL_GEOMETRY_SHADER = 0x8DD9; public static final int GL_GEOMETRY_SHADER = 0x8DD9;
public static final int GL_NUM_EXTENSIONS = 0x821D; public static final int GL_NUM_EXTENSIONS = 0x821D;
public static final int GL_R8 = 0x8229;
public static final int GL_R16F = 0x822D;
public static final int GL_R32F = 0x822E;
public static final int GL_RG16F = 0x822F;
public static final int GL_RG32F = 0x8230;
public static final int GL_RG = 0x8227;
public static final int GL_RG8 = 0x822B;
public static final int GL_TEXTURE_SWIZZLE_A = 0x8E45;
public static final int GL_TEXTURE_SWIZZLE_B = 0x8E44;
public static final int GL_TEXTURE_SWIZZLE_G = 0x8E43;
public static final int GL_TEXTURE_SWIZZLE_R = 0x8E42;
public void glBindFragDataLocation(int param1, int param2, String param3); /// GL3+ public void glBindFragDataLocation(int param1, int param2, String param3); /// GL3+
public void glBindVertexArray(int param1); /// GL3+ public void glBindVertexArray(int param1); /// GL3+

@ -34,7 +34,7 @@ package com.jme3.renderer.opengl;
import java.nio.IntBuffer; import java.nio.IntBuffer;
/** /**
* GL functions only available on vanilla desktop OpenGL 3.0. * GL functions only available on vanilla desktop OpenGL 4.0.
* *
* @author Kirill Vainer * @author Kirill Vainer
*/ */

@ -42,6 +42,7 @@ public final class GLImageFormat {
public final int format; public final int format;
public final int dataType; public final int dataType;
public final boolean compressed; public final boolean compressed;
public final boolean swizzleRequired;
/** /**
* Constructor for formats. * Constructor for formats.
@ -55,6 +56,7 @@ public final class GLImageFormat {
this.format = format; this.format = format;
this.dataType = dataType; this.dataType = dataType;
this.compressed = false; this.compressed = false;
this.swizzleRequired = false;
} }
/** /**
@ -63,11 +65,30 @@ public final class GLImageFormat {
* @param internalFormat OpenGL internal format * @param internalFormat OpenGL internal format
* @param format OpenGL format * @param format OpenGL format
* @param dataType OpenGL datatype * @param dataType OpenGL datatype
* @param compressed Format is compressed
*/ */
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) { public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) {
this.internalFormat = internalFormat; this.internalFormat = internalFormat;
this.format = format; this.format = format;
this.dataType = dataType; this.dataType = dataType;
this.compressed = compressed; this.compressed = compressed;
this.swizzleRequired = false;
}
/**
* Constructor for formats.
*
* @param internalFormat OpenGL internal format
* @param format OpenGL format
* @param dataType OpenGL datatype
* @param compressed Format is compressed
* @param swizzleRequired Need to use texture swizzle to upload texture
*/
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed, boolean swizzleRequired) {
this.internalFormat = internalFormat;
this.format = format;
this.dataType = dataType;
this.compressed = compressed;
this.swizzleRequired = swizzleRequired;
} }
} }

@ -52,6 +52,13 @@ public final class GLImageFormats {
formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType); formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType);
} }
private static void formatSwiz(GLImageFormat[][] formatToGL, Image.Format format,
int glInternalFormat,
int glFormat,
int glDataType){
formatToGL[0][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true);
}
private static void formatSrgb(GLImageFormat[][] formatToGL, Image.Format format, private static void formatSrgb(GLImageFormat[][] formatToGL, Image.Format format,
int glInternalFormat, int glInternalFormat,
int glFormat, int glFormat,
@ -60,6 +67,14 @@ public final class GLImageFormats {
formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType); formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType);
} }
private static void formatSrgbSwiz(GLImageFormat[][] formatToGL, Image.Format format,
int glInternalFormat,
int glFormat,
int glDataType)
{
formatToGL[1][format.ordinal()] = new GLImageFormat(glInternalFormat, glFormat, glDataType, false, true);
}
private static void formatComp(GLImageFormat[][] formatToGL, Image.Format format, private static void formatComp(GLImageFormat[][] formatToGL, Image.Format format,
int glCompressedFormat, int glCompressedFormat,
int glFormat, int glFormat,
@ -88,6 +103,19 @@ public final class GLImageFormats {
public static GLImageFormat[][] getFormatsForCaps(EnumSet<Caps> caps) { public static GLImageFormat[][] getFormatsForCaps(EnumSet<Caps> caps) {
GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length]; GLImageFormat[][] formatToGL = new GLImageFormat[2][Image.Format.values().length];
// Core Profile Formats (supported by both OpenGL Core 3.3 and OpenGL ES 3.0+)
if (caps.contains(Caps.CoreProfile)) {
formatSwiz(formatToGL, Format.Alpha8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE);
formatSwiz(formatToGL, Format.Luminance8, GL3.GL_R8, GL.GL_RED, GL.GL_UNSIGNED_BYTE);
formatSwiz(formatToGL, Format.Luminance8Alpha8, GL3.GL_RG8, GL3.GL_RG, GL.GL_UNSIGNED_BYTE);
formatSwiz(formatToGL, Format.Luminance16F, GL3.GL_R16F, GL.GL_RED, GLExt.GL_HALF_FLOAT_ARB);
formatSwiz(formatToGL, Format.Luminance32F, GL3.GL_R32F, GL.GL_RED, GL.GL_FLOAT);
formatSwiz(formatToGL, Format.Luminance16FAlpha16F, GL3.GL_RG16F, GL3.GL_RG, GLExt.GL_HALF_FLOAT_ARB);
formatSrgbSwiz(formatToGL, Format.Luminance8, GLExt.GL_SRGB8_EXT, GL.GL_RED, GL.GL_UNSIGNED_BYTE);
formatSrgbSwiz(formatToGL, Format.Luminance8Alpha8, GLExt.GL_SRGB8_ALPHA8_EXT, GL3.GL_RG, GL.GL_UNSIGNED_BYTE);
}
if (caps.contains(Caps.OpenGL20)) { if (caps.contains(Caps.OpenGL20)) {
if (!caps.contains(Caps.CoreProfile)) { if (!caps.contains(Caps.CoreProfile)) {
format(formatToGL, Format.Alpha8, GL2.GL_ALPHA8, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE); format(formatToGL, Format.Alpha8, GL2.GL_ALPHA8, GL.GL_ALPHA, GL.GL_UNSIGNED_BYTE);

@ -54,6 +54,7 @@ import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapAxis; import com.jme3.texture.Texture.WrapAxis;
import com.jme3.util.BufferUtils; import com.jme3.util.BufferUtils;
import com.jme3.util.ListMap; import com.jme3.util.ListMap;
import com.jme3.util.MipMapGenerator;
import com.jme3.util.NativeObjectManager; import com.jme3.util.NativeObjectManager;
import java.nio.*; import java.nio.*;
import java.util.Arrays; import java.util.Arrays;
@ -72,7 +73,7 @@ public class GLRenderer implements Renderer {
private static final Logger logger = Logger.getLogger(GLRenderer.class.getName()); private static final Logger logger = Logger.getLogger(GLRenderer.class.getName());
private static final boolean VALIDATE_SHADER = false; private static final boolean VALIDATE_SHADER = false;
private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*"); private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*");
private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250); private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250);
private final StringBuilder stringBuf = new StringBuilder(250); private final StringBuilder stringBuf = new StringBuilder(250);
private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1); private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1);
@ -82,22 +83,7 @@ public class GLRenderer implements Renderer {
private final NativeObjectManager objManager = new NativeObjectManager(); private final NativeObjectManager objManager = new NativeObjectManager();
private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class); private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.class);
private final EnumMap<Limits, Integer> limits = new EnumMap<Limits, Integer>(Limits.class); private final EnumMap<Limits, Integer> limits = new EnumMap<Limits, Integer>(Limits.class);
// private int vertexTextureUnits;
// private int fragTextureUnits;
// private int vertexUniforms;
// private int fragUniforms;
// private int vertexAttribs;
// private int maxFBOSamples;
// private int maxFBOAttachs;
// private int maxMRTFBOAttachs;
// private int maxRBSize;
// private int maxTexSize;
// private int maxCubeTexSize;
// private int maxVertCount;
// private int maxTriCount;
// private int maxColorTexSamples;
// private int maxDepthTexSamples;
private FrameBuffer mainFbOverride = null; private FrameBuffer mainFbOverride = null;
private final Statistics statistics = new Statistics(); private final Statistics statistics = new Statistics();
private int vpX, vpY, vpW, vpH; private int vpX, vpY, vpW, vpH;
@ -112,7 +98,7 @@ public class GLRenderer implements Renderer {
private final GLExt glext; private final GLExt glext;
private final GLFbo glfbo; private final GLFbo glfbo;
private final TextureUtil texUtil; private final TextureUtil texUtil;
public GLRenderer(GL gl, GLExt glext, GLFbo glfbo) { public GLRenderer(GL gl, GLExt glext, GLFbo glfbo) {
this.gl = gl; this.gl = gl;
this.gl2 = gl instanceof GL2 ? (GL2)gl : null; this.gl2 = gl instanceof GL2 ? (GL2)gl : null;
@ -120,7 +106,7 @@ public class GLRenderer implements Renderer {
this.gl4 = gl instanceof GL4 ? (GL4)gl : null; this.gl4 = gl instanceof GL4 ? (GL4)gl : null;
this.glfbo = glfbo; this.glfbo = glfbo;
this.glext = glext; this.glext = glext;
this.texUtil = new TextureUtil(gl, gl2, glext, context); this.texUtil = new TextureUtil(gl, gl2, glext);
} }
@Override @Override
@ -132,7 +118,7 @@ public class GLRenderer implements Renderer {
public EnumSet<Caps> getCaps() { public EnumSet<Caps> getCaps() {
return caps; return caps;
} }
// Not making public yet ... // Not making public yet ...
public EnumMap<Limits, Integer> getLimits() { public EnumMap<Limits, Integer> getLimits() {
return limits; return limits;
@ -154,7 +140,7 @@ public class GLRenderer implements Renderer {
} }
return extensionSet; return extensionSet;
} }
public static int extractVersion(String version) { public static int extractVersion(String version) {
Matcher m = GLVERSION_PATTERN.matcher(version); Matcher m = GLVERSION_PATTERN.matcher(version);
if (m.matches()) { if (m.matches()) {
@ -174,17 +160,17 @@ public class GLRenderer implements Renderer {
private boolean hasExtension(String extensionName) { private boolean hasExtension(String extensionName) {
return extensions.contains(extensionName); return extensions.contains(extensionName);
} }
private void loadCapabilitiesES() { private void loadCapabilitiesES() {
caps.add(Caps.GLSL100); caps.add(Caps.GLSL100);
caps.add(Caps.OpenGLES20); caps.add(Caps.OpenGLES20);
// Important: Do not add OpenGL20 - that's the desktop capability! // Important: Do not add OpenGL20 - that's the desktop capability!
} }
private void loadCapabilitiesGL2() { private void loadCapabilitiesGL2() {
int oglVer = extractVersion(gl.glGetString(GL.GL_VERSION)); int oglVer = extractVersion(gl.glGetString(GL.GL_VERSION));
if (oglVer >= 200) { if (oglVer >= 200) {
caps.add(Caps.OpenGL20); caps.add(Caps.OpenGL20);
if (oglVer >= 210) { if (oglVer >= 210) {
@ -208,9 +194,9 @@ public class GLRenderer implements Renderer {
} }
} }
} }
int glslVer = extractVersion(gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION)); int glslVer = extractVersion(gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION));
switch (glslVer) { switch (glslVer) {
default: default:
if (glslVer < 400) { if (glslVer < 400) {
@ -236,34 +222,34 @@ public class GLRenderer implements Renderer {
caps.add(Caps.GLSL100); caps.add(Caps.GLSL100);
break; break;
} }
// Workaround, always assume we support GLSL100 & GLSL110 // Workaround, always assume we support GLSL100 & GLSL110
// Supporting OpenGL 2.0 means supporting GLSL 1.10. // Supporting OpenGL 2.0 means supporting GLSL 1.10.
caps.add(Caps.GLSL110); caps.add(Caps.GLSL110);
caps.add(Caps.GLSL100); caps.add(Caps.GLSL100);
// Fix issue in TestRenderToMemory when GL.GL_FRONT is the main // Fix issue in TestRenderToMemory when GL.GL_FRONT is the main
// buffer being used. // buffer being used.
context.initialDrawBuf = getInteger(GL2.GL_DRAW_BUFFER); context.initialDrawBuf = getInteger(GL2.GL_DRAW_BUFFER);
context.initialReadBuf = getInteger(GL2.GL_READ_BUFFER); context.initialReadBuf = getInteger(GL2.GL_READ_BUFFER);
// XXX: This has to be GL.GL_BACK for canvas on Mac // XXX: This has to be GL.GL_BACK for canvas on Mac
// Since initialDrawBuf is GL.GL_FRONT for pbuffer, gotta // Since initialDrawBuf is GL.GL_FRONT for pbuffer, gotta
// change this value later on ... // change this value later on ...
// initialDrawBuf = GL.GL_BACK; // initialDrawBuf = GL.GL_BACK;
// initialReadBuf = GL.GL_BACK; // initialReadBuf = GL.GL_BACK;
} }
private void loadCapabilitiesCommon() { private void loadCapabilitiesCommon() {
extensions = loadExtensions(); extensions = loadExtensions();
limits.put(Limits.VertexTextureUnits, getInteger(GL.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)); limits.put(Limits.VertexTextureUnits, getInteger(GL.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS));
if (limits.get(Limits.VertexTextureUnits) > 0) { if (limits.get(Limits.VertexTextureUnits) > 0) {
caps.add(Caps.VertexTextureFetch); caps.add(Caps.VertexTextureFetch);
} }
limits.put(Limits.FragmentTextureUnits, getInteger(GL.GL_MAX_TEXTURE_IMAGE_UNITS)); limits.put(Limits.FragmentTextureUnits, getInteger(GL.GL_MAX_TEXTURE_IMAGE_UNITS));
// gl.glGetInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16); // gl.glGetInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS, intBuf16);
// vertexUniforms = intBuf16.get(0); // vertexUniforms = intBuf16.get(0);
// logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms); // logger.log(Level.FINER, "Vertex Uniforms: {0}", vertexUniforms);
@ -271,62 +257,66 @@ public class GLRenderer implements Renderer {
// gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16); // gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16);
// fragUniforms = intBuf16.get(0); // fragUniforms = intBuf16.get(0);
// logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms); // logger.log(Level.FINER, "Fragment Uniforms: {0}", fragUniforms);
if (caps.contains(Caps.OpenGLES20)) {
limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS));
} else {
limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4);
}
limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS)); limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS));
limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE)); limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE));
limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE)); limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE));
if (hasExtension("GL_ARB_draw_instanced") && if (hasExtension("GL_ARB_draw_instanced") &&
hasExtension("GL_ARB_instanced_arrays")) { hasExtension("GL_ARB_instanced_arrays")) {
caps.add(Caps.MeshInstancing); caps.add(Caps.MeshInstancing);
} }
if (hasExtension("GL_OES_element_index_uint") || gl2 != null) { if (hasExtension("GL_OES_element_index_uint") || gl2 != null) {
caps.add(Caps.IntegerIndexBuffer); caps.add(Caps.IntegerIndexBuffer);
} }
if (hasExtension("GL_ARB_texture_buffer_object")) { if (hasExtension("GL_ARB_texture_buffer_object")) {
caps.add(Caps.TextureBuffer); caps.add(Caps.TextureBuffer);
} }
// == texture format extensions == // == texture format extensions ==
boolean hasFloatTexture; boolean hasFloatTexture;
hasFloatTexture = hasExtension("GL_OES_texture_half_float") && hasFloatTexture = hasExtension("GL_OES_texture_half_float") &&
hasExtension("GL_OES_texture_float"); hasExtension("GL_OES_texture_float");
if (!hasFloatTexture) { if (!hasFloatTexture) {
hasFloatTexture = hasExtension("GL_ARB_texture_float") && hasFloatTexture = hasExtension("GL_ARB_texture_float") &&
hasExtension("GL_ARB_half_float_pixel"); hasExtension("GL_ARB_half_float_pixel");
if (!hasFloatTexture) { if (!hasFloatTexture) {
hasFloatTexture = caps.contains(Caps.OpenGL30); hasFloatTexture = caps.contains(Caps.OpenGL30);
} }
} }
if (hasFloatTexture) { if (hasFloatTexture) {
caps.add(Caps.FloatTexture); caps.add(Caps.FloatTexture);
} }
if (hasExtension("GL_OES_depth_texture") || gl2 != null) { if (hasExtension("GL_OES_depth_texture") || gl2 != null) {
caps.add(Caps.DepthTexture); caps.add(Caps.DepthTexture);
// TODO: GL_OES_depth24 // TODO: GL_OES_depth24
} }
if (hasExtension("GL_OES_rgb8_rgba8") || if (hasExtension("GL_OES_rgb8_rgba8") ||
hasExtension("GL_ARM_rgba8") || hasExtension("GL_ARM_rgba8") ||
hasExtension("GL_EXT_texture_format_BGRA8888")) { hasExtension("GL_EXT_texture_format_BGRA8888")) {
caps.add(Caps.Rgba8); caps.add(Caps.Rgba8);
} }
if (caps.contains(Caps.OpenGL30) || hasExtension("GL_OES_packed_depth_stencil")) { if (caps.contains(Caps.OpenGL30) || hasExtension("GL_OES_packed_depth_stencil")) {
caps.add(Caps.PackedDepthStencilBuffer); caps.add(Caps.PackedDepthStencilBuffer);
} }
if (hasExtension("GL_ARB_color_buffer_float") && if (hasExtension("GL_ARB_color_buffer_float") &&
hasExtension("GL_ARB_half_float_pixel")) { hasExtension("GL_ARB_half_float_pixel")) {
// XXX: Require both 16 and 32 bit float support for FloatColorBuffer. // XXX: Require both 16 and 32 bit float support for FloatColorBuffer.
caps.add(Caps.FloatColorBuffer); caps.add(Caps.FloatColorBuffer);
} }
@ -335,45 +325,44 @@ public class GLRenderer implements Renderer {
caps.add(Caps.FloatDepthBuffer); caps.add(Caps.FloatDepthBuffer);
} }
if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) || if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) ||
caps.contains(Caps.OpenGL30)) { caps.contains(Caps.OpenGL30)) {
// Either OpenGL3 is available or both packed_float & half_float_pixel. // Either OpenGL3 is available or both packed_float & half_float_pixel.
caps.add(Caps.PackedFloatColorBuffer); caps.add(Caps.PackedFloatColorBuffer);
caps.add(Caps.PackedFloatTexture); caps.add(Caps.PackedFloatTexture);
} }
if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) { if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) {
caps.add(Caps.SharedExponentTexture); caps.add(Caps.SharedExponentTexture);
} }
if (hasExtension("GL_EXT_texture_compression_s3tc")) { if (hasExtension("GL_EXT_texture_compression_s3tc")) {
caps.add(Caps.TextureCompressionS3TC); caps.add(Caps.TextureCompressionS3TC);
} }
if (hasExtension("GL_ARB_ES3_compatibility")) { if (hasExtension("GL_ARB_ES3_compatibility")) {
caps.add(Caps.TextureCompressionETC2); caps.add(Caps.TextureCompressionETC2);
caps.add(Caps.TextureCompressionETC1); caps.add(Caps.TextureCompressionETC1);
} else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) { } else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
caps.add(Caps.TextureCompressionETC1); caps.add(Caps.TextureCompressionETC1);
} }
// == end texture format extensions == // == end texture format extensions ==
if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) { if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30)) {
caps.add(Caps.VertexBufferArray); caps.add(Caps.VertexBufferArray);
} }
if (hasExtension("GL_ARB_texture_non_power_of_two") || if (hasExtension("GL_ARB_texture_non_power_of_two") ||
hasExtension("GL_OES_texture_npot") || hasExtension("GL_OES_texture_npot") ||
hasExtension("GL_APPLE_texture_2D_limited_npot") || caps.contains(Caps.OpenGL30)) {
caps.contains(Caps.OpenGL30)) {
caps.add(Caps.NonPowerOfTwoTextures); caps.add(Caps.NonPowerOfTwoTextures);
} else { } else {
logger.log(Level.WARNING, "Your graphics card does not " logger.log(Level.WARNING, "Your graphics card does not "
+ "support non-power-of-2 textures. " + "support non-power-of-2 textures. "
+ "Some features might not work."); + "Some features might not work.");
} }
if (caps.contains(Caps.OpenGLES20)) { if (caps.contains(Caps.OpenGLES20)) {
// OpenGL ES 2 has some limited support for NPOT textures // OpenGL ES 2 has some limited support for NPOT textures
caps.add(Caps.PartialNonPowerOfTwoTextures); caps.add(Caps.PartialNonPowerOfTwoTextures);
@ -387,16 +376,18 @@ public class GLRenderer implements Renderer {
caps.add(Caps.TextureFilterAnisotropic); caps.add(Caps.TextureFilterAnisotropic);
} }
if (hasExtension("GL_EXT_framebuffer_object") || gl3 != null) { if (hasExtension("GL_EXT_framebuffer_object")
|| gl3 != null
|| caps.contains(Caps.OpenGLES20)) {
caps.add(Caps.FrameBuffer); caps.add(Caps.FrameBuffer);
limits.put(Limits.RenderBufferSize, getInteger(GLFbo.GL_MAX_RENDERBUFFER_SIZE_EXT)); limits.put(Limits.RenderBufferSize, getInteger(GLFbo.GL_MAX_RENDERBUFFER_SIZE_EXT));
limits.put(Limits.FrameBufferAttachments, getInteger(GLFbo.GL_MAX_COLOR_ATTACHMENTS_EXT)); limits.put(Limits.FrameBufferAttachments, getInteger(GLFbo.GL_MAX_COLOR_ATTACHMENTS_EXT));
if (hasExtension("GL_EXT_framebuffer_blit")) { if (hasExtension("GL_EXT_framebuffer_blit")) {
caps.add(Caps.FrameBufferBlit); caps.add(Caps.FrameBufferBlit);
} }
if (hasExtension("GL_EXT_framebuffer_multisample")) { if (hasExtension("GL_EXT_framebuffer_multisample")) {
caps.add(Caps.FrameBufferMultisample); caps.add(Caps.FrameBufferMultisample);
limits.put(Limits.FrameBufferSamples, getInteger(GLExt.GL_MAX_SAMPLES_EXT)); limits.put(Limits.FrameBufferSamples, getInteger(GLExt.GL_MAX_SAMPLES_EXT));
@ -412,7 +403,7 @@ public class GLRenderer implements Renderer {
} }
} }
if (hasExtension("GL_ARB_draw_buffers")) { if (hasExtension("GL_ARB_draw_buffers") || gl3 != null) {
limits.put(Limits.FrameBufferMrtAttachments, getInteger(GLExt.GL_MAX_DRAW_BUFFERS_ARB)); limits.put(Limits.FrameBufferMrtAttachments, getInteger(GLExt.GL_MAX_DRAW_BUFFERS_ARB));
if (limits.get(Limits.FrameBufferMrtAttachments) > 1) { if (limits.get(Limits.FrameBufferMrtAttachments) > 1) {
caps.add(Caps.FrameBufferMRT); caps.add(Caps.FrameBufferMRT);
@ -434,10 +425,10 @@ public class GLRenderer implements Renderer {
} }
caps.add(Caps.Multisample); caps.add(Caps.Multisample);
} }
// Supports sRGB pipeline. // Supports sRGB pipeline.
if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB")) if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB"))
|| caps.contains(Caps.OpenGL30) ) { || caps.contains(Caps.OpenGL30) ) {
caps.add(Caps.Srgb); caps.add(Caps.Srgb);
} }
@ -445,33 +436,33 @@ public class GLRenderer implements Renderer {
if (hasExtension("GL_ARB_seamless_cube_map") || caps.contains(Caps.OpenGL32)) { if (hasExtension("GL_ARB_seamless_cube_map") || caps.contains(Caps.OpenGL32)) {
caps.add(Caps.SeamlessCubemap); caps.add(Caps.SeamlessCubemap);
} }
if (caps.contains(Caps.OpenGL32) && !hasExtension("GL_ARB_compatibility")) { if (caps.contains(Caps.OpenGL32) && !hasExtension("GL_ARB_compatibility")) {
caps.add(Caps.CoreProfile); caps.add(Caps.CoreProfile);
} }
if (hasExtension("GL_ARB_get_program_binary")) { if (hasExtension("GL_ARB_get_program_binary")) {
int binaryFormats = getInteger(GLExt.GL_NUM_PROGRAM_BINARY_FORMATS); int binaryFormats = getInteger(GLExt.GL_NUM_PROGRAM_BINARY_FORMATS);
if (binaryFormats > 0) { if (binaryFormats > 0) {
caps.add(Caps.BinaryShader); caps.add(Caps.BinaryShader);
} }
} }
// Print context information // Print context information
logger.log(Level.INFO, "OpenGL Renderer Information\n" + logger.log(Level.INFO, "OpenGL Renderer Information\n" +
" * Vendor: {0}\n" + " * Vendor: {0}\n" +
" * Renderer: {1}\n" + " * Renderer: {1}\n" +
" * OpenGL Version: {2}\n" + " * OpenGL Version: {2}\n" +
" * GLSL Version: {3}\n" + " * GLSL Version: {3}\n" +
" * Profile: {4}", " * Profile: {4}",
new Object[]{ new Object[]{
gl.glGetString(GL.GL_VENDOR), gl.glGetString(GL.GL_VENDOR),
gl.glGetString(GL.GL_RENDERER), gl.glGetString(GL.GL_RENDERER),
gl.glGetString(GL.GL_VERSION), gl.glGetString(GL.GL_VERSION),
gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION), gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION),
caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility" caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility"
}); });
// Print capabilities (if fine logging is enabled) // Print capabilities (if fine logging is enabled)
if (logger.isLoggable(Level.FINE)) { if (logger.isLoggable(Level.FINE)) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -482,10 +473,10 @@ public class GLRenderer implements Renderer {
} }
logger.log(Level.FINE, sb.toString()); logger.log(Level.FINE, sb.toString());
} }
texUtil.initialize(caps); texUtil.initialize(caps);
} }
private void loadCapabilities() { private void loadCapabilities() {
if (gl2 != null) { if (gl2 != null) {
loadCapabilitiesGL2(); loadCapabilitiesGL2();
@ -494,31 +485,31 @@ public class GLRenderer implements Renderer {
} }
loadCapabilitiesCommon(); loadCapabilitiesCommon();
} }
private int getInteger(int en) { private int getInteger(int en) {
intBuf16.clear(); intBuf16.clear();
gl.glGetInteger(en, intBuf16); gl.glGetInteger(en, intBuf16);
return intBuf16.get(0); return intBuf16.get(0);
} }
private boolean getBoolean(int en) { private boolean getBoolean(int en) {
gl.glGetBoolean(en, nameBuf); gl.glGetBoolean(en, nameBuf);
return nameBuf.get(0) != (byte)0; return nameBuf.get(0) != (byte)0;
} }
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
public void initialize() { public void initialize() {
loadCapabilities(); loadCapabilities();
// Initialize default state.. // Initialize default state..
gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1);
if (caps.contains(Caps.CoreProfile)) { if (caps.contains(Caps.CoreProfile)) {
// Core Profile requires VAO to be bound. // Core Profile requires VAO to be bound.
gl3.glGenVertexArrays(intBuf16); gl3.glGenVertexArrays(intBuf16);
int vaoId = intBuf16.get(0); int vaoId = intBuf16.get(0);
gl3.glBindVertexArray(vaoId); gl3.glBindVertexArray(vaoId);
} }
if (gl2 != null) { if (gl2 != null) {
gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE); gl2.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE);
if (!caps.contains(Caps.CoreProfile)) { if (!caps.contains(Caps.CoreProfile)) {
@ -551,8 +542,8 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Render State *| |* Render State *|
\*********************************************************************/ \*********************************************************************/
public void setDepthRange(float start, float end) { public void setDepthRange(float start, float end) {
gl.glDepthRange(start, end); gl.glDepthRange(start, end);
} }
@ -617,7 +608,7 @@ public class GLRenderer implements Renderer {
} }
if (state.isDepthTest() && !context.depthTestEnabled) { if (state.isDepthTest() && !context.depthTestEnabled) {
gl.glEnable(GL.GL_DEPTH_TEST); gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(convertTestFunction(context.depthFunc)); gl.glDepthFunc(convertTestFunction(context.depthFunc));
context.depthTestEnabled = true; context.depthTestEnabled = true;
} else if (!state.isDepthTest() && context.depthTestEnabled) { } else if (!state.isDepthTest() && context.depthTestEnabled) {
@ -729,7 +720,7 @@ public class GLRenderer implements Renderer {
case Color: case Color:
case Screen: case Screen:
gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR); gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR);
break; break;
case Exclusion: case Exclusion:
gl.glBlendFunc(GL.GL_ONE_MINUS_DST_COLOR, GL.GL_ONE_MINUS_SRC_COLOR); gl.glBlendFunc(GL.GL_ONE_MINUS_DST_COLOR, GL.GL_ONE_MINUS_SRC_COLOR);
break; break;
@ -830,8 +821,8 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Camera and World transforms *| |* Camera and World transforms *|
\*********************************************************************/ \*********************************************************************/
public void setViewPort(int x, int y, int w, int h) { public void setViewPort(int x, int y, int w, int h) {
if (x != vpX || vpY != y || vpW != w || vpH != h) { if (x != vpX || vpY != y || vpW != w || vpH != h) {
gl.glViewport(x, y, w, h); gl.glViewport(x, y, w, h);
@ -874,8 +865,8 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Shaders *| |* Shaders *|
\*********************************************************************/ \*********************************************************************/
protected void updateUniformLocation(Shader shader, Uniform uniform) { protected void updateUniformLocation(Shader shader, Uniform uniform) {
int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName()); int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName());
if (loc < 0) { if (loc < 0) {
@ -1055,12 +1046,12 @@ public class GLRenderer implements Renderer {
boolean gles2 = caps.contains(Caps.OpenGLES20); boolean gles2 = caps.contains(Caps.OpenGLES20);
String language = source.getLanguage(); String language = source.getLanguage();
if (gles2 && !language.equals("GLSL100")) { if (gles2 && !language.equals("GLSL100")) {
throw new RendererException("This shader cannot run in OpenGL ES 2. " throw new RendererException("This shader cannot run in OpenGL ES 2. "
+ "Only GLSL 1.00 shaders are supported."); + "Only GLSL 1.00 shaders are supported.");
} }
// Upload shader source. // Upload shader source.
// Merge the defines and source code. // Merge the defines and source code.
stringBuf.setLength(0); stringBuf.setLength(0);
@ -1075,6 +1066,9 @@ public class GLRenderer implements Renderer {
stringBuf.append("\n"); stringBuf.append("\n");
} else { } else {
if (gles2) { if (gles2) {
// request GLSL ES (1.00) when compiling under GLES2.
stringBuf.append("#version 100\n");
if (source.getType() == ShaderType.Fragment) { if (source.getType() == ShaderType.Fragment) {
// GLES2 requires precision qualifier. // GLES2 requires precision qualifier.
stringBuf.append("precision mediump float;\n"); stringBuf.append("precision mediump float;\n");
@ -1087,14 +1081,15 @@ public class GLRenderer implements Renderer {
} }
} }
} }
if (linearizeSrgbImages) { if (linearizeSrgbImages) {
stringBuf.append("#define SRGB 1\n"); stringBuf.append("#define SRGB 1\n");
} }
stringBuf.append("#define ").append(source.getType().name().toUpperCase()).append("_SHADER 1\n");
stringBuf.append(source.getDefines()); stringBuf.append(source.getDefines());
stringBuf.append(source.getSource()); stringBuf.append(source.getSource());
intBuf1.clear(); intBuf1.clear();
intBuf1.put(0, stringBuf.length()); intBuf1.put(0, stringBuf.length());
gl.glShaderSource(id, new String[]{ stringBuf.toString() }, intBuf1); gl.glShaderSource(id, new String[]{ stringBuf.toString() }, intBuf1);
@ -1152,7 +1147,7 @@ public class GLRenderer implements Renderer {
// If using GLSL 1.5, we bind the outputs for the user // If using GLSL 1.5, we bind the outputs for the user
// For versions 3.3 and up, user should use layout qualifiers instead. // For versions 3.3 and up, user should use layout qualifiers instead.
boolean bindFragDataRequired = false; boolean bindFragDataRequired = false;
for (ShaderSource source : shader.getSources()) { for (ShaderSource source : shader.getSources()) {
if (source.isUpdateNeeded()) { if (source.isUpdateNeeded()) {
updateShaderSourceData(source); updateShaderSourceData(source);
@ -1261,8 +1256,8 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Framebuffers *| |* Framebuffers *|
\*********************************************************************/ \*********************************************************************/
public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) { public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
copyFrameBuffer(src, dst, true); copyFrameBuffer(src, dst, true);
} }
@ -1417,7 +1412,7 @@ public class GLRenderer implements Renderer {
} else if (attachmentSlot < 0 || attachmentSlot >= 16) { } else if (attachmentSlot < 0 || attachmentSlot >= 16) {
throw new UnsupportedOperationException("Invalid FBO attachment slot: " + attachmentSlot); throw new UnsupportedOperationException("Invalid FBO attachment slot: " + attachmentSlot);
} }
return GLFbo.GL_COLOR_ATTACHMENT0_EXT + attachmentSlot; return GLFbo.GL_COLOR_ATTACHMENT0_EXT + attachmentSlot;
} }
@ -1427,8 +1422,8 @@ public class GLRenderer implements Renderer {
if (image.isUpdateNeeded()) { if (image.isUpdateNeeded()) {
// Check NPOT requirements // Check NPOT requirements
checkNonPowerOfTwo(tex); checkNonPowerOfTwo(tex);
updateTexImageData(image, tex.getType(), 0); updateTexImageData(image, tex.getType(), 0, false);
// NOTE: For depth textures, sets nearest/no-mips mode // NOTE: For depth textures, sets nearest/no-mips mode
// Required to fix "framebuffer unsupported" // Required to fix "framebuffer unsupported"
@ -1491,7 +1486,7 @@ public class GLRenderer implements Renderer {
} }
checkFrameBufferError(); checkFrameBufferError();
fb.clearUpdateNeeded(); fb.clearUpdateNeeded();
} }
@ -1584,7 +1579,7 @@ public class GLRenderer implements Renderer {
// update viewport to reflect framebuffer's resolution // update viewport to reflect framebuffer's resolution
setViewPort(0, 0, fb.getWidth(), fb.getHeight()); setViewPort(0, 0, fb.getWidth(), fb.getHeight());
if (context.boundFBO != fb.getId()) { if (context.boundFBO != fb.getId()) {
glfbo.glBindFramebufferEXT(GLFbo.GL_FRAMEBUFFER_EXT, fb.getId()); glfbo.glBindFramebufferEXT(GLFbo.GL_FRAMEBUFFER_EXT, fb.getId());
statistics.onFrameBufferUse(fb, true); statistics.onFrameBufferUse(fb, true);
@ -1655,7 +1650,7 @@ public class GLRenderer implements Renderer {
public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) {
readFrameBufferWithGLFormat(fb, byteBuf, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); readFrameBufferWithGLFormat(fb, byteBuf, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE);
} }
private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int glFormat, int dataType) { private void readFrameBufferWithGLFormat(FrameBuffer fb, ByteBuffer byteBuf, int glFormat, int dataType) {
if (fb != null) { if (fb != null) {
RenderBuffer rb = fb.getColorBuffer(); RenderBuffer rb = fb.getColorBuffer();
@ -1677,8 +1672,8 @@ public class GLRenderer implements Renderer {
gl.glReadPixels(vpX, vpY, vpW, vpH, glFormat, dataType, byteBuf); gl.glReadPixels(vpX, vpY, vpW, vpH, glFormat, dataType, byteBuf);
} }
public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) { public void readFrameBufferWithFormat(FrameBuffer fb, ByteBuffer byteBuf, Image.Format format) {
GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false); GLImageFormat glFormat = texUtil.getImageFormatWithError(format, false);
readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType); readFrameBufferWithGLFormat(fb, byteBuf, glFormat.format, glFormat.dataType);
} }
@ -1711,14 +1706,14 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Textures *| |* Textures *|
\*********************************************************************/ \*********************************************************************/
private int convertTextureType(Texture.Type type, int samples, int face) { private int convertTextureType(Texture.Type type, int samples, int face) {
if (samples > 1 && !caps.contains(Caps.TextureMultisample)) { if (samples > 1 && !caps.contains(Caps.TextureMultisample)) {
throw new RendererException("Multisample textures are not supported" + throw new RendererException("Multisample textures are not supported" +
" by the video hardware."); " by the video hardware.");
} }
switch (type) { switch (type) {
case TwoDimensional: case TwoDimensional:
if (samples > 1) { if (samples > 1) {
@ -1738,8 +1733,8 @@ public class GLRenderer implements Renderer {
} }
case ThreeDimensional: case ThreeDimensional:
if (!caps.contains(Caps.OpenGL20)) { if (!caps.contains(Caps.OpenGL20)) {
throw new RendererException("3D textures are not supported" + throw new RendererException("3D textures are not supported" +
" by the video hardware."); " by the video hardware.");
} }
return GL2.GL_TEXTURE_3D; return GL2.GL_TEXTURE_3D;
case CubeMap: case CubeMap:
@ -1822,11 +1817,11 @@ public class GLRenderer implements Renderer {
int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1); int target = convertTextureType(tex.getType(), image != null ? image.getMultiSamples() : 1, -1);
boolean haveMips = true; boolean haveMips = true;
if (image != null) { if (image != null) {
haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps(); haveMips = image.isGeneratedMipmapsRequired() || image.hasMipmaps();
} }
// filter things // filter things
if (image.getLastTextureState().magFilter != tex.getMagFilter()) { if (image.getLastTextureState().magFilter != tex.getMagFilter()) {
int magFilter = convertMagFilter(tex.getMagFilter()); int magFilter = convertMagFilter(tex.getMagFilter());
@ -1849,7 +1844,7 @@ public class GLRenderer implements Renderer {
context.seamlessCubemap = false; context.seamlessCubemap = false;
} }
} }
if (tex.getAnisotropicFilter() > 1) { if (tex.getAnisotropicFilter() > 1) {
if (caps.contains(Caps.TextureFilterAnisotropic)) { if (caps.contains(Caps.TextureFilterAnisotropic)) {
gl.glTexParameterf(target, gl.glTexParameterf(target,
@ -1858,10 +1853,6 @@ public class GLRenderer implements Renderer {
} }
} }
if (context.pointSprite) {
return; // Attempt to fix glTexParameter crash for some ATI GPUs
}
// repeat modes // repeat modes
switch (tex.getType()) { switch (tex.getType()) {
case ThreeDimensional: case ThreeDimensional:
@ -1890,15 +1881,15 @@ public class GLRenderer implements Renderer {
// R to Texture compare mode // R to Texture compare mode
if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) { if (tex.getShadowCompareMode() != Texture.ShadowCompareMode.Off) {
gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE); gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL2.GL_COMPARE_R_TO_TEXTURE);
gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY); gl2.glTexParameteri(target, GL2.GL_DEPTH_TEXTURE_MODE, GL2.GL_INTENSITY);
if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual) { if (tex.getShadowCompareMode() == Texture.ShadowCompareMode.GreaterOrEqual) {
gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_GEQUAL); gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_GEQUAL);
} else { } else {
gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_LEQUAL); gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_FUNC, GL.GL_LEQUAL);
} }
}else{ }else{
//restoring default value //restoring default value
gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE); gl2.glTexParameteri(target, GL2.GL_TEXTURE_COMPARE_MODE, GL.GL_NONE);
} }
tex.compareModeUpdated(); tex.compareModeUpdated();
} }
@ -1910,7 +1901,7 @@ public class GLRenderer implements Renderer {
* Textures with power-of-2 dimensions are supported on all hardware, however * Textures with power-of-2 dimensions are supported on all hardware, however
* non-power-of-2 textures may or may not be supported depending on which * non-power-of-2 textures may or may not be supported depending on which
* texturing features are used. * texturing features are used.
* *
* @param tex The texture to validate. * @param tex The texture to validate.
* @throws RendererException If the texture is not supported by the hardware * @throws RendererException If the texture is not supported by the hardware
*/ */
@ -1919,23 +1910,23 @@ public class GLRenderer implements Renderer {
// Texture is power-of-2, safe to use. // Texture is power-of-2, safe to use.
return; return;
} }
if (caps.contains(Caps.NonPowerOfTwoTextures)) { if (caps.contains(Caps.NonPowerOfTwoTextures)) {
// Texture is NPOT but it is supported by video hardware. // Texture is NPOT but it is supported by video hardware.
return; return;
} }
// Maybe we have some / partial support for NPOT? // Maybe we have some / partial support for NPOT?
if (!caps.contains(Caps.PartialNonPowerOfTwoTextures)) { if (!caps.contains(Caps.PartialNonPowerOfTwoTextures)) {
// Cannot use any type of NPOT texture (uncommon) // Cannot use any type of NPOT texture (uncommon)
throw new RendererException("non-power-of-2 textures are not " throw new RendererException("non-power-of-2 textures are not "
+ "supported by the video hardware"); + "supported by the video hardware");
} }
// Partial NPOT supported.. // Partial NPOT supported..
if (tex.getMinFilter().usesMipMapLevels()) { if (tex.getMinFilter().usesMipMapLevels()) {
throw new RendererException("non-power-of-2 textures with mip-maps " throw new RendererException("non-power-of-2 textures with mip-maps "
+ "are not supported by the video hardware"); + "are not supported by the video hardware");
} }
switch (tex.getType()) { switch (tex.getType()) {
@ -1943,7 +1934,7 @@ public class GLRenderer implements Renderer {
case ThreeDimensional: case ThreeDimensional:
if (tex.getWrap(WrapAxis.R) != Texture.WrapMode.EdgeClamp) { if (tex.getWrap(WrapAxis.R) != Texture.WrapMode.EdgeClamp) {
throw new RendererException("repeating non-power-of-2 textures " throw new RendererException("repeating non-power-of-2 textures "
+ "are not supported by the video hardware"); + "are not supported by the video hardware");
} }
// fallthrough intentional!!! // fallthrough intentional!!!
case TwoDimensionalArray: case TwoDimensionalArray:
@ -1951,22 +1942,24 @@ public class GLRenderer implements Renderer {
if (tex.getWrap(WrapAxis.S) != Texture.WrapMode.EdgeClamp if (tex.getWrap(WrapAxis.S) != Texture.WrapMode.EdgeClamp
|| tex.getWrap(WrapAxis.T) != Texture.WrapMode.EdgeClamp) { || tex.getWrap(WrapAxis.T) != Texture.WrapMode.EdgeClamp) {
throw new RendererException("repeating non-power-of-2 textures " throw new RendererException("repeating non-power-of-2 textures "
+ "are not supported by the video hardware"); + "are not supported by the video hardware");
} }
break; break;
default: default:
throw new UnsupportedOperationException("unrecongized texture type"); throw new UnsupportedOperationException("unrecongized texture type");
} }
} }
/** /**
* Uploads the given image to the GL driver. * Uploads the given image to the GL driver.
* *
* @param img The image to upload * @param img The image to upload
* @param type How the data in the image argument should be interpreted. * @param type How the data in the image argument should be interpreted.
* @param unit The texture slot to be used to upload the image, not important * @param unit The texture slot to be used to upload the image, not important
* @param scaleToPot If true, the image will be scaled to power-of-2 dimensions
* before being uploaded.
*/ */
public void updateTexImageData(Image img, Texture.Type type, int unit) { public void updateTexImageData(Image img, Texture.Type type, int unit, boolean scaleToPot) {
int texId = img.getId(); int texId = img.getId();
if (texId == -1) { if (texId == -1) {
// create texture // create texture
@ -1985,7 +1978,7 @@ public class GLRenderer implements Renderer {
gl.glActiveTexture(GL.GL_TEXTURE0 + unit); gl.glActiveTexture(GL.GL_TEXTURE0 + unit);
context.boundTextureUnit = unit; context.boundTextureUnit = unit;
} }
gl.glBindTexture(target, texId); gl.glBindTexture(target, texId);
context.boundTextures[unit] = img; context.boundTextures[unit] = img;
@ -2028,12 +2021,12 @@ public class GLRenderer implements Renderer {
throw new RendererException("Multisample textures are not supported by the video hardware"); throw new RendererException("Multisample textures are not supported by the video hardware");
} }
} }
// Check if graphics card doesn't support depth textures // Check if graphics card doesn't support depth textures
if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) { if (img.getFormat().isDepthFormat() && !caps.contains(Caps.DepthTexture)) {
throw new RendererException("Depth textures are not supported by the video hardware"); throw new RendererException("Depth textures are not supported by the video hardware");
} }
if (target == GL.GL_TEXTURE_CUBE_MAP) { if (target == GL.GL_TEXTURE_CUBE_MAP) {
// Check max texture size before upload // Check max texture size before upload
int cubeSize = limits.get(Limits.CubemapSize); int cubeSize = limits.get(Limits.CubemapSize);
@ -2050,33 +2043,39 @@ public class GLRenderer implements Renderer {
} }
} }
Image imageForUpload;
if (scaleToPot) {
imageForUpload = MipMapGenerator.resizeToPowerOf2(img);
} else {
imageForUpload = img;
}
if (target == GL.GL_TEXTURE_CUBE_MAP) { if (target == GL.GL_TEXTURE_CUBE_MAP) {
List<ByteBuffer> data = img.getData(); List<ByteBuffer> data = imageForUpload.getData();
if (data.size() != 6) { if (data.size() != 6) {
logger.log(Level.WARNING, "Invalid texture: {0}\n" logger.log(Level.WARNING, "Invalid texture: {0}\n"
+ "Cubemap textures must contain 6 data units.", img); + "Cubemap textures must contain 6 data units.", img);
return; return;
} }
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
texUtil.uploadTexture(img, GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, linearizeSrgbImages); texUtil.uploadTexture(imageForUpload, GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, i, linearizeSrgbImages);
} }
} else if (target == GLExt.GL_TEXTURE_2D_ARRAY_EXT) { } else if (target == GLExt.GL_TEXTURE_2D_ARRAY_EXT) {
if (!caps.contains(Caps.TextureArray)) { if (!caps.contains(Caps.TextureArray)) {
throw new RendererException("Texture arrays not supported by graphics hardware"); throw new RendererException("Texture arrays not supported by graphics hardware");
} }
List<ByteBuffer> data = img.getData(); List<ByteBuffer> data = imageForUpload.getData();
// -1 index specifies prepare data for 2D Array // -1 index specifies prepare data for 2D Array
texUtil.uploadTexture(img, target, -1, linearizeSrgbImages); texUtil.uploadTexture(imageForUpload, target, -1, linearizeSrgbImages);
for (int i = 0; i < data.size(); i++) { for (int i = 0; i < data.size(); i++) {
// upload each slice of 2D array in turn // upload each slice of 2D array in turn
// this time with the appropriate index // this time with the appropriate index
texUtil.uploadTexture(img, target, i, linearizeSrgbImages); texUtil.uploadTexture(imageForUpload, target, i, linearizeSrgbImages);
} }
} else { } else {
texUtil.uploadTexture(img, target, 0, linearizeSrgbImages); texUtil.uploadTexture(imageForUpload, target, 0, linearizeSrgbImages);
} }
if (img.getMultiSamples() != imageSamples) { if (img.getMultiSamples() != imageSamples) {
@ -2097,9 +2096,23 @@ public class GLRenderer implements Renderer {
Image image = tex.getImage(); Image image = tex.getImage();
if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) { if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) {
// Check NPOT requirements // Check NPOT requirements
checkNonPowerOfTwo(tex); boolean scaleToPot = false;
updateTexImageData(image, tex.getType(), unit); try {
checkNonPowerOfTwo(tex);
} catch (RendererException ex) {
if (logger.isLoggable(Level.WARNING)) {
int nextWidth = FastMath.nearestPowerOfTwo(tex.getImage().getWidth());
int nextHeight = FastMath.nearestPowerOfTwo(tex.getImage().getHeight());
logger.log(Level.WARNING,
"Non-power-of-2 textures are not supported! Scaling texture '" + tex.getName() +
"' of size " + tex.getImage().getWidth() + "x" + tex.getImage().getHeight() +
" to " + nextWidth + "x" + nextHeight);
}
scaleToPot = true;
}
updateTexImageData(image, tex.getType(), unit, scaleToPot);
} }
int texId = image.getId(); int texId = image.getId();
@ -2144,8 +2157,8 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Vertex Buffers and Attributes *| |* Vertex Buffers and Attributes *|
\*********************************************************************/ \*********************************************************************/
private int convertUsage(Usage usage) { private int convertUsage(Usage usage) {
switch (usage) { switch (usage) {
case Static: case Static:
@ -2219,7 +2232,7 @@ public class GLRenderer implements Renderer {
//statistics.onVertexBufferUse(vb, false); //statistics.onVertexBufferUse(vb, false);
} }
} }
int usage = convertUsage(vb.getUsage()); int usage = convertUsage(vb.getUsage());
vb.getData().rewind(); vb.getData().rewind();
@ -2280,7 +2293,7 @@ public class GLRenderer implements Renderer {
if (context.boundShaderProgram <= 0) { if (context.boundShaderProgram <= 0) {
throw new IllegalStateException("Cannot render mesh without shader bound"); throw new IllegalStateException("Cannot render mesh without shader bound");
} }
Attribute attrib = context.boundShader.getAttribute(vb.getBufferType()); Attribute attrib = context.boundShader.getAttribute(vb.getBufferType());
int loc = attrib.getLocation(); int loc = attrib.getLocation();
if (loc == -1) { if (loc == -1) {
@ -2410,7 +2423,7 @@ public class GLRenderer implements Renderer {
// What is this? // What is this?
throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat()); throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat());
} }
if (indexBuf.isUpdateNeeded()) { if (indexBuf.isUpdateNeeded()) {
updateBufferData(indexBuf); updateBufferData(indexBuf);
} }
@ -2484,8 +2497,8 @@ public class GLRenderer implements Renderer {
} }
/*********************************************************************\ /*********************************************************************\
|* Render Calls *| |* Render Calls *|
\*********************************************************************/ \*********************************************************************/
public int convertElementMode(Mesh.Mode mode) { public int convertElementMode(Mesh.Mode mode) {
switch (mode) { switch (mode) {
case Points: case Points:
@ -2527,7 +2540,7 @@ public class GLRenderer implements Renderer {
if (interleavedData != null && interleavedData.isUpdateNeeded()) { if (interleavedData != null && interleavedData.isUpdateNeeded()) {
updateBufferData(interleavedData); updateBufferData(interleavedData);
} }
if (instanceData != null) { if (instanceData != null) {
setVertexAttrib(instanceData, null); setVertexAttrib(instanceData, null);
} }
@ -2577,11 +2590,11 @@ public class GLRenderer implements Renderer {
} }
private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) { private void renderMeshDefault(Mesh mesh, int lod, int count, VertexBuffer[] instanceData) {
// Here while count is still passed in. Can be removed when/if // Here while count is still passed in. Can be removed when/if
// the method is collapsed again. -pspeed // the method is collapsed again. -pspeed
count = Math.max(mesh.getInstanceCount(), count); count = Math.max(mesh.getInstanceCount(), count);
VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData); VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
if (interleavedData != null && interleavedData.isUpdateNeeded()) { if (interleavedData != null && interleavedData.isUpdateNeeded()) {
updateBufferData(interleavedData); updateBufferData(interleavedData);
@ -2599,7 +2612,7 @@ public class GLRenderer implements Renderer {
setVertexAttrib(vb, null); setVertexAttrib(vb, null);
} }
} }
for (VertexBuffer vb : mesh.getBufferList().getArray()) { for (VertexBuffer vb : mesh.getBufferList().getArray()) {
if (vb.getBufferType() == Type.InterleavedData if (vb.getBufferType() == Type.InterleavedData
|| vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers || vb.getUsage() == Usage.CpuOnly // ignore cpu-only buffers
@ -2634,7 +2647,7 @@ public class GLRenderer implements Renderer {
gl.glLineWidth(mesh.getLineWidth()); gl.glLineWidth(mesh.getLineWidth());
context.lineWidth = mesh.getLineWidth(); context.lineWidth = mesh.getLineWidth();
} }
if (gl4 != null && mesh.getMode().equals(Mode.Patch)) { if (gl4 != null && mesh.getMode().equals(Mode.Patch)) {
gl4.glPatchParameter(mesh.getPatchVertexCount()); gl4.glPatchParameter(mesh.getPatchVertexCount());
} }
@ -2648,14 +2661,14 @@ public class GLRenderer implements Renderer {
public void setMainFrameBufferSrgb(boolean enableSrgb) { public void setMainFrameBufferSrgb(boolean enableSrgb) {
// Gamma correction // Gamma correction
if (!caps.contains(Caps.Srgb)) { if (!caps.contains(Caps.Srgb) && enableSrgb) {
// Not supported, sorry. // Not supported, sorry.
logger.warning("sRGB framebuffer is not supported " + logger.warning("sRGB framebuffer is not supported " +
"by video hardware, but was requested."); "by video hardware, but was requested.");
return; return;
} }
setFrameBuffer(null); setFrameBuffer(null);
if (enableSrgb) { if (enableSrgb) {

@ -54,14 +54,12 @@ final class TextureUtil {
private final GL gl; private final GL gl;
private final GL2 gl2; private final GL2 gl2;
private final GLExt glext; private final GLExt glext;
private final RenderContext context;
private GLImageFormat[][] formats; private GLImageFormat[][] formats;
public TextureUtil(GL gl, GL2 gl2, GLExt glext, RenderContext context) { public TextureUtil(GL gl, GL2 gl2, GLExt glext) {
this.gl = gl; this.gl = gl;
this.gl2 = gl2; this.gl2 = gl2;
this.glext = glext; this.glext = glext;
this.context = context;
} }
public void initialize(EnumSet<Caps> caps) { public void initialize(EnumSet<Caps> caps) {
@ -92,9 +90,11 @@ final class TextureUtil {
} }
public GLImageFormat getImageFormatWithError(Format fmt, boolean isSrgb) { public GLImageFormat getImageFormatWithError(Format fmt, boolean isSrgb) {
//if the passed format is one kind of depth there isno point in getting the srgb format;
isSrgb = isSrgb && fmt != Format.Depth && fmt != Format.Depth16 && fmt != Format.Depth24 && fmt != Format.Depth24Stencil8 && fmt != Format.Depth32 && fmt != Format.Depth32F;
GLImageFormat glFmt = getImageFormat(fmt, isSrgb); GLImageFormat glFmt = getImageFormat(fmt, isSrgb);
if (glFmt == null && isSrgb) { if (glFmt == null && isSrgb) {
glFmt = getImageFormat(fmt, false); glFmt = getImageFormat(fmt, false);
logger.log(Level.WARNING, "No sRGB format available for ''{0}''. Failling back to linear.", fmt); logger.log(Level.WARNING, "No sRGB format available for ''{0}''. Failling back to linear.", fmt);
} }
if (glFmt == null) { if (glFmt == null) {
@ -103,6 +103,33 @@ final class TextureUtil {
return glFmt; return glFmt;
} }
private void setupTextureSwizzle(int target, Format format) {
// Needed for OpenGL 3.3 to support luminance / alpha formats
switch (format) {
case Alpha8:
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_ZERO);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_ZERO);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_ZERO);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_RED);
break;
case Luminance8:
case Luminance16F:
case Luminance32F:
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_RED);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_RED);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_ONE);
break;
case Luminance8Alpha8:
case Luminance16FAlpha16F:
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_R, GL.GL_RED);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_G, GL.GL_RED);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_B, GL.GL_RED);
gl.glTexParameteri(target, GL3.GL_TEXTURE_SWIZZLE_A, GL.GL_GREEN);
break;
}
}
private void uploadTextureLevel(GLImageFormat format, int target, int level, int slice, int sliceCount, int width, int height, int depth, int samples, ByteBuffer data) { private void uploadTextureLevel(GLImageFormat format, int target, int level, int slice, int sliceCount, int width, int height, int depth, int samples, ByteBuffer data) {
if (format.compressed && data != null) { if (format.compressed && data != null) {
if (target == GL2.GL_TEXTURE_3D) { if (target == GL2.GL_TEXTURE_3D) {
@ -242,6 +269,11 @@ final class TextureUtil {
} }
int samples = image.getMultiSamples(); int samples = image.getMultiSamples();
// For OGL3 core: setup texture swizzle.
if (oglFormat.swizzleRequired) {
setupTextureSwizzle(target, jmeFormat);
}
for (int i = 0; i < mipSizes.length; i++) { for (int i = 0; i < mipSizes.length; i++) {
int mipWidth = Math.max(1, width >> i); int mipWidth = Math.max(1, width >> i);

@ -119,19 +119,6 @@ public class BatchNode extends GeometryGroupNode {
setNeedsFullRebatch(true); setNeedsFullRebatch(true);
} }
@Override
public void updateGeometricState() {
if (!children.isEmpty()) {
for (Batch batch : batches.getArray()) {
if (batch.needMeshUpdate) {
batch.geometry.updateModelBound();
batch.geometry.updateWorldBound();
batch.needMeshUpdate = false;
}
}
}
super.updateGeometricState();
}
protected Matrix4f getTransformMatrix(Geometry g){ protected Matrix4f getTransformMatrix(Geometry g){
return g.cachedWorldMat; return g.cachedWorldMat;
@ -169,7 +156,7 @@ public class BatchNode extends GeometryGroupNode {
nvb.updateData(normBuf); nvb.updateData(normBuf);
batch.needMeshUpdate = true; batch.geometry.updateModelBound();
} }
} }
@ -234,7 +221,7 @@ public class BatchNode extends GeometryGroupNode {
batch.geometry.setMesh(m); batch.geometry.setMesh(m);
batch.geometry.getMesh().updateCounts(); batch.geometry.getMesh().updateCounts();
batch.geometry.getMesh().updateBound(); batch.geometry.updateModelBound();
batches.add(batch); batches.add(batch);
} }
if (batches.size() > 0) { if (batches.size() > 0) {
@ -457,6 +444,7 @@ public class BatchNode extends GeometryGroupNode {
int maxWeights = -1; int maxWeights = -1;
Mesh.Mode mode = null; Mesh.Mode mode = null;
float lineWidth = 1f;
for (Geometry geom : geometries) { for (Geometry geom : geometries) {
totalVerts += geom.getVertexCount(); totalVerts += geom.getVertexCount();
totalTris += geom.getTriangleCount(); totalTris += geom.getTriangleCount();
@ -465,6 +453,7 @@ public class BatchNode extends GeometryGroupNode {
maxVertCount = geom.getVertexCount(); maxVertCount = geom.getVertexCount();
} }
Mesh.Mode listMode; Mesh.Mode listMode;
float listLineWidth = 1f;
int components; int components;
switch (geom.getMesh().getMode()) { switch (geom.getMesh().getMode()) {
case Points: case Points:
@ -475,6 +464,7 @@ public class BatchNode extends GeometryGroupNode {
case LineStrip: case LineStrip:
case Lines: case Lines:
listMode = Mesh.Mode.Lines; listMode = Mesh.Mode.Lines;
listLineWidth = geom.getMesh().getLineWidth();
components = 2; components = 2;
break; break;
case TriangleFan: case TriangleFan:
@ -504,13 +494,21 @@ public class BatchNode extends GeometryGroupNode {
if (mode != null && mode != listMode) { if (mode != null && mode != listMode) {
throw new UnsupportedOperationException("Cannot combine different" throw new UnsupportedOperationException("Cannot combine different"
+ " primitive types: " + mode + " != " + listMode); + " primitive types: " + mode + " != " + listMode);
} }
mode = listMode; mode = listMode;
if (mode == Mesh.Mode.Lines) {
if (lineWidth != 1f && listLineWidth != lineWidth) {
throw new UnsupportedOperationException("When using Mesh Line mode, cannot combine meshes with different line width "
+ lineWidth + " != " + listLineWidth);
}
lineWidth = listLineWidth;
}
compsForBuf[VertexBuffer.Type.Index.ordinal()] = components; compsForBuf[VertexBuffer.Type.Index.ordinal()] = components;
} }
outMesh.setMaxNumWeights(maxWeights); outMesh.setMaxNumWeights(maxWeights);
outMesh.setMode(mode); outMesh.setMode(mode);
outMesh.setLineWidth(lineWidth);
if (totalVerts >= 65536) { if (totalVerts >= 65536) {
// make sure we create an UnsignedInt buffer so // make sure we create an UnsignedInt buffer so
// we can fit all of the meshes // we can fit all of the meshes
@ -583,11 +581,13 @@ public class BatchNode extends GeometryGroupNode {
useTangents = true; useTangents = true;
} }
} else { } else {
inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount); if (inBuf == null) {
// for (int vert = 0; vert < geomVertCount; vert++) { throw new IllegalArgumentException("Geometry " + geom.getName() + " has no " + outBuf.getBufferType() + " buffer whereas other geoms have. all geometries should have the same types of buffers.\n Try to use GeometryBatchFactory.alignBuffer() on the BatchNode before batching");
// int curGlobalVertIndex = globalVertIndex + vert; } else if (outBuf == null) {
// inBuf.copyElement(vert, outBuf, curGlobalVertIndex); throw new IllegalArgumentException("Geometry " + geom.getName() + " has a " + outBuf.getBufferType() + " buffer whereas other geoms don't. all geometries should have the same types of buffers.\n Try to use GeometryBatchFactory.alignBuffer() on the BatchNode before batching");
// } } else {
inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount);
}
} }
} }
@ -745,8 +745,7 @@ public class BatchNode extends GeometryGroupNode {
} }
} }
} }
Geometry geometry; Geometry geometry;
boolean needMeshUpdate = false;
} }
protected void setNeedsFullRebatch(boolean needsFullRebatch) { protected void setNeedsFullRebatch(boolean needsFullRebatch) {

@ -149,6 +149,7 @@ public abstract class AbstractBox extends Mesh {
duUpdateGeometryNormals(); duUpdateGeometryNormals();
duUpdateGeometryTextures(); duUpdateGeometryTextures();
duUpdateGeometryIndices(); duUpdateGeometryIndices();
setStatic();
} }
/** /**

@ -424,7 +424,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
renderManager.setCamera(shadowCam, false); renderManager.setCamera(shadowCam, false);
renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]); renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]);
renderManager.getRenderer().clearBuffers(false, true, false); renderManager.getRenderer().clearBuffers(true, true, true);
// render shadow casters to shadow map // render shadow casters to shadow map
viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true); viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true);
@ -459,7 +459,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
debug = true; debug = true;
} }
abstract void getReceivers(GeometryList lightReceivers); protected abstract void getReceivers(GeometryList lightReceivers);
public void postFrame(FrameBuffer out) { public void postFrame(FrameBuffer out) {
if (skipPostPass) { if (skipPostPass) {

@ -190,7 +190,7 @@ public class BasicShadowRenderer implements SceneProcessor {
renderManager.setForcedMaterial(preshadowMat); renderManager.setForcedMaterial(preshadowMat);
r.setFrameBuffer(shadowFB); r.setFrameBuffer(shadowFB);
r.clearBuffers(false, true, false); r.clearBuffers(true, true, true);
viewPort.getQueue().renderShadowQueue(shadowOccluders, renderManager, shadowCam, true); viewPort.getQueue().renderShadowQueue(shadowOccluders, renderManager, shadowCam, true);
r.setFrameBuffer(viewPort.getOutputFrameBuffer()); r.setFrameBuffer(viewPort.getOutputFrameBuffer());

@ -192,7 +192,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
} }
@Override @Override
void getReceivers(GeometryList lightReceivers) { protected void getReceivers(GeometryList lightReceivers) {
if (lightReceivers.size()==0) { if (lightReceivers.size()==0) {
for (Spatial scene : viewPort.getScenes()) { for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), RenderQueue.ShadowMode.Receive, lightReceivers); ShadowUtil.getGeometriesInCamFrustum(scene, viewPort.getCamera(), RenderQueue.ShadowMode.Receive, lightReceivers);

@ -139,7 +139,7 @@ public class PointLightShadowRenderer extends AbstractShadowRenderer {
} }
@Override @Override
void getReceivers(GeometryList lightReceivers) { protected void getReceivers(GeometryList lightReceivers) {
lightReceivers.clear(); lightReceivers.clear();
for (Spatial scene : viewPort.getScenes()) { for (Spatial scene : viewPort.getScenes()) {
ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers); ShadowUtil.getLitGeometriesInViewPort(scene, viewPort.getCamera(), shadowCams, RenderQueue.ShadowMode.Receive, lightReceivers);

@ -450,7 +450,7 @@ public class PssmShadowRenderer implements SceneProcessor {
} }
r.setFrameBuffer(shadowFB[i]); r.setFrameBuffer(shadowFB[i]);
r.clearBuffers(false, true, false); r.clearBuffers(true, true, true);
// render shadow casters to shadow map // render shadow casters to shadow map
viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true); viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true);

@ -151,7 +151,7 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
} }
@Override @Override
void getReceivers(GeometryList lightReceivers) { protected void getReceivers(GeometryList lightReceivers) {
lightReceivers.clear(); lightReceivers.clear();
Camera[] cameras = new Camera[1]; Camera[] cameras = new Camera[1];
cameras[0] = shadowCam; cameras[0] = shadowCam;

@ -54,6 +54,8 @@ import java.util.prefs.Preferences;
*/ */
public final class AppSettings extends HashMap<String, Object> { public final class AppSettings extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
private static final AppSettings defaults = new AppSettings(false); private static final AppSettings defaults = new AppSettings(false);
/** /**

@ -172,15 +172,6 @@ public class JmeSystem {
return systemDelegate.getPlatformAssetConfigURL(); return systemDelegate.getPlatformAssetConfigURL();
} }
/**
* @deprecated Directly create an image raster via {@link DefaultImageRaster}.
*/
@Deprecated
public static ImageRaster createImageRaster(Image image, int slice) {
checkDelegate();
return systemDelegate.createImageRaster(image, slice);
}
/** /**
* Displays an error message to the user in whichever way the context * Displays an error message to the user in whichever way the context
* feels is appropriate. If this is a headless or an offscreen surface * feels is appropriate. If this is a headless or an offscreen surface

@ -132,11 +132,6 @@ public abstract class JmeSystemDelegate {
return new DesktopAssetManager(null); return new DesktopAssetManager(null);
} }
@Deprecated
public final ImageRaster createImageRaster(Image image, int slice) {
return new DefaultImageRaster(image, slice);
}
public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException; public abstract void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException;
public abstract void showErrorDialog(String message); public abstract void showErrorDialog(String message);

@ -0,0 +1,66 @@
/*
* Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.system;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Pulls in version info from the version.properties file.
*
* @author Kirill Vainer
*/
public class JmeVersion {
private static final Logger logger = Logger.getLogger(JmeVersion.class.getName());
private static final Properties props = new Properties();
static {
try {
props.load(JmeVersion.class.getResourceAsStream("version.properties"));
} catch (IOException ex) {
logger.log(Level.WARNING, "Unable to read version info!", ex);
}
}
public static final String BUILD_DATE = props.getProperty("build.date", "1900-01-01");
public static final String BRANCH_NAME = props.getProperty("git.branch", "unknown");
public static final String GIT_HASH = props.getProperty("git.hash", "");
public static final String GIT_SHORT_HASH = props.getProperty("git.hash.short", "");
public static final String GIT_TAG = props.getProperty("git.tag", "");
public static final String VERSION_NUMBER = props.getProperty("version.number", "");
public static final String VERSION_TAG = props.getProperty("version.tag", "");
public static final String VERSION_FULL = props.getProperty("version.full", "");
public static final String FULL_NAME = props.getProperty("name.full", "jMonkeyEngine (unknown version)");
}

@ -367,7 +367,6 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
protected int width, height, depth; protected int width, height, depth;
protected int[] mipMapSizes; protected int[] mipMapSizes;
protected ArrayList<ByteBuffer> data; protected ArrayList<ByteBuffer> data;
protected transient Object efficientData;
protected int multiSamples = 1; protected int multiSamples = 1;
protected ColorSpace colorSpace = null; protected ColorSpace colorSpace = null;
// protected int mipOffset = 0; // protected int mipOffset = 0;
@ -375,7 +374,7 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
// attributes relating to GL object // attributes relating to GL object
protected boolean mipsWereGenerated = false; protected boolean mipsWereGenerated = false;
protected boolean needGeneratedMips = false; protected boolean needGeneratedMips = false;
protected final LastTextureState lastTextureState = new LastTextureState(); protected LastTextureState lastTextureState = new LastTextureState();
/** /**
* Internal use only. * Internal use only.
@ -490,6 +489,7 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
Image clone = (Image) super.clone(); Image clone = (Image) super.clone();
clone.mipMapSizes = mipMapSizes != null ? mipMapSizes.clone() : null; clone.mipMapSizes = mipMapSizes != null ? mipMapSizes.clone() : null;
clone.data = data != null ? new ArrayList<ByteBuffer>(data) : null; clone.data = data != null ? new ArrayList<ByteBuffer>(data) : null;
clone.lastTextureState = new LastTextureState();
clone.setUpdateNeeded(); clone.setUpdateNeeded();
return clone; return clone;
} }
@ -760,8 +760,6 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
*/ */
@Deprecated @Deprecated
public void setEfficentData(Object efficientData){ public void setEfficentData(Object efficientData){
this.efficientData = efficientData;
setUpdateNeeded();
} }
/** /**
@ -769,7 +767,7 @@ public class Image extends NativeObject implements Savable /*, Cloneable*/ {
*/ */
@Deprecated @Deprecated
public Object getEfficentData(){ public Object getEfficentData(){
return efficientData; return null;
} }
/** /**

@ -44,7 +44,9 @@ public class DefaultImageRaster extends ImageRaster {
private final ImageCodec codec; private final ImageCodec codec;
private final int width; private final int width;
private final int height; private final int height;
private final int offset;
private final byte[] temp; private final byte[] temp;
private final boolean convertToLinear;
private int slice; private int slice;
private void rangeCheck(int x, int y) { private void rangeCheck(int x, int y) {
@ -53,13 +55,40 @@ public class DefaultImageRaster extends ImageRaster {
} }
} }
public DefaultImageRaster(Image image, int slice) { public DefaultImageRaster(Image image, int slice, int mipMapLevel, boolean convertToLinear) {
int[] mipMapSizes = image.getMipMapSizes();
int availableMips = mipMapSizes != null ? mipMapSizes.length : 1;
if (mipMapLevel >= availableMips) {
throw new IllegalStateException("Cannot create image raster for mipmap level #" + mipMapLevel + ". "
+ "Image only has " + availableMips + " mipmap levels.");
}
if (image.hasMipmaps()) {
this.width = Math.max(1, image.getWidth() >> mipMapLevel);
this.height = Math.max(1, image.getHeight() >> mipMapLevel);
int mipOffset = 0;
for (int i = 0; i < mipMapLevel; i++) {
mipOffset += mipMapSizes[i];
}
this.offset = mipOffset;
} else {
this.width = image.getWidth();
this.height = image.getHeight();
this.offset = 0;
}
this.image = image; this.image = image;
this.slice = slice; this.slice = slice;
// Conversion to linear only needed if image's color space is sRGB.
this.convertToLinear = convertToLinear && image.getColorSpace() == ColorSpace.sRGB;
this.buffer = image.getData(slice); this.buffer = image.getData(slice);
this.codec = ImageCodec.lookup(image.getFormat()); this.codec = ImageCodec.lookup(image.getFormat());
this.width = image.getWidth();
this.height = image.getHeight();
if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) { if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) {
this.temp = new byte[codec.bpp]; this.temp = new byte[codec.bpp];
} else { } else {
@ -86,6 +115,12 @@ public class DefaultImageRaster extends ImageRaster {
public void setPixel(int x, int y, ColorRGBA color) { public void setPixel(int x, int y, ColorRGBA color) {
rangeCheck(x, y); rangeCheck(x, y);
if (convertToLinear) {
// Input is linear, needs to be converted to sRGB before writing
// into image.
color = color.getAsSrgb();
}
// Check flags for grayscale // Check flags for grayscale
if (codec.isGray) { if (codec.isGray) {
float gray = color.r * 0.27f + color.g * 0.67f + color.b * 0.06f; float gray = color.r * 0.27f + color.g * 0.67f + color.b * 0.06f;
@ -113,7 +148,7 @@ public class DefaultImageRaster extends ImageRaster {
components[3] = Math.min( (int) (color.b * codec.maxBlue + 0.5f), codec.maxBlue); components[3] = Math.min( (int) (color.b * codec.maxBlue + 0.5f), codec.maxBlue);
break; break;
} }
codec.writeComponents(getBuffer(), x, y, width, 0, components, temp); codec.writeComponents(getBuffer(), x, y, width, offset, components, temp);
image.setUpdateNeeded(); image.setUpdateNeeded();
} }
@ -128,7 +163,7 @@ public class DefaultImageRaster extends ImageRaster {
public ColorRGBA getPixel(int x, int y, ColorRGBA store) { public ColorRGBA getPixel(int x, int y, ColorRGBA store) {
rangeCheck(x, y); rangeCheck(x, y);
codec.readComponents(getBuffer(), x, y, width, 0, components, temp); codec.readComponents(getBuffer(), x, y, width, offset, components, temp);
if (store == null) { if (store == null) {
store = new ColorRGBA(); store = new ColorRGBA();
} }
@ -169,6 +204,12 @@ public class DefaultImageRaster extends ImageRaster {
store.a = 1; store.a = 1;
} }
} }
if (convertToLinear) {
// Input image is sRGB, need to convert to linear.
store.setAsSrgb(store.r, store.g, store.b, store.a);
}
return store; return store;
} }
} }

@ -71,21 +71,42 @@ public abstract class ImageRaster {
* @param image The image to read / write to. * @param image The image to read / write to.
* @param slice Which slice to use. Only applies to 3D images, 2D image * @param slice Which slice to use. Only applies to 3D images, 2D image
* arrays or cubemaps. * arrays or cubemaps.
* @param mipMapLevel The mipmap level to read / write to. To access levels
* other than 0, the image must have
* {@link Image#setMipMapSizes(int[]) mipmap sizes} set.
* @param convertToLinear If true, the application expects read or written
* colors to be in linear color space (<code>ImageRaster</code> will
* automatically perform a conversion as needed). If false, the application expects
* colors to be in the image's native {@link Image#getColorSpace() color space}.
* @return An ImageRaster to read / write to the image.
*/
public static ImageRaster create(Image image, int slice, int mipMapLevel, boolean convertToLinear) {
return new DefaultImageRaster(image, slice, mipMapLevel, convertToLinear);
}
/**
* Create new image reader / writer.
*
* @param image The image to read / write to.
* @param slice Which slice to use. Only applies to 3D images, 2D image
* arrays or cubemaps.
* @return An ImageRaster to read / write to the image.
*/ */
public static ImageRaster create(Image image, int slice) { public static ImageRaster create(Image image, int slice) {
return JmeSystem.createImageRaster(image, slice); return create(image, slice, 0, false);
} }
/** /**
* Create new image reader / writer for 2D images. * Create new image reader / writer for 2D images.
* *
* @param image The image to read / write to. * @param image The image to read / write to.
* @return An ImageRaster to read / write to the image.
*/ */
public static ImageRaster create(Image image) { public static ImageRaster create(Image image) {
if (image.getData().size() > 1) { if (image.getData().size() > 1) {
throw new IllegalStateException("Use constructor that takes slices argument to read from multislice image"); throw new IllegalStateException("Use constructor that takes slices argument to read from multislice image");
} }
return JmeSystem.createImageRaster(image, 0); return create(image, 0, 0, false);
} }
public ImageRaster() { public ImageRaster() {

@ -36,6 +36,7 @@ import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f; import com.jme3.math.Vector4f;
import java.io.UnsupportedEncodingException;
import java.lang.ref.PhantomReference; import java.lang.ref.PhantomReference;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
@ -1010,11 +1011,15 @@ public final class BufferUtils {
} }
public static ByteBuffer createByteBuffer(String data) { public static ByteBuffer createByteBuffer(String data) {
byte[] bytes = data.getBytes(); try {
ByteBuffer bb = createByteBuffer(bytes.length); byte[] bytes = data.getBytes("UTF-8");
bb.put(bytes); ByteBuffer bb = createByteBuffer(bytes.length);
bb.flip(); bb.put(bytes);
return bb; bb.flip();
return bb;
} catch (UnsupportedEncodingException ex) {
throw new UnsupportedOperationException(ex);
}
} }
/** /**

@ -42,7 +42,6 @@ import java.io.*;
public class LittleEndien extends InputStream implements DataInput { public class LittleEndien extends InputStream implements DataInput {
protected BufferedInputStream in; protected BufferedInputStream in;
protected BufferedReader inRead;
/** /**
* Creates a new LittleEndien reader from the given input stream. The * Creates a new LittleEndien reader from the given input stream. The
@ -51,7 +50,6 @@ public class LittleEndien extends InputStream implements DataInput {
*/ */
public LittleEndien(InputStream in) { public LittleEndien(InputStream in) {
this.in = new BufferedInputStream(in); this.in = new BufferedInputStream(in);
inRead = new BufferedReader(new InputStreamReader(in));
} }
public int read() throws IOException { public int read() throws IOException {
@ -141,7 +139,7 @@ public class LittleEndien extends InputStream implements DataInput {
} }
public String readLine() throws IOException { public String readLine() throws IOException {
return inRead.readLine(); throw new IOException("Unsupported operation");
} }
public String readUTF() throws IOException { public String readUTF() throws IOException {

@ -0,0 +1,140 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.util;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.texture.image.ImageRaster;
import java.nio.ByteBuffer;
import java.util.ArrayList;
public class MipMapGenerator {
private MipMapGenerator() {
}
public static Image scaleImage(Image inputImage, int outputWidth, int outputHeight) {
int size = outputWidth * outputHeight * inputImage.getFormat().getBitsPerPixel() / 8;
ByteBuffer buffer = BufferUtils.createByteBuffer(size);
Image outputImage = new Image(inputImage.getFormat(),
outputWidth,
outputHeight,
buffer,
inputImage.getColorSpace());
ImageRaster input = ImageRaster.create(inputImage, 0, 0, false);
ImageRaster output = ImageRaster.create(outputImage, 0, 0, false);
float xRatio = ((float)(input.getWidth() - 1)) / output.getWidth();
float yRatio = ((float)(input.getHeight() - 1)) / output.getHeight();
ColorRGBA outputColor = new ColorRGBA();
ColorRGBA bottomLeft = new ColorRGBA();
ColorRGBA bottomRight = new ColorRGBA();
ColorRGBA topLeft = new ColorRGBA();
ColorRGBA topRight = new ColorRGBA();
for (int y = 0; y < outputHeight; y++) {
for (int x = 0; x < outputWidth; x++) {
float x2f = x * xRatio;
float y2f = y * yRatio;
int x2 = (int)x2f;
int y2 = (int)y2f;
float xDiff = x2f - x2;
float yDiff = y2f - y2;
input.getPixel(x2, y2, bottomLeft);
input.getPixel(x2 + 1, y2, bottomRight);
input.getPixel(x2, y2 + 1, topLeft);
input.getPixel(x2 + 1, y2 + 1, topRight);
bottomLeft.multLocal( (1f - xDiff) * (1f - yDiff) );
bottomRight.multLocal( (xDiff) * (1f - yDiff) );
topLeft.multLocal( (1f - xDiff) * (yDiff) );
topRight.multLocal( (xDiff) * (yDiff) );
outputColor.set(bottomLeft).addLocal(bottomRight)
.addLocal(topLeft).addLocal(topRight);
output.setPixel(x, y, outputColor);
}
}
return outputImage;
}
public static Image resizeToPowerOf2(Image original){
int potWidth = FastMath.nearestPowerOfTwo(original.getWidth());
int potHeight = FastMath.nearestPowerOfTwo(original.getHeight());
return scaleImage(original, potWidth, potHeight);
}
public static void generateMipMaps(Image image){
int width = image.getWidth();
int height = image.getHeight();
Image current = image;
ArrayList<ByteBuffer> output = new ArrayList<ByteBuffer>();
int totalSize = 0;
while (height >= 1 || width >= 1){
output.add(current.getData(0));
totalSize += current.getData(0).capacity();
if (height == 1 || width == 1) {
break;
}
height /= 2;
width /= 2;
current = scaleImage(current, width, height);
}
ByteBuffer combinedData = BufferUtils.createByteBuffer(totalSize);
int[] mipSizes = new int[output.size()];
for (int i = 0; i < output.size(); i++){
ByteBuffer data = output.get(i);
data.clear();
combinedData.put(data);
mipSizes[i] = data.capacity();
}
combinedData.flip();
// insert mip data into image
image.setData(0, combinedData);
image.setMipMapSizes(mipSizes);
}
}

@ -612,9 +612,9 @@ public class TangentBinormalGenerator {
normal.normalizeLocal(); normal.normalizeLocal();
return new TriangleData( return new TriangleData(
tangent, tangent.clone(),
binormal, binormal.clone(),
normal); normal.clone());
} finally { } finally {
tmp.release(); tmp.release();
} }

@ -37,6 +37,7 @@ varying vec3 SpecularSum;
#endif #endif
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING) #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
uniform float m_ParallaxHeight; uniform float m_ParallaxHeight;
varying vec3 vViewDirPrlx;
#endif #endif
#ifdef LIGHTMAP #ifdef LIGHTMAP
@ -78,18 +79,18 @@ void main(){
#ifdef STEEP_PARALLAX #ifdef STEEP_PARALLAX
#ifdef NORMALMAP_PARALLAX #ifdef NORMALMAP_PARALLAX
//parallax map is stored in the alpha channel of the normal map //parallax map is stored in the alpha channel of the normal map
newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); newTexCoord = steepParallaxOffset(m_NormalMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
#else #else
//parallax map is a texture //parallax map is a texture
newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
#endif #endif
#else #else
#ifdef NORMALMAP_PARALLAX #ifdef NORMALMAP_PARALLAX
//parallax map is stored in the alpha channel of the normal map //parallax map is stored in the alpha channel of the normal map
newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight); newTexCoord = classicParallaxOffset(m_NormalMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
#else #else
//parallax map is a texture //parallax map is a texture
newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight); newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
#endif #endif
#endif #endif
#else #else

@ -48,6 +48,10 @@ varying vec3 lightVec;
uniform vec4 g_LightDirection; uniform vec4 g_LightDirection;
#endif #endif
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
varying vec3 vViewDirPrlx;
#endif
#ifdef USE_REFLECTION #ifdef USE_REFLECTION
uniform vec3 g_CameraPosition; uniform vec3 g_CameraPosition;
@ -107,17 +111,25 @@ void main(){
wvLightPos.w = g_LightPosition.w; wvLightPos.w = g_LightPosition.w;
vec4 lightColor = g_LightColor; vec4 lightColor = g_LightColor;
#if defined(NORMALMAP) && !defined(VERTEX_LIGHTING) #if (defined(NORMALMAP) || defined(PARALLAXMAP)) && !defined(VERTEX_LIGHTING)
vec3 wvTangent = normalize(TransformNormal(modelSpaceTan)); vec3 wvTangent = normalize(TransformNormal(modelSpaceTan));
vec3 wvBinormal = cross(wvNormal, wvTangent); vec3 wvBinormal = cross(wvNormal, wvTangent);
mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal); mat3 tbnMat = mat3(wvTangent, wvBinormal * inTangent.w,wvNormal);
#endif
vViewDir = -wvPosition * tbnMat; #if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
vViewDir = -wvPosition * tbnMat;
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
vViewDirPrlx = vViewDir;
#endif
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz; vLightDir.xyz = (vLightDir.xyz * tbnMat).xyz;
#elif !defined(VERTEX_LIGHTING) #elif !defined(VERTEX_LIGHTING)
vNormal = wvNormal; vNormal = wvNormal;
vViewDir = viewDir; vViewDir = viewDir;
#if defined(PARALLAXMAP)
vViewDirPrlx = -wvPosition * tbnMat;
#endif
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec); lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
#endif #endif

@ -17,10 +17,7 @@ varying vec3 SpecularSum;
#ifndef VERTEX_LIGHTING #ifndef VERTEX_LIGHTING
uniform mat4 g_ViewMatrix; uniform mat4 g_ViewMatrix;
uniform vec4 g_LightData[NB_LIGHTS]; uniform vec4 g_LightData[NB_LIGHTS];
varying vec3 vPos; varying vec3 vPos;
#else
varying vec3 specularAccum;
varying vec4 diffuseAccum;
#endif #endif
#ifdef DIFFUSEMAP #ifdef DIFFUSEMAP
@ -167,10 +164,9 @@ void main(){
#endif #endif
#ifdef VERTEX_LIGHTING #ifdef VERTEX_LIGHTING
gl_FragColor.rgb = AmbientSum * diffuseColor.rgb gl_FragColor.rgb = AmbientSum.rgb * diffuseColor.rgb
+diffuseAccum.rgb *diffuseColor.rgb + DiffuseSum.rgb * diffuseColor.rgb
+specularAccum.rgb * specularColor.rgb; + SpecularSum.rgb * specularColor.rgb;
gl_FragColor.a=1.0;
#else #else
int i = 0; int i = 0;

@ -43,8 +43,6 @@ attribute vec3 inNormal;
varying vec3 vBinormal; varying vec3 vBinormal;
#endif #endif
#else #else
varying vec3 specularAccum;
varying vec4 diffuseAccum;
#ifdef COLORRAMP #ifdef COLORRAMP
uniform sampler2D m_ColorRamp; uniform sampler2D m_ColorRamp;
#endif #endif
@ -131,14 +129,13 @@ void main(){
#endif #endif
#ifdef VERTEX_LIGHTING #ifdef VERTEX_LIGHTING
int i = 0; int i = 0;
diffuseAccum = vec4(0.0); vec3 diffuseAccum = vec3(0.0);
specularAccum = vec3(0.0); vec3 specularAccum = vec3(0.0);
vec4 diffuseColor; vec4 diffuseColor;
vec3 specularColor; vec3 specularColor;
for (int i =0;i < NB_LIGHTS; i+=3){ for (int i =0;i < NB_LIGHTS; i+=3){
vec4 lightColor = g_LightData[i]; vec4 lightColor = g_LightData[i];
vec4 lightData1 = g_LightData[i+1]; vec4 lightData1 = g_LightData[i+1];
DiffuseSum = vec4(1.0);
#ifdef MATERIAL_COLORS #ifdef MATERIAL_COLORS
diffuseColor = m_Diffuse * vec4(lightColor.rgb, 1.0); diffuseColor = m_Diffuse * vec4(lightColor.rgb, 1.0);
specularColor = m_Specular.rgb * lightColor.rgb; specularColor = m_Specular.rgb * lightColor.rgb;
@ -166,13 +163,16 @@ void main(){
vec2 light = computeLighting(wvNormal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess); vec2 light = computeLighting(wvNormal, viewDir, lightDir.xyz, lightDir.w * spotFallOff, m_Shininess);
#ifdef COLORRAMP #ifdef COLORRAMP
diffuseAccum.rgb += texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb * diffuseColor.rgb; diffuseAccum += texture2D(m_ColorRamp, vec2(light.x, 0.0)).rgb * diffuseColor.rgb;
specularAccum.rgb += texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb * specularColor; specularAccum += texture2D(m_ColorRamp, vec2(light.y, 0.0)).rgb * specularColor;
#else #else
diffuseAccum.rgb += light.x * diffuseColor.rgb; diffuseAccum += light.x * diffuseColor.rgb;
specularAccum.rgb += light.y * specularColor; specularAccum += light.y * specularColor;
#endif #endif
} }
DiffuseSum.rgb *= diffuseAccum.rgb;
SpecularSum.rgb *= specularAccum.rgb;
#endif #endif

@ -1,3 +1,4 @@
Exception This material definition is deprecated. Please use Unshaded.j3md instead.
MaterialDef Colored Textured { MaterialDef Colored Textured {
MaterialParameters { MaterialParameters {
@ -17,4 +18,4 @@ MaterialDef Colored Textured {
Technique { Technique {
} }
} }

@ -1,3 +1,5 @@
#import "Common/ShaderLib/GLSLCompat.glsllib"
#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) #if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD))
#define NEED_TEXCOORD1 #define NEED_TEXCOORD1
#endif #endif

@ -13,7 +13,7 @@ MaterialDef Unshaded {
Color GlowColor Color GlowColor
// For instancing // For instancing
Boolean UseInstancing Boolean UseInstancing
// For hardware skinning // For hardware skinning
Int NumberOfBones Int NumberOfBones
@ -54,8 +54,8 @@ MaterialDef Unshaded {
} }
Technique { Technique {
VertexShader GLSL100: Common/MatDefs/Misc/Unshaded.vert VertexShader GLSL150: Common/MatDefs/Misc/Unshaded.vert
FragmentShader GLSL100: Common/MatDefs/Misc/Unshaded.frag FragmentShader GLSL150: Common/MatDefs/Misc/Unshaded.frag
WorldParameters { WorldParameters {
WorldViewProjectionMatrix WorldViewProjectionMatrix
@ -76,6 +76,25 @@ MaterialDef Unshaded {
} }
Technique { Technique {
VertexShader GLSL100: Common/MatDefs/Misc/Unshaded.vert
FragmentShader GLSL100: Common/MatDefs/Misc/Unshaded.frag
WorldParameters {
WorldViewProjectionMatrix
ViewProjectionMatrix
ViewMatrix
}
Defines {
INSTANCING : UseInstancing
SEPARATE_TEXCOORD : SeparateTexCoord
HAS_COLORMAP : ColorMap
HAS_LIGHTMAP : LightMap
HAS_VERTEXCOLOR : VertexColor
HAS_COLOR : Color
NUM_BONES : NumberOfBones
DISCARD_ALPHA : AlphaDiscardThreshold
}
} }
Technique PreNormalPass { Technique PreNormalPass {

@ -1,3 +1,4 @@
#import "Common/ShaderLib/GLSLCompat.glsllib"
#import "Common/ShaderLib/Skinning.glsllib" #import "Common/ShaderLib/Skinning.glsllib"
#import "Common/ShaderLib/Instancing.glsllib" #import "Common/ShaderLib/Instancing.glsllib"

@ -1,97 +1,121 @@
MaterialDef UnshadedNodes { MaterialDef UnshadedNodes {
MaterialParameters {
MaterialParameters { Texture2D ColorMap
Texture2D ColorMap Texture2D LightMap
Texture2D LightMap Color Color (Color)
Color Color (Color) Boolean VertexColor (UseVertexColor)
Boolean VertexColor (UseVertexColor) Boolean SeparateTexCoord
Boolean SeparateTexCoord Float AlphaDiscardThreshold (AlphaTestFallOff)
Int NumberOfBones
// Alpha threshold for fragment discarding Matrix4Array BoneMatrices
Float AlphaDiscardThreshold (AlphaTestFallOff) }
Technique {
// For hardware skinning WorldParameters {
Int NumberOfBones WorldViewProjectionMatrix
Matrix4Array BoneMatrices WorldViewMatrix
}
} VertexShaderNodes {
ShaderNode GpuSkinning {
Technique { Definition : BasicGPUSkinning : Common/MatDefs/ShaderNodes/HardwareSkinning/HardwareSkinning.j3sn
Condition : NumberOfBones
WorldParameters { InputMapping {
WorldViewProjectionMatrix modelPosition = Global.position
//used for fog boneMatrices = MatParam.BoneMatrices
WorldViewMatrix boneWeight = Attr.inHWBoneWeight
} boneIndex = Attr.inHWBoneIndex
}
VertexShaderNodes{ OutputMapping {
ShaderNode GpuSkinning{ Global.position = modModelPosition
Definition: BasicGPUSkinning : Common/MatDefs/ShaderNodes/HardwareSkinning/HardwareSkinning.j3sn }
Condition : NumberOfBones }
InputMapping{ ShaderNode UnshadedVert {
modelPosition = Global.position; Definition : CommonVert : Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn
boneMatrices = MatParam.BoneMatrices InputMapping {
boneWeight = Attr.inHWBoneWeight worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix
boneIndex = Attr.inHWBoneIndex modelPosition = Global.position.xyz
} texCoord1 = Attr.inTexCoord : ColorMap || (LightMap && !SeparateTexCoord)
OutputMapping{ texCoord2 = Attr.inTexCoord2 : SeparateTexCoord
Global.position = modModelPosition vertColor = Attr.inColor : VertexColor
} }
} OutputMapping {
ShaderNode UnshadedVert{ Global.position = projPosition
Definition: CommonVert : Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn }
InputMapping{ }
worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix }
modelPosition = Global.position.xyz FragmentShaderNodes {
texCoord1 = Attr.inTexCoord: ColorMap || (LightMap && !SeparateTexCoord) ShaderNode MatColorMult {
texCoord2 = Attr.inTexCoord2: SeparateTexCoord Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
vertColor = Attr.inColor: VertexColor InputMappings {
} color1 = MatParam.Color
OutputMapping{ color2 = Global.outColor
Global.position = projPosition }
} OutputMappings {
} Global.outColor = outColor
} }
FragmentShaderNodes{ Condition : Color
ShaderNode UnshadedFrag{ }
Definition: Unshaded : Common/MatDefs/ShaderNodes/Common/Unshaded.j3sn ShaderNode VertColorMult {
InputMapping{ Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
texCoord = UnshadedVert.texCoord1: ColorMap InputMappings {
vertColor = UnshadedVert.vertColor: VertexColor color1 = UnshadedVert.vertColor
matColor = MatParam.Color: Color color2 = Global.outColor
colorMap = MatParam.ColorMap: ColorMap }
color = Global.outColor OutputMappings {
} Global.outColor = outColor
OutputMapping{ }
Global.outColor = color Condition : VertexColor
} }
} ShaderNode ColorMapTF {
Definition : TextureFetch : Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn
ShaderNode AlphaDiscardThreshold{ InputMappings {
Definition: AlphaDiscard : Common/MatDefs/ShaderNodes/Basic/AlphaDiscard.j3sn texCoord = UnshadedVert.texCoord1
Condition : AlphaDiscardThreshold textureMap = MatParam.ColorMap
InputMapping{ }
alpha = Global.outColor.a OutputMappings {
threshold = MatParam.AlphaDiscardThreshold }
} Condition : ColorMap
} }
ShaderNode LightMap{ ShaderNode ColorMapMult {
Definition: LightMapping : Common/MatDefs/ShaderNodes/LightMapping/LightMapping.j3sn Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
Condition: LightMap InputMappings {
InputMapping{ color1 = ColorMapTF.outColor
texCoord = UnshadedVert.texCoord1: !SeparateTexCoord color2 = Global.outColor
texCoord = UnshadedVert.texCoord2: SeparateTexCoord }
lightMap = MatParam.LightMap OutputMappings {
color = Global.outColor Global.outColor = outColor
} }
OutputMapping{ Condition : ColorMap
Global.outColor = color }
} ShaderNode AlphaDiscardThreshold {
} Definition : AlphaDiscard : Common/MatDefs/ShaderNodes/Basic/AlphaDiscard.j3sn
Condition : AlphaDiscardThreshold
} InputMapping {
alpha = Global.outColor.a
} threshold = MatParam.AlphaDiscardThreshold
}
}
ShaderNode LightMapTF {
Definition : TextureFetch : Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn
InputMappings {
textureMap = MatParam.LightMap
texCoord = UnshadedVert.texCoord2 : SeparateTexCoord
texCoord = UnshadedVert.texCoord1 : !SeparateTexCoord
}
OutputMappings {
}
Condition : LightMap
}
ShaderNode LightMapMult {
Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
OutputMappings {
Global.outColor = outColor
}
InputMappings {
color1 = LightMapTF.outColor
color2 = Global.outColor
}
Condition : LightMap
}
}
}
} }

@ -2,14 +2,15 @@ ShaderNodeDefinitions{
ShaderNodeDefinition TextureFetch { ShaderNodeDefinition TextureFetch {
Type: Fragment Type: Fragment
Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/texture.frag Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/texture.frag
Shader GLSL150: Common/MatDefs/ShaderNodes/Basic/texture15.frag
Documentation{ Documentation{
Fetches a color value in the given texture acording to given texture coordinates Fetches a color value in the given texture acording to given texture coordinates
@input texture the texture to read @input textureMap the texture to read
@input texCoord the texture coordinates @input texCoord the texture coordinates
@output outColor the fetched color @output outColor the fetched color
} }
Input { Input {
sampler2D texture sampler2D textureMap
vec2 texCoord vec2 texCoord
} }
Output { Output {

@ -1,3 +1,3 @@
void main(){ void main(){
outColor = texture2D(texture,texCoord); outColor = texture2D(textureMap,texCoord);
} }

@ -0,0 +1,3 @@
void main(){
outColor = texture(textureMap,texCoord);
}

@ -0,0 +1,34 @@
#if defined _GL_ES_
# define hfloat highp float
# define hvec2 highp vec2
# define hvec3 highp vec3
# define hvec4 highp vec4
# define lfloat lowp float
# define lvec2 lowp vec2
# define lvec3 lowp vec3
# define lvec4 lowp vec4
#else
# define hfloat float
# define hvec2 vec2
# define hvec3 vec3
# define hvec4 vec4
# define lfloat float
# define lvec2 vec2
# define lvec3 vec3
# define lvec4 vec4
#endif
#if __VERSION__ >= 130
out vec4 outFragColor;
# define texture1D texture
# define texture2D texture
# define texture3D texture
# define texture2DLod texture
# if defined VERTEX_SHADER
# define varying out
# define attribute in
# elif defined FRAGMENT_SHADER
# define varying in
# define gl_FragColor outFragColor
# endif
#endif

@ -15,8 +15,14 @@ uniform int m_NumSamplesDepth;
#define DEPTHTEXTURE sampler2D #define DEPTHTEXTURE sampler2D
#endif #endif
// NOTE: Only define multisample functions if multisample is available and is being used! #if __VERSION__ >= 150
#if defined(GL_ARB_texture_multisample) && (defined(RESOLVE_MS) || defined(RESOLVE_DEPTH_MS)) #define TEXTURE texture
#else
#define TEXTURE texture2D
#endif
// NOTE: Only define multisample functions if multisample is available
#if defined(GL_ARB_texture_multisample)
vec4 textureFetch(in sampler2DMS tex,in vec2 texC, in int numSamples){ vec4 textureFetch(in sampler2DMS tex,in vec2 texC, in int numSamples){
ivec2 iTexC = ivec2(texC * vec2(textureSize(tex))); ivec2 iTexC = ivec2(texC * vec2(textureSize(tex)));
vec4 color = vec4(0.0); vec4 color = vec4(0.0);
@ -44,40 +50,21 @@ vec4 getDepth(in sampler2DMS tex,in vec2 texC){
return textureFetch(tex,texC,m_NumSamplesDepth); return textureFetch(tex,texC,m_NumSamplesDepth);
} }
#elif __VERSION__ >= 150 #endif
vec4 fetchTextureSample(in sampler2D tex,in vec2 texC,in int sample){
return texture(tex,texC);
}
vec4 getColor(in sampler2D tex, in vec2 texC){
return texture(tex,texC);
}
vec4 getColorSingle(in sampler2D tex, in vec2 texC){
return texture(tex, texC);
}
vec4 getDepth(in sampler2D tex,in vec2 texC){
return texture(tex,texC);
}
#else
vec4 fetchTextureSample(in sampler2D tex,in vec2 texC,in int sample){ vec4 fetchTextureSample(in sampler2D tex,in vec2 texC,in int sample){
return texture2D(tex,texC); return TEXTURE(tex,texC);
} }
vec4 getColor(in sampler2D tex, in vec2 texC){ vec4 getColor(in sampler2D tex, in vec2 texC){
return texture2D(tex,texC); return TEXTURE(tex,texC);
} }
vec4 getColorSingle(in sampler2D tex, in vec2 texC){ vec4 getColorSingle(in sampler2D tex, in vec2 texC){
return texture2D(tex, texC); return TEXTURE(tex, texC);
} }
vec4 getDepth(in sampler2D tex,in vec2 texC){ vec4 getDepth(in sampler2D tex,in vec2 texC){
return texture2D(tex,texC); return TEXTURE(tex,texC);
} }
#endif

@ -2,26 +2,4 @@ INCLUDE com/jme3/asset/General.cfg
# Desktop-specific loaders # Desktop-specific loaders
LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg LOADER com.jme3.texture.plugins.AWTLoader : jpg, bmp, gif, png, jpeg
LOADER com.jme3.audio.plugins.OGGLoader : oggLOADER com.jme3.audio.plugins.WAVLoader : wav
LOADER com.jme3.audio.plugins.OGGLoader : ogg LOADER com.jme3.audio.plugins.OGGLoader : ogg
LOADER com.jme3.cursors.plugins.CursorLoader : ani, cur, ico
LOADER com.jme3.material.plugins.J3MLoader : j3m
LOADER com.jme3.material.plugins.J3MLoader : j3md
LOADER com.jme3.material.plugins.ShaderNodeDefinitionLoader : j3sn
LOADER com.jme3.font.plugins.BitmapFontLoader : fnt
LOADER com.jme3.texture.plugins.DDSLoader : dds
LOADER com.jme3.texture.plugins.PFMLoader : pfm
LOADER com.jme3.texture.plugins.HDRLoader : hdr
LOADER com.jme3.texture.plugins.TGALoader : tga
LOADER com.jme3.export.binary.BinaryImporter : j3o
LOADER com.jme3.export.binary.BinaryImporter : j3f
LOADER com.jme3.scene.plugins.OBJLoader : obj
LOADER com.jme3.scene.plugins.MTLLoader : mtl
LOADER com.jme3.scene.plugins.ogre.MeshLoader : meshxml, mesh.xml
LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml
LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag,geom,tsctrl,tseval, glsl, glsllib
LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba

@ -21,6 +21,6 @@ LOADER com.jme3.scene.plugins.ogre.SkeletonLoader : skeletonxml, skeleton.xml
LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material LOADER com.jme3.scene.plugins.ogre.MaterialLoader : material
LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene LOADER com.jme3.scene.plugins.ogre.SceneLoader : scene
LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend LOADER com.jme3.scene.plugins.blender.BlenderModelLoader : blend
LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, glsl, glsllib LOADER com.jme3.shader.plugins.GLSLLoader : vert, frag, geom, tsctrl, tseval, glsl, glsllib
LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx LOADER com.jme3.scene.plugins.fbx.SceneLoader : fbx
LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba LOADER com.jme3.scene.plugins.fbx.SceneWithAnimationLoader : fba

@ -0,0 +1,11 @@
# THIS IS AN AUTO-GENERATED FILE..
# DO NOT MODIFY!
build.date=1900-01-01
git.revision=0
git.branch=unknown
git.hash=
git.hash.short=
git.tag=
name.full=jMonkeyEngine 3.1.0-UNKNOWN
version.number=3.1.0
version.tag=SNAPSHOT

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

Loading…
Cancel
Save