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

experimental
Dokthar 9 years ago
commit c9230d370a
  1. 15
      .gitignore
  2. 36
      .travis.yml
  3. 7
      CONTRIBUTING.md
  4. 2
      README.md
  5. 67
      build.gradle
  6. 13
      common-android-app.gradle
  7. 43
      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. 3
      jme3-blender/build.gradle
  16. 11
      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. 17
      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. 250
      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. 24
      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. 2
      jme3-bullet/src/main/java/com/jme3/bullet/collision/shapes/CapsuleCollisionShape.java
  31. 46
      jme3-bullet/src/main/java/com/jme3/bullet/objects/PhysicsRigidBody.java
  32. 66
      jme3-core/build.gradle
  33. 1
      jme3-core/src/main/java/com/jme3/animation/Bone.java
  34. 15
      jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java
  35. 22
      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. 2
      jme3-core/src/main/java/com/jme3/cinematic/Cinematic.java
  42. 10
      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. 2
      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. 106
      jme3-core/src/main/java/com/jme3/light/SpotLight.java
  51. 5
      jme3-core/src/main/java/com/jme3/material/Material.java
  52. 27
      jme3-core/src/main/java/com/jme3/material/TechniqueDef.java
  53. 32
      jme3-core/src/main/java/com/jme3/math/ColorRGBA.java
  54. 71
      jme3-core/src/main/java/com/jme3/math/Matrix4f.java
  55. 36
      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. 81
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
  64. 38
      jme3-core/src/main/java/com/jme3/renderer/opengl/TextureUtil.java
  65. 39
      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. 7
      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. 14
      jme3-core/src/main/resources/Common/MatDefs/Light/Lighting.vert
  86. 10
      jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.frag
  87. 18
      jme3-core/src/main/resources/Common/MatDefs/Light/SPLighting.vert
  88. 1
      jme3-core/src/main/resources/Common/MatDefs/Misc/ColoredTextured.j3md
  89. 2
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.frag
  90. 23
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.j3md
  91. 1
      jme3-core/src/main/resources/Common/MatDefs/Misc/Unshaded.vert
  92. 94
      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/
/build/
/netbeans/
/sdk/jdks/local/
/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-desktop/build/
/jme3-android-native/build/
/jme3-android/build/
/jme3-android-examples/build/
/jme3-blender/build/
/jme3-effects/build/
/jme3-bullet/build/
@ -79,6 +81,7 @@
/sdk/jme3-vehicle-creator/build/
/sdk/jme3-welcome-screen/build/
/sdk/jme3-glsl-support/build/
/sdk/jme3-dark-laf/build/
/sdk/nbproject/private/
/sdk/jme3-scenecomposer/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/linux/x86/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
- netbeans
branches:
only:
- master
# branches:
# only:
# - master
notifications:
slack:
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:
- 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
# sudo apt-get update
# 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.
- 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.
#### Core Contributors

@ -1,6 +1,8 @@
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.
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.*
apply plugin: 'base' // To add "clean" task to the root project.
//apply plugin: 'java-library-distribution'
buildscript {
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
subprojects {
// Don't add to native builds
// if(!project.name.endsWith('native')){
if(!project.name.equals('jme3-android-examples')) {
apply from: rootProject.file('common.gradle')
// }
} else {
apply from: rootProject.file('common-android-app.gradle')
}
}
task run(dependsOn: ':jme3-examples:run') {
@ -50,8 +61,7 @@ task libDist(dependsOn: subprojects.build) << {
}
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("/") {
from {"./dist"}
}
@ -105,7 +115,12 @@ task wrapper(type: Wrapper, description: 'Creates and deploys the Gradle wrapper
gradleVersion = '2.2.1'
}
String findNDK() {
ext {
ndkCommandPath = ""
ndkExists = false
}
task configureAndroidNDK {
def ndkBuildFile = "ndk-build"
// if windows, use ndk-build.cmd instead
if (System.properties['os.name'].toLowerCase().contains('windows')) {
@ -118,25 +133,11 @@ String findNDK() {
if (System.env.ANDROID_NDK != null) {
ndkBuildPath = System.env.ANDROID_NDK + File.separator + ndkBuildFile
}
if (new File(ndkBuildPath).exists()) {
return ndkBuildPath
} else {
return null
}
}
boolean checkNdkExists(String ndkCommandPath) {
// String ndkCommandPath = findNDK()
if (ndkCommandPath != null && new File(ndkCommandPath).exists()) {
return true
} else {
return false
}
if (new File(ndkBuildPath).exists()) {
ndkExists = true
ndkCommandPath = ndkBuildPath
}
ext {
ndkCommandPath = findNDK()
ndkExists = checkNdkExists(ndkCommandPath)
}
//class IncrementalReverseTask extends DefaultTask {
@ -166,11 +167,11 @@ ext {
// }
//}
allprojects {
tasks.withType(JavaExec) {
enableAssertions = true // false by default
}
tasks.withType(Test) {
enableAssertions = true // true by default
}
}
//allprojects {
// tasks.withType(JavaExec) {
// enableAssertions = true // false by default
// }
// tasks.withType(Test) {
// 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: 'maven'
apply plugin: 'maven-publish'
group = 'com.jme3'
version = jmeVersion + '-' + jmeVersionTag
version = jmePomVersion
sourceCompatibility = '1.6'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
@ -19,9 +18,21 @@ repositories {
}
}
configurations {
deployerJars
}
dependencies {
// Adding dependencies here will add the dependencies to each subproject.
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 {
@ -56,16 +67,18 @@ artifacts {
}
}
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar
uploadArchives {
repositories.mavenDeployer {
configuration = configurations.deployerJars
// disable this otherwise it will fill up the server with stale jars
uniqueVersion = false
repository(url: "scp://updates.jmonkeyengine.org/var/www/updates/maven") {
authentication(userName: "www-updater", privateKey: "private/www-updater.key")
}
pom.withXml {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
pom.project {
name POM_NAME
description POM_DESCRIPTION
url POM_URL
@ -84,14 +97,6 @@ publishing {
}
}
}
}
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 {
// sourceSets*.allSource*.srcDirs*.each { File srcDir ->

@ -3,7 +3,9 @@ jmeVersion = 3.1.0
# Version used for application and settings folder, no spaces!
jmeMainVersion = 3.1
# 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
buildJavaDoc = true
@ -11,6 +13,7 @@ buildJavaDoc = true
# specify if SDK and Native libraries get built
buildSdkProject = true
buildNativeProjects = false
buildAndroidExamples = false
# Path to android NDK for building native libraries
#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
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-desktop')
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];
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];
float[] quaternionRotation = new float[] { localRotation.getX(), localRotation.getY(), localRotation.getZ(), localRotation.getW(), };
float[] eulerRotation = localRotation.toAngles(null);
@ -165,6 +165,8 @@ public class Ipo {
// calculating track data
for (int frame = startFrame; frame <= stopFrame; ++frame) {
boolean translationSet = false;
translation[0] = translation[1] = translation[2] = 0;
int index = frame - startFrame;
times[index] = index * timeBetweenFrames;// start + (frame - 1) * timeBetweenFrames;
for (int j = 0; j < bezierCurves.length; ++j) {
@ -173,15 +175,18 @@ public class Ipo {
// LOCATION
case AC_LOC_X:
translation[0] = (float) value;
translationSet = true;
break;
case AC_LOC_Y:
if (swapAxes && value != 0) {
value = -value;
}
translation[yIndex] = (float) value;
translationSet = true;
break;
case AC_LOC_Z:
translation[zIndex] = (float) value;
translationSet = true;
break;
// EULER ROTATION
@ -235,7 +240,11 @@ public class Ipo {
LOGGER.log(Level.WARNING, "Unknown ipo curve type: {0}.", bezierCurves[j].getType());
}
}
if(translationSet) {
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
} else {
translations[index] = new Vector3f();
}
if(boneContext != null) {
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");
if (pData.isNotNull()) {
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");
if (pTar != null && pTar.isNotNull()) {
targetOMA = pTar.getOldMemoryAddress();
@ -77,7 +77,7 @@ public abstract class Constraint {
}
} else {
// 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());
ipo = influenceIpo;

@ -7,6 +7,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Logger;
import com.jme3.animation.AnimChannel;
@ -209,7 +210,6 @@ public class SimulationNode {
TempVars vars = TempVars.get();
AnimChannel animChannel = animControl.createChannel();
// List<Bone> bonesWithConstraints = this.collectBonesWithConstraints(skeleton);
for (Animation animation : animations) {
float[] animationTimeBoundaries = this.computeAnimationTimeBoundaries(animation);
int maxFrame = (int) animationTimeBoundaries[0];
@ -233,7 +233,7 @@ public class SimulationNode {
for (Bone rootBone : skeleton.getRoots()) {
// ignore the 0-indexed bone
if (skeleton.getBoneIndex(rootBone) > 0) {
this.applyConstraints(rootBone, alteredOmas, applied, frame);
this.applyConstraints(rootBone, alteredOmas, applied, frame, new Stack<Bone>());
}
}
@ -294,18 +294,21 @@ public class SimulationNode {
* the set of OMAS of the altered bones (is populated if necessary)
* @param frame
* 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) {
if (!bonesStack.contains(bone)) {
bonesStack.push(bone);
BoneContext boneContext = blenderContext.getBoneContext(bone);
if (!applied.contains(boneContext.getBoneOma())) {
List<Constraint> constraints = this.findConstraints(boneContext.getBoneOma(), blenderContext);
if (constraints != null && constraints.size() > 0) {
// TODO: BEWARE OF INFINITE LOOPS !!!!!!!!!!!!!!!!!!!!!!!!!!
for (Constraint constraint : constraints) {
if (constraint.getTargetOMA() != null && constraint.getTargetOMA() > 0L) {
// first apply constraints of the target bone
BoneContext targetBone = blenderContext.getBoneContext(constraint.getTargetOMA());
this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame);
this.applyConstraints(targetBone.getBone(), alteredOmas, applied, frame, bonesStack);
}
constraint.apply(frame);
if (constraint.getAlteredOmas() != null) {
@ -320,9 +323,11 @@ public class SimulationNode {
List<Bone> children = bone.getChildren();
if (children != null && children.size() > 0) {
for (Bone child : bone.getChildren()) {
this.applyConstraints(child, alteredOmas, applied, frame);
this.applyConstraints(child, alteredOmas, applied, frame, bonesStack);
}
}
bonesStack.pop();
}
}
/**

@ -30,6 +30,8 @@ public abstract class ConstraintDefinition {
protected Set<Long> alteredOmas;
/** The variable that determines if the constraint will alter the track in any way. */
protected boolean trackToBeChanged = true;
/** The name of the constraint. */
protected String constraintName;
/**
* Loads a constraint definition based on the constraint definition
@ -54,6 +56,10 @@ public abstract class ConstraintDefinition {
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
* it is possible to tell that even before the constraint baking simulation is started, so we can discard such bones from constraint

@ -92,7 +92,7 @@ public class ConstraintDefinitionFactory {
* this exception is thrown when the blender file is somehow
* 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) {
return new ConstraintDefinitionNull(null, ownerOMA, blenderContext);
}
@ -100,7 +100,9 @@ public class ConstraintDefinitionFactory {
Class<? extends ConstraintDefinition> constraintDefinitionClass = CONSTRAINT_CLASSES.get(constraintClassName);
if (constraintDefinitionClass != null) {
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) {
throw new BlenderFileException(e.getLocalizedMessage(), e);
} catch (SecurityException e) {
@ -113,9 +115,9 @@ public class ConstraintDefinitionFactory {
throw new BlenderFileException(e.getLocalizedMessage(), e);
}
} else {
String constraintName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName);
if (constraintName != null) {
return new UnsupportedConstraintDefinition(constraintName);
String unsupportedConstraintClassName = UNSUPPORTED_CONSTRAINTS.get(constraintClassName);
if (unsupportedConstraintClassName != null) {
return new UnsupportedConstraintDefinition(unsupportedConstraintClassName);
} else {
throw new BlenderFileException("Unknown constraint type: " + constraintClassName);
}

@ -1,40 +1,44 @@
package com.jme3.scene.plugins.blender.constraints.definitions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.ejml.simple.SimpleMatrix;
import com.jme3.animation.Bone;
import com.jme3.math.Transform;
import com.jme3.math.Vector3f;
import com.jme3.scene.plugins.blender.BlenderContext;
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.file.Structure;
import com.jme3.scene.plugins.blender.math.DQuaternion;
import com.jme3.scene.plugins.blender.math.DTransform;
import com.jme3.scene.plugins.blender.math.Matrix;
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)
*/
public class ConstraintDefinitionIK extends ConstraintDefinition {
private static final float MIN_DISTANCE = 0.0001f;
private static final float MIN_DISTANCE = 0.001f;
private static final float MIN_ANGLE_CHANGE = 0.001f;
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. */
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. */
private boolean useTail;
/** The amount of iterations of the algorithm. */
private int iterations;
/** The count of bones' chain. */
private int bonesCount = -1;
public ConstraintDefinitionIK(Structure constraintData, Long ownerOMA, BlenderContext 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
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
}
DQuaternion q = new DQuaternion();
Vector3d t = new Vector3d(targetTransform.getTranslation());
List<BoneContext> bones = this.loadBones();
if (bones == null) {
bones = new BonesChain((Bone) this.getOwner(), useTail, bonesAffected, alteredOmas, blenderContext);
}
if (bones.size() == 0) {
bonesCount = 0;
return;// no need to do anything
}
double distanceFromTarget = Double.MAX_VALUE;
target.set(targetTransform.getTranslation().x, targetTransform.getTranslation().y, targetTransform.getTranslation().z);
int iterations = this.iterations;
if (bones.size() == 1) {
iterations = 1;// if only one bone is in the chain then only one iteration that will properly rotate it will be needed
} else {
// if the target cannot be rached by the bones' chain then the chain will become straight and point towards the target
// 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());
if (bonesCount < 0) {
bonesCount = bones.size();
rotationVectors = new Vector3d[bonesCount];
for (int i = 0; i < bonesCount; ++i) {
rotationVectors[i] = new Vector3d();
}
J = new Matrix(3, bonesCount);
}
iterations = 0;
}
BoneContext topBone = bones.get(0);
for (int i = 0; i < iterations; ++i) {
DTransform topBoneTransform = bones.getWorldTransform(topBone);
Vector3d e = topBoneTransform.getTranslation().add(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
distanceFromTarget = e.distance(target);
if (distanceFromTarget <= MIN_DISTANCE) {
break;
}
List<Transform> bestSolution = new ArrayList<Transform>(bones.size());
double bestSolutionDistance = Double.MAX_VALUE;
BoneContext topBone = bones.get(0);
for (int i = 0; i < iterations && distanceFromTarget > MIN_DISTANCE; ++i) {
deltaP.setColumn(0, 0, target.x - e.x, target.y - e.y, target.z - e.z);
int column = 0;
for (BoneContext boneContext : bones) {
Bone bone = boneContext.getBone();
DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD));
DTransform boneWorldTransform = new DTransform(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD));
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
DTransform boneWorldTransform = bones.getWorldTransform(boneContext);
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();
Vector3d target = t.subtract(j).normalizeLocal();
double angle = currentDir.angleBetween(target);
if (angle != 0) {
Vector3d cross = currentDir.crossLocal(target).normalizeLocal();
q.fromAngleAxis(angle, cross);
SimpleMatrix deltaThetas = J_1.mult(deltaP);
if (deltaThetas.elementMaxAbs() < MIN_ANGLE_CHANGE) {
break;
}
for (int j = 0; j < deltaThetas.numRows(); ++j) {
double angle = deltaThetas.get(j, 0);
Vector3d rotationVector = rotationVectors[j];
tempDQuaternion.fromAngleAxis(angle, rotationVector);
BoneContext boneContext = bones.get(j);
Bone bone = boneContext.getBone();
if (bone.equals(this.getOwner())) {
if (boneContext.isLockX()) {
q.set(0, q.getY(), q.getZ(), q.getW());
tempDQuaternion.set(0, tempDQuaternion.getY(), tempDQuaternion.getZ(), tempDQuaternion.getW());
}
if (boneContext.isLockY()) {
q.set(q.getX(), 0, q.getZ(), q.getW());
tempDQuaternion.set(tempDQuaternion.getX(), 0, tempDQuaternion.getZ(), tempDQuaternion.getW());
}
if (boneContext.isLockZ()) {
q.set(q.getX(), q.getY(), 0, q.getW());
tempDQuaternion.set(tempDQuaternion.getX(), tempDQuaternion.getY(), 0, tempDQuaternion.getW());
}
}
boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation()));
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform.toTransform());
} else {
iterations = 0;
break;
DTransform boneTransform = bones.getWorldTransform(boneContext);
boneTransform.getRotation().set(tempDQuaternion.mult(boneTransform.getRotation()));
bones.setWorldTransform(boneContext, boneTransform);
}
}
DTransform topBoneTransform = new DTransform(constraintHelper.getTransform(topBone.getArmatureObjectOMA(), topBone.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD));
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
distanceFromTarget = e.distance(t);
if(distanceFromTarget < bestSolutionDistance) {
bestSolutionDistance = distanceFromTarget;
bestSolution.clear();
for(BoneContext boneContext : bones) {
bestSolution.add(constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD));
}
}
}
// applying best solution
for(int i=0;i<bestSolution.size();++i) {
// applying the results
for (int i = bonesCount - 1; i >= 0; --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
@ -174,56 +160,68 @@ public class ConstraintDefinitionIK extends ConstraintDefinition {
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() {
List<BoneContext> bones = new ArrayList<BoneContext>();
Bone bone = (Bone) this.getOwner();
if (bone == null) {
return bones;
}
private static class BonesChain extends ArrayList<BoneContext> {
private static final long serialVersionUID = -1850524345643600718L;
private List<Matrix> bonesMatrices = new ArrayList<Matrix>();
public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection<Long> alteredOmas, BlenderContext blenderContext) {
if (bone != null) {
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
if (!useTail) {
bone = bone.getParent();
}
chainLength = 0;
while (bone != null) {
while (bone != null && (bonesAffected <= 0 || this.size() < bonesAffected)) {
BoneContext boneContext = blenderContext.getBoneContext(bone);
chainLength += boneContext.getLength();
bones.add(boneContext);
this.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();
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());
if (bone != null) {
boneContext = blenderContext.getBoneContext(bone);
Transform parentWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
Vector3f parentWorldTranslation = parentWorldTransform.getTranslation();
chainLength += boneWorldTranslation.distance(parentWorldTranslation);
bone = bone.getParent();
}
}
return bones;
}
@Override
public boolean isTrackToBeChanged() {
if (trackToBeChanged) {
// 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;
public DTransform getWorldTransform(BoneContext bone) {
int index = this.indexOf(bone);
return this.getWorldMatrix(index).toTransform();
}
public void setWorldTransform(BoneContext bone, DTransform transform) {
int index = this.indexOf(bone);
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);
}
return trackToBeChanged;
bonesMatrices.set(index, boneMatrix);
}
@Override
public boolean isTargetRequired() {
return true;
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;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.scene.plugins.blender.BlenderContext;
@ -171,8 +172,21 @@ public class FileBlockHeader {
BLOCK_IP00('I' << 24 | 'P' << 16), // ipo
BLOCK_AC00('A' << 24 | 'C' << 16), // action
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
| 'S' << 8 | 'T'), BLOCK_UNKN(0);
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_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;
@ -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) };
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;
}
}

@ -164,6 +164,134 @@ public final class DQuaternion implements Savable, Cloneable, java.io.Serializab
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
* 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;
import com.jme3.export.*;
import com.jme3.math.Transform;
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>
* <br>
@ -57,6 +61,12 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
private Vector3d translation;
private Vector3d scale;
public DTransform() {
translation = new Vector3d();
rotation = new DQuaternion();
scale = new Vector3d();
}
public DTransform(Transform transform) {
translation = new Vector3d(transform.getTranslation());
rotation = new DQuaternion(transform.getRotation());
@ -67,6 +77,14 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
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.
* @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,37 +811,70 @@ extern "C" {
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: getAngularFactor
* Signature: (J)F
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
JNIEXPORT jfloat JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor
(JNIEnv *env, jobject object, jlong bodyId) {
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor
(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 0;
return;
}
return body->getAngularFactor().getX();
jmeBulletUtil::convert(env, &body->getAngularFactor(), factor);
}
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: setAngularFactor
* Signature: (JF)V
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
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);
if (body == NULL) {
jclass newExc = env->FindClass("java/lang/NullPointerException");
env->ThrowNew(newExc, "The native object does not exist.");
return;
}
btVector3 vec1 = btVector3();
vec1.setX(value);
vec1.setY(value);
vec1.setZ(value);
body->setAngularFactor(vec1);
btVector3 vec = btVector3();
jmeBulletUtil::convert(env, factor, &vec);
body->setAngularFactor(vec);
}
/*
* 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

@ -396,18 +396,35 @@ JNIEXPORT jfloat JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngula
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: getAngularFactor
* Signature: (J)F
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
JNIEXPORT jfloat JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor
(JNIEnv *, jobject, jlong);
JNIEXPORT void JNICALL Java_com_jme3_bullet_objects_PhysicsRigidBody_getAngularFactor
(JNIEnv *, jobject, jlong, jobject);
/*
* Class: com_jme3_bullet_objects_PhysicsRigidBody
* Method: setAngularFactor
* Signature: (JF)V
* Signature: (JLcom/jme3/math/Vector3f;)V
*/
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
}

@ -93,8 +93,10 @@ public class CapsuleCollisionShape extends CollisionShape{
*/
@Override
public void setScale(Vector3f scale) {
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 {
super.write(ex);

@ -627,16 +627,44 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
private native float getAngularSleepingThreshold(long objectId);
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) {
setAngularFactor(objectId, new Vector3f(factor, factor, factor));
}
public void setAngularFactor(Vector3f factor) {
setAngularFactor(objectId, factor);
}
private native void setAngularFactor(long objectId, float factor);
private native void setAngularFactor(long objectId, Vector3f factor);
public Vector3f getLinearFactor() {
Vector3f vec = new Vector3f();
getLinearFactor(objectId, vec);
return vec;
}
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
@ -673,7 +701,13 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
capsule.write(getGravity(), "gravity", Vector3f.ZERO);
capsule.write(getFriction(), "friction", 0.5f);
capsule.write(getRestitution(), "restitution", 0);
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(getLinearDamping(), "linearDamping", 0);
@ -703,7 +737,13 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
setKinematic(capsule.readBoolean("kinematic", false));
setRestitution(capsule.readFloat("restitution", 0));
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));
setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f));
setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0));

@ -12,55 +12,23 @@ sourceSets {
}
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.ajoberstar:gradle-git:1.0.0-rc.1'
}
}
import java.text.SimpleDateFormat
import org.ajoberstar.grgit.*
task updateVersion << {
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)
task updateVersionPropertiesFile << {
def verfile = file('src/main/resources/com/jme3/system/version.properties')
verfile.text = "# THIS IS AN AUTO-GENERATED FILE..\n" +
"# DO NOT MODIFY!\n" +
"build.date=${jmeBuildDate}\n" +
"git.revision=${jmeRevision}\n" +
"git.branch=${jmeBranchName}\n" +
"git.hash=${jmeGitHash}\n" +
"git.hash.short=${jmeShortGitHash}\n" +
"git.tag=${jmeGitTag}\n" +
"name.full=jMonkeyEngine ${jmeFullVersion}\n" +
"version.full=${jmeFullVersion}\n" +
"version.number=${jmeVersion}\n" +
"version.tag=${jmeVersionTag}"
}
compileJava.dependsOn(updateVersionPropertiesFile)
dependencies {
}

@ -553,7 +553,6 @@ public final class Bone implements Savable {
Vector3f translate = modelPos.add(rotate.mult(scale.mult(modelBindInversePos, tmp2), tmp2), tmp2);
// Populating the matrix
outTransform.loadIdentity();
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.
*/
private transient boolean hwSkinningDesired = false;
private transient boolean hwSkinningDesired = true;
/**
* Hardware skinning is currently being used.
@ -347,10 +347,21 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
public Control cloneForSpatial(Spatial spatial) {
Node clonedNode = (Node) spatial;
AnimControl ctrl = spatial.getControl(AnimControl.class);
SkeletonControl clone = new SkeletonControl();
AnimControl ctrl = spatial.getControl(AnimControl.class);
if (ctrl != null) {
// AnimControl is responsible for cloning the skeleton, not
// SkeletonControl.
clone.skeleton = ctrl.getSkeleton();
} else {
// If there's no AnimControl, create the clone ourselves.
clone.skeleton = new Skeleton(skeleton);
}
clone.hwSkinningDesired = this.hwSkinningDesired;
clone.hwSkinningEnabled = this.hwSkinningEnabled;
clone.hwSkinningSupported = this.hwSkinningSupported;
clone.hwSkinningTested = this.hwSkinningTested;
clone.setSpatial(clonedNode);

@ -60,7 +60,7 @@ import com.jme3.scene.control.Control;
*/
public class StatsView extends Node implements Control {
private BitmapText[] labels;
private BitmapText statText;
private Statistics statistics;
private String[] statLabels;
@ -81,20 +81,17 @@ public class StatsView extends Node implements Control {
statLabels = statistics.getLabels();
statData = new int[statLabels.length];
labels = new BitmapText[statLabels.length];
BitmapFont font = manager.loadFont("Interface/Fonts/Console.fnt");
for (int i = 0; i < labels.length; i++){
labels[i] = new BitmapText(font);
labels[i].setLocalTranslation(0, labels[i].getLineHeight() * (i+1), 0);
attachChild(labels[i]);
}
statText = new BitmapText(font);
statText.setLocalTranslation(0, statText.getLineHeight() * statLabels.length, 0);
attachChild(statText);
addControl(this);
}
public float getHeight() {
return labels[0].getLineHeight() * statLabels.length;
return statText.getLineHeight() * statLabels.length;
}
public void update(float tpf) {
@ -103,11 +100,14 @@ public class StatsView extends Node implements Control {
return;
statistics.getData(statData);
for (int i = 0; i < labels.length; i++) {
stringBuilder.setLength(0);
stringBuilder.append(statLabels[i]).append(" = ").append(statData[i]);
labels[i].setText(stringBuilder);
// Need to walk through it backwards, as the first label
// 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
// 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 int channel = -1;
protected Vector3f velocity = new Vector3f();
protected boolean reverbEnabled = true;
protected boolean reverbEnabled = false;
protected float maxDistance = 200; // 200 meters
protected float refDistance = 10; // 10 meters
protected Filter reverbFilter;
@ -410,6 +410,14 @@ public class AudioNode extends Node implements AudioSource {
}
}
@Override
public float getPlaybackTime() {
if (channel >= 0)
return getRenderer().getSourcePlaybackTime(this);
else
return 0;
}
public Vector3f getPosition() {
return getWorldTranslation();
}

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

@ -96,6 +96,11 @@ public interface AudioSource {
*/
public float getTimeOffset();
/**
* @return the current playback position of the source in seconds.
*/
public float getPlaybackTime();
/**
* @return The velocity of the audio source.
*

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

@ -301,6 +301,58 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
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) {
checkDead();
synchronized (threadLock) {
@ -648,6 +700,7 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
private boolean fillStreamingSource(int sourceId, AudioStream stream, boolean looping) {
boolean success = false;
int processed = al.alGetSourcei(sourceId, AL_BUFFERS_PROCESSED);
int unqueuedBufferBytes = 0;
for (int i = 0; i < processed; i++) {
int buffer;
@ -656,6 +709,11 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
al.alSourceUnqueueBuffers(sourceId, 1, ib);
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);
if (!active && !stream.isEOF()) {
@ -683,6 +741,8 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
}
}
stream.setUnqueuedBufferBytes(stream.getUnqueuedBufferBytes() + unqueuedBufferBytes);
return success;
}

@ -702,8 +702,10 @@ public class Cinematic extends AbstractCinematicEvent implements AppState {
dispose();
cinematicEvents.clear();
timeLine.clear();
if (eventsData != null) {
eventsData.clear();
}
}
/**
* used internally to cleanup the cinematic. Called when the clear() method

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

@ -48,6 +48,7 @@ import com.jme3.math.Vector3f;
import com.jme3.scene.CollisionData;
import com.jme3.scene.Mesh;
import com.jme3.scene.Mesh.Mode;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.scene.mesh.VirtualIndexBuffer;
@ -114,8 +115,13 @@ public class BIHTree implements CollisionData {
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();
FloatBuffer vb = (FloatBuffer) vBuffer.getData();
if (ib == null) {
ib = new VirtualIndexBuffer(mesh.getVertexCount(), mesh.getMode());
} else if (mesh.getMode() != Mode.Triangles) {

@ -46,22 +46,18 @@ public interface JmeExporter {
*
* @param object The savable to export
* @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
*/
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.
*
* @param object The savable to export
* @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
*/
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.

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,6 +32,7 @@
package com.jme3.light;
import com.jme3.bounding.BoundingBox;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial;
@ -49,6 +50,13 @@ import com.jme3.util.TempVars;
*/
public class AmbientLight extends Light {
public AmbientLight() {
}
public AmbientLight(ColorRGBA color) {
super(color);
}
@Override
public boolean intersectsBox(BoundingBox box, TempVars vars) {
return true;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
* All rights reserved.
*
* 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.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial;
@ -53,6 +54,30 @@ public class DirectionalLight extends Light {
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
public void computeLastDistance(Spatial 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.
*/
public void setDirection(Vector3f dir){
public final void setDirection(Vector3f dir){
direction.set(dir);
if (!direction.isUnitVector()) {
direction.normalizeLocal();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
* All rights reserved.
*
* 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
@ -115,6 +115,13 @@ public abstract class Light implements Savable, Cloneable {
boolean frustumCheckNeeded = true;
boolean intersectsFrustum = false;
protected Light() {
}
protected Light(ColorRGBA color) {
setColor(color);
}
/**
* Returns the color of the light.
*

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,14 +32,13 @@
package com.jme3.light;
import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Plane;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.scene.Spatial;
@ -62,6 +61,52 @@ public class PointLight extends Light {
protected float radius = 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
public void computeLastDistance(Spatial owner) {
if (owner.getWorldBound() != null) {
@ -88,7 +133,7 @@ public class PointLight extends 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);
}
@ -115,13 +160,13 @@ public class PointLight extends Light {
*
* @throws IllegalArgumentException If radius is negative
*/
public void setRadius(float radius) {
public final void setRadius(float radius) {
if (radius < 0) {
throw new IllegalArgumentException("Light radius cannot be negative");
}
this.radius = radius;
if (radius != 0) {
this.invRadius = 1 / radius;
if (radius != 0f) {
this.invRadius = 1f / radius;
} else {
this.invRadius = 0;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
* All rights reserved.
*
* 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.BoundingVolume;
import com.jme3.export.*;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Plane;
import com.jme3.math.Vector3f;
@ -44,16 +45,16 @@ import java.io.IOException;
/**
* Represents a spot light.
* A spot light emmit a cone of light from a position and in a direction.
* It can be used to fake torch lights or car's lights.
* A spot light emits a cone of light from a position and in a direction.
* It can be used to fake torch lights or cars' lights.
* <p>
* 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
* 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.
* the spot inner angle determin 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 light intensity slowly decrease between the inner cone and the outer cone.
* the spot inner angle determines the cone of light where light has full influence.
* the spot outer angle determines the cone global cone of light of the spot light.
* the light intensity slowly decreases between the inner cone and the outer cone.
* @author Nehon
*/
public class SpotLight extends Light {
@ -63,17 +64,102 @@ public class SpotLight extends Light {
protected float spotInnerAngle = FastMath.QUARTER_PI / 8;
protected float spotOuterAngle = FastMath.QUARTER_PI / 6;
protected float spotRange = 100;
protected float invSpotRange = 1 / 100;
protected float invSpotRange = 1f / 100;
protected float packedAngleCos = 0;
protected float outerAngleCosSqr, outerAngleSinSqr;
protected float outerAngleSinRcp, outerAngleSin, outerAngleCos;
/**
* Creates a SpotLight.
*/
public SpotLight() {
super();
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() {
float innerCos = FastMath.cos(spotInnerAngle);
outerAngleCos = FastMath.cos(spotOuterAngle);
@ -189,7 +275,7 @@ public class SpotLight extends Light {
return direction;
}
public void setDirection(Vector3f direction) {
public final void setDirection(Vector3f direction) {
this.direction.set(direction);
}
@ -197,7 +283,7 @@ public class SpotLight extends Light {
return position;
}
public void setPosition(Vector3f position) {
public final void setPosition(Vector3f position) {
this.position.set(position);
}

@ -1147,10 +1147,11 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
*/
public void render(Geometry geom, LightList lights, RenderManager 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) {
r.applyRenderState(rm.getForcedRenderState());

@ -102,6 +102,7 @@ public class TechniqueDef implements Savable {
private List<ShaderNode> shaderNodes;
private ShaderGenerationInfo shaderGenerationInfo;
private boolean noRender = false;
private RenderState renderState;
private RenderState forcedRenderState;
@ -201,6 +202,28 @@ public class TechniqueDef implements Savable {
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
*/
@ -448,6 +471,7 @@ public class TechniqueDef implements Savable {
oc.write(lightMode, "lightMode", LightMode.Disable);
oc.write(shadowMode, "shadowMode", ShadowMode.Disable);
oc.write(renderState, "renderState", null);
oc.write(noRender, "noRender", false);
oc.write(usesNodes, "usesNodes", false);
oc.writeSavableArrayList((ArrayList)shaderNodes,"shaderNodes", null);
oc.write(shaderGenerationInfo, "shaderGenerationInfo", null);
@ -470,6 +494,7 @@ public class TechniqueDef implements Savable {
lightMode = ic.readEnum("lightMode", LightMode.class, LightMode.Disable);
shadowMode = ic.readEnum("shadowMode", ShadowMode.class, ShadowMode.Disable);
renderState = (RenderState) ic.readSavable("renderState", null);
noRender = ic.readBoolean("noRender", false);
if (ic.getSavableVersion(TechniqueDef.class) == 0) {
// Old version
@ -525,6 +550,6 @@ public class TechniqueDef implements Savable {
//todo: make toString return something usefull
@Override
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
* and returned as a Vector4f
* 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
* and returned as a ColorRGBA.
*
* Note that no correction will be performed on the alpha channel as it's
* conventionnally doesn't represent a color itself
* The x attribute will be fed with the r channel in sRGB space.
* 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.
*
* @return the color in sRGB color space as a ColorRGBA.
*/
public Vector4f getAsSrgb(){
Vector4f srgb = new Vector4f();
public ColorRGBA getAsSrgb() {
ColorRGBA srgb = new ColorRGBA();
float invGama = 1f / GAMMA;
srgb.x = (float)Math.pow(r, invGama);
srgb.y = (float)Math.pow(g, invGama);
srgb.z = (float)Math.pow(b, invGama);
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;
}

@ -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) {
loadIdentity();
TempVars vars = TempVars.get();
Vector3f f = vars.vect1.set(direction);
Vector3f s = vars.vect2.set(f).crossLocal(up);
Vector3f u = vars.vect3.set(s).crossLocal(f);
// s.normalizeLocal();
// u.normalizeLocal();
m00 = s.x;
m01 = s.y;
m02 = s.z;
m10 = u.x;
m11 = u.y;
m12 = u.z;
m20 = -f.x;
m21 = -f.y;
m22 = -f.z;
// m00 = -left.x;
// m10 = -left.y;
// m20 = -left.z;
//
// m01 = up.x;
// m11 = up.y;
// m21 = up.z;
//
// 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);
try {
Vector3f fwdVector = vars.vect1.set(direction);
Vector3f leftVector = vars.vect2.set(fwdVector).crossLocal(up);
Vector3f upVector = vars.vect3.set(leftVector).crossLocal(fwdVector);
m00 = leftVector.x;
m01 = leftVector.y;
m02 = leftVector.z;
m03 = -leftVector.dot(location);
m10 = upVector.x;
m11 = upVector.y;
m12 = upVector.z;
m13 = -upVector.dot(location);
m20 = -fwdVector.x;
m21 = -fwdVector.y;
m22 = -fwdVector.z;
m23 = fwdVector.dot(location);
m30 = 0f;
m31 = 0f;
m32 = 0f;
m33 = 1f;
} finally {
vars.release();
// transMatrix.multLocal(this);
// set(transMatrix);
}
}
/**

@ -288,6 +288,29 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
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
public String toString(){
return getClass().getSimpleName() + "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n"
@ -307,22 +330,21 @@ public final class Transform implements Savable, Cloneable, java.io.Serializable
return this;
}
@Override
public void write(JmeExporter e) throws IOException {
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(scale, "scale", Vector3f.UNIT_XYZ);
}
@Override
public void read(JmeImporter e) throws IOException {
InputCapsule capsule = e.getCapsule(this);
rot = (Quaternion)capsule.readSavable("rot", new Quaternion());
translation = (Vector3f)capsule.readSavable("translation", null);
if( translation == null ) {
translation = new Vector3f();
}
scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ);
rot.set((Quaternion)capsule.readSavable("rot", Quaternion.IDENTITY));
translation.set((Vector3f)capsule.readSavable("translation", Vector3f.ZERO));
scale.set((Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ));
}
@Override

@ -300,7 +300,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
public void postFrame(FrameBuffer out) {
FrameBuffer sceneBuffer = renderFrameBuffer;
if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL31)) {
if (renderFrameBufferMS != null && !renderer.getCaps().contains(Caps.OpenGL32)) {
renderer.copyFrameBuffer(renderFrameBufferMS, renderFrameBuffer, true);
} else if (renderFrameBufferMS != null) {
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
if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample)) {
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 msDepth = new Texture2D(width, height, numSamples, Format.Depth);
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.setDepthBuffer(Format.Depth);
filterTexture = new Texture2D(width, height, fbFormat);

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

@ -74,6 +74,7 @@ public interface GL {
public static final int GL_FRONT_AND_BACK = 0x408;
public static final int GL_GEQUAL = 0x206;
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_WRAP = 0x8507;
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_VERTEX_ATTRIBS = 0x8869;
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_NEAREST = 0x2600;
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_POINTS = 0x0;
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_REPEAT = 0x2901;
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_POSITIVE_Z = 0x8519;
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_MAX_LEVEL = 0x813D;
public static final int GL_TEXTURE_MIN_FILTER = 0x2801;

@ -34,7 +34,7 @@ package com.jme3.renderer.opengl;
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
*/
@ -43,6 +43,17 @@ public interface GL3 extends GL2 {
public static final int GL_DEPTH_STENCIL_ATTACHMENT = 0x821A;
public static final int GL_GEOMETRY_SHADER = 0x8DD9;
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 glBindVertexArray(int param1); /// GL3+

@ -34,7 +34,7 @@ package com.jme3.renderer.opengl;
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
*/

@ -42,6 +42,7 @@ public final class GLImageFormat {
public final int format;
public final int dataType;
public final boolean compressed;
public final boolean swizzleRequired;
/**
* Constructor for formats.
@ -55,6 +56,7 @@ public final class GLImageFormat {
this.format = format;
this.dataType = dataType;
this.compressed = false;
this.swizzleRequired = false;
}
/**
@ -63,11 +65,30 @@ public final class GLImageFormat {
* @param internalFormat OpenGL internal format
* @param format OpenGL format
* @param dataType OpenGL datatype
* @param compressed Format is compressed
*/
public GLImageFormat(int internalFormat, int format, int dataType, boolean compressed) {
this.internalFormat = internalFormat;
this.format = format;
this.dataType = dataType;
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);
}
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,
int glInternalFormat,
int glFormat,
@ -60,6 +67,14 @@ public final class GLImageFormats {
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,
int glCompressedFormat,
int glFormat,
@ -88,6 +103,19 @@ public final class GLImageFormats {
public static GLImageFormat[][] getFormatsForCaps(EnumSet<Caps> caps) {
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.CoreProfile)) {
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.util.BufferUtils;
import com.jme3.util.ListMap;
import com.jme3.util.MipMapGenerator;
import com.jme3.util.NativeObjectManager;
import java.nio.*;
import java.util.Arrays;
@ -83,21 +84,6 @@ public class GLRenderer implements Renderer {
private final EnumSet<Caps> caps = EnumSet.noneOf(Caps.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 final Statistics statistics = new Statistics();
private int vpX, vpY, vpW, vpH;
@ -120,7 +106,7 @@ public class GLRenderer implements Renderer {
this.gl4 = gl instanceof GL4 ? (GL4)gl : null;
this.glfbo = glfbo;
this.glext = glext;
this.texUtil = new TextureUtil(gl, gl2, glext, context);
this.texUtil = new TextureUtil(gl, gl2, glext);
}
@Override
@ -271,7 +257,11 @@ public class GLRenderer implements Renderer {
// gl.glGetInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, intBuf16);
// fragUniforms = intBuf16.get(0);
// 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.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE));
limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE));
@ -365,7 +355,6 @@ public class GLRenderer implements Renderer {
if (hasExtension("GL_ARB_texture_non_power_of_two") ||
hasExtension("GL_OES_texture_npot") ||
hasExtension("GL_APPLE_texture_2D_limited_npot") ||
caps.contains(Caps.OpenGL30)) {
caps.add(Caps.NonPowerOfTwoTextures);
} else {
@ -387,7 +376,9 @@ public class GLRenderer implements Renderer {
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);
limits.put(Limits.RenderBufferSize, getInteger(GLFbo.GL_MAX_RENDERBUFFER_SIZE_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));
if (limits.get(Limits.FrameBufferMrtAttachments) > 1) {
caps.add(Caps.FrameBufferMRT);
@ -1075,6 +1066,9 @@ public class GLRenderer implements Renderer {
stringBuf.append("\n");
} else {
if (gles2) {
// request GLSL ES (1.00) when compiling under GLES2.
stringBuf.append("#version 100\n");
if (source.getType() == ShaderType.Fragment) {
// GLES2 requires precision qualifier.
stringBuf.append("precision mediump float;\n");
@ -1091,6 +1085,7 @@ public class GLRenderer implements Renderer {
if (linearizeSrgbImages) {
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.getSource());
@ -1428,7 +1423,7 @@ public class GLRenderer implements Renderer {
// Check NPOT requirements
checkNonPowerOfTwo(tex);
updateTexImageData(image, tex.getType(), 0);
updateTexImageData(image, tex.getType(), 0, false);
// NOTE: For depth textures, sets nearest/no-mips mode
// Required to fix "framebuffer unsupported"
@ -1858,10 +1853,6 @@ public class GLRenderer implements Renderer {
}
}
if (context.pointSprite) {
return; // Attempt to fix glTexParameter crash for some ATI GPUs
}
// repeat modes
switch (tex.getType()) {
case ThreeDimensional:
@ -1965,8 +1956,10 @@ public class GLRenderer implements Renderer {
* @param img The image to upload
* @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 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();
if (texId == -1) {
// create texture
@ -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) {
List<ByteBuffer> data = img.getData();
List<ByteBuffer> data = imageForUpload.getData();
if (data.size() != 6) {
logger.log(Level.WARNING, "Invalid texture: {0}\n"
+ "Cubemap textures must contain 6 data units.", img);
return;
}
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) {
if (!caps.contains(Caps.TextureArray)) {
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
texUtil.uploadTexture(img, target, -1, linearizeSrgbImages);
texUtil.uploadTexture(imageForUpload, target, -1, linearizeSrgbImages);
for (int i = 0; i < data.size(); i++) {
// upload each slice of 2D array in turn
// this time with the appropriate index
texUtil.uploadTexture(img, target, i, linearizeSrgbImages);
texUtil.uploadTexture(imageForUpload, target, i, linearizeSrgbImages);
}
} else {
texUtil.uploadTexture(img, target, 0, linearizeSrgbImages);
texUtil.uploadTexture(imageForUpload, target, 0, linearizeSrgbImages);
}
if (img.getMultiSamples() != imageSamples) {
@ -2097,9 +2096,23 @@ public class GLRenderer implements Renderer {
Image image = tex.getImage();
if (image.isUpdateNeeded() || (image.isGeneratedMipmapsRequired() && !image.isMipmapsGenerated())) {
// Check NPOT requirements
boolean scaleToPot = false;
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);
updateTexImageData(image, tex.getType(), unit, scaleToPot);
}
int texId = image.getId();
@ -2648,7 +2661,7 @@ public class GLRenderer implements Renderer {
public void setMainFrameBufferSrgb(boolean enableSrgb) {
// Gamma correction
if (!caps.contains(Caps.Srgb)) {
if (!caps.contains(Caps.Srgb) && enableSrgb) {
// Not supported, sorry.
logger.warning("sRGB framebuffer is not supported " +
"by video hardware, but was requested.");

@ -54,14 +54,12 @@ final class TextureUtil {
private final GL gl;
private final GL2 gl2;
private final GLExt glext;
private final RenderContext context;
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.gl2 = gl2;
this.glext = glext;
this.context = context;
}
public void initialize(EnumSet<Caps> caps) {
@ -92,6 +90,8 @@ final class TextureUtil {
}
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);
if (glFmt == null && isSrgb) {
glFmt = getImageFormat(fmt, false);
@ -103,6 +103,33 @@ final class TextureUtil {
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) {
if (format.compressed && data != null) {
if (target == GL2.GL_TEXTURE_3D) {
@ -243,6 +270,11 @@ final class TextureUtil {
int samples = image.getMultiSamples();
// For OGL3 core: setup texture swizzle.
if (oglFormat.swizzleRequired) {
setupTextureSwizzle(target, jmeFormat);
}
for (int i = 0; i < mipSizes.length; i++) {
int mipWidth = Math.max(1, width >> i);
int mipHeight = Math.max(1, height >> i);

@ -119,19 +119,6 @@ public class BatchNode extends GeometryGroupNode {
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){
return g.cachedWorldMat;
@ -169,7 +156,7 @@ public class BatchNode extends GeometryGroupNode {
nvb.updateData(normBuf);
batch.needMeshUpdate = true;
batch.geometry.updateModelBound();
}
}
@ -234,7 +221,7 @@ public class BatchNode extends GeometryGroupNode {
batch.geometry.setMesh(m);
batch.geometry.getMesh().updateCounts();
batch.geometry.getMesh().updateBound();
batch.geometry.updateModelBound();
batches.add(batch);
}
if (batches.size() > 0) {
@ -457,6 +444,7 @@ public class BatchNode extends GeometryGroupNode {
int maxWeights = -1;
Mesh.Mode mode = null;
float lineWidth = 1f;
for (Geometry geom : geometries) {
totalVerts += geom.getVertexCount();
totalTris += geom.getTriangleCount();
@ -465,6 +453,7 @@ public class BatchNode extends GeometryGroupNode {
maxVertCount = geom.getVertexCount();
}
Mesh.Mode listMode;
float listLineWidth = 1f;
int components;
switch (geom.getMesh().getMode()) {
case Points:
@ -475,6 +464,7 @@ public class BatchNode extends GeometryGroupNode {
case LineStrip:
case Lines:
listMode = Mesh.Mode.Lines;
listLineWidth = geom.getMesh().getLineWidth();
components = 2;
break;
case TriangleFan:
@ -506,11 +496,19 @@ public class BatchNode extends GeometryGroupNode {
+ " primitive types: " + 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;
}
outMesh.setMaxNumWeights(maxWeights);
outMesh.setMode(mode);
outMesh.setLineWidth(lineWidth);
if (totalVerts >= 65536) {
// make sure we create an UnsignedInt buffer so
// we can fit all of the meshes
@ -582,12 +580,14 @@ public class BatchNode extends GeometryGroupNode {
if (VertexBuffer.Type.Tangent.ordinal() == bufType) {
useTangents = true;
}
} else {
if (inBuf == null) {
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");
} else if (outBuf == null) {
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);
// for (int vert = 0; vert < geomVertCount; vert++) {
// int curGlobalVertIndex = globalVertIndex + vert;
// inBuf.copyElement(vert, outBuf, curGlobalVertIndex);
// }
}
}
}
@ -746,7 +746,6 @@ public class BatchNode extends GeometryGroupNode {
}
}
Geometry geometry;
boolean needMeshUpdate = false;
}
protected void setNeedsFullRebatch(boolean needsFullRebatch) {

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

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

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

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

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

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

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

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

@ -172,15 +172,6 @@ public class JmeSystem {
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
* feels is appropriate. If this is a headless or an offscreen surface

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

@ -44,7 +44,9 @@ public class DefaultImageRaster extends ImageRaster {
private final ImageCodec codec;
private final int width;
private final int height;
private final int offset;
private final byte[] temp;
private final boolean convertToLinear;
private int slice;
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.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.codec = ImageCodec.lookup(image.getFormat());
this.width = image.getWidth();
this.height = image.getHeight();
if (codec instanceof ByteAlignedImageCodec || codec instanceof ByteOffsetImageCodec) {
this.temp = new byte[codec.bpp];
} else {
@ -86,6 +115,12 @@ public class DefaultImageRaster extends ImageRaster {
public void setPixel(int x, int y, ColorRGBA color) {
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
if (codec.isGray) {
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);
break;
}
codec.writeComponents(getBuffer(), x, y, width, 0, components, temp);
codec.writeComponents(getBuffer(), x, y, width, offset, components, temp);
image.setUpdateNeeded();
}
@ -128,7 +163,7 @@ public class DefaultImageRaster extends ImageRaster {
public ColorRGBA getPixel(int x, int y, ColorRGBA store) {
rangeCheck(x, y);
codec.readComponents(getBuffer(), x, y, width, 0, components, temp);
codec.readComponents(getBuffer(), x, y, width, offset, components, temp);
if (store == null) {
store = new ColorRGBA();
}
@ -169,6 +204,12 @@ public class DefaultImageRaster extends ImageRaster {
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;
}
}

@ -71,21 +71,42 @@ public abstract class ImageRaster {
* @param image The image to read / write to.
* @param slice Which slice to use. Only applies to 3D images, 2D image
* 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) {
return JmeSystem.createImageRaster(image, slice);
return create(image, slice, 0, false);
}
/**
* Create new image reader / writer for 2D images.
*
* @param image The image to read / write to.
* @return An ImageRaster to read / write to the image.
*/
public static ImageRaster create(Image image) {
if (image.getData().size() > 1) {
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() {

@ -36,6 +36,7 @@ import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import java.io.UnsupportedEncodingException;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
@ -1010,11 +1011,15 @@ public final class BufferUtils {
}
public static ByteBuffer createByteBuffer(String data) {
byte[] bytes = data.getBytes();
try {
byte[] bytes = data.getBytes("UTF-8");
ByteBuffer bb = createByteBuffer(bytes.length);
bb.put(bytes);
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 {
protected BufferedInputStream in;
protected BufferedReader inRead;
/**
* 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) {
this.in = new BufferedInputStream(in);
inRead = new BufferedReader(new InputStreamReader(in));
}
public int read() throws IOException {
@ -141,7 +139,7 @@ public class LittleEndien extends InputStream implements DataInput {
}
public String readLine() throws IOException {
return inRead.readLine();
throw new IOException("Unsupported operation");
}
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();
return new TriangleData(
tangent,
binormal,
normal);
tangent.clone(),
binormal.clone(),
normal.clone());
} finally {
tmp.release();
}

@ -37,6 +37,7 @@ varying vec3 SpecularSum;
#endif
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)
uniform float m_ParallaxHeight;
varying vec3 vViewDirPrlx;
#endif
#ifdef LIGHTMAP
@ -78,18 +79,18 @@ void main(){
#ifdef STEEP_PARALLAX
#ifdef NORMALMAP_PARALLAX
//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
//parallax map is a texture
newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
#endif
#else
#ifdef NORMALMAP_PARALLAX
//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
//parallax map is a texture
newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDirPrlx, texCoord, m_ParallaxHeight);
#endif
#endif
#else

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

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

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

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

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

@ -54,8 +54,8 @@ MaterialDef Unshaded {
}
Technique {
VertexShader GLSL100: Common/MatDefs/Misc/Unshaded.vert
FragmentShader GLSL100: Common/MatDefs/Misc/Unshaded.frag
VertexShader GLSL150: Common/MatDefs/Misc/Unshaded.vert
FragmentShader GLSL150: Common/MatDefs/Misc/Unshaded.frag
WorldParameters {
WorldViewProjectionMatrix
@ -76,6 +76,25 @@ MaterialDef Unshaded {
}
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 {

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

@ -1,35 +1,25 @@
MaterialDef UnshadedNodes {
MaterialParameters {
Texture2D ColorMap
Texture2D LightMap
Color Color (Color)
Boolean VertexColor (UseVertexColor)
Boolean SeparateTexCoord
// Alpha threshold for fragment discarding
Float AlphaDiscardThreshold (AlphaTestFallOff)
// For hardware skinning
Int NumberOfBones
Matrix4Array BoneMatrices
}
Technique {
WorldParameters {
WorldViewProjectionMatrix
//used for fog
WorldViewMatrix
}
VertexShaderNodes {
ShaderNode GpuSkinning {
Definition : BasicGPUSkinning : Common/MatDefs/ShaderNodes/HardwareSkinning/HardwareSkinning.j3sn
Condition : NumberOfBones
InputMapping {
modelPosition = Global.position;
modelPosition = Global.position
boneMatrices = MatParam.BoneMatrices
boneWeight = Attr.inHWBoneWeight
boneIndex = Attr.inHWBoneIndex
@ -53,20 +43,49 @@ MaterialDef UnshadedNodes {
}
}
FragmentShaderNodes {
ShaderNode UnshadedFrag{
Definition: Unshaded : Common/MatDefs/ShaderNodes/Common/Unshaded.j3sn
InputMapping{
texCoord = UnshadedVert.texCoord1: ColorMap
vertColor = UnshadedVert.vertColor: VertexColor
matColor = MatParam.Color: Color
colorMap = MatParam.ColorMap: ColorMap
color = Global.outColor
ShaderNode MatColorMult {
Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
InputMappings {
color1 = MatParam.Color
color2 = Global.outColor
}
OutputMapping{
Global.outColor = color
OutputMappings {
Global.outColor = outColor
}
Condition : Color
}
ShaderNode VertColorMult {
Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
InputMappings {
color1 = UnshadedVert.vertColor
color2 = Global.outColor
}
OutputMappings {
Global.outColor = outColor
}
Condition : VertexColor
}
ShaderNode ColorMapTF {
Definition : TextureFetch : Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn
InputMappings {
texCoord = UnshadedVert.texCoord1
textureMap = MatParam.ColorMap
}
OutputMappings {
}
Condition : ColorMap
}
ShaderNode ColorMapMult {
Definition : ColorMult : Common/MatDefs/ShaderNodes/Basic/ColorMult.j3sn
InputMappings {
color1 = ColorMapTF.outColor
color2 = Global.outColor
}
OutputMappings {
Global.outColor = outColor
}
Condition : ColorMap
}
ShaderNode AlphaDiscardThreshold {
Definition : AlphaDiscard : Common/MatDefs/ShaderNodes/Basic/AlphaDiscard.j3sn
Condition : AlphaDiscardThreshold
@ -75,23 +94,28 @@ MaterialDef UnshadedNodes {
threshold = MatParam.AlphaDiscardThreshold
}
}
ShaderNode LightMap{
Definition: LightMapping : Common/MatDefs/ShaderNodes/LightMapping/LightMapping.j3sn
Condition: LightMap
InputMapping{
texCoord = UnshadedVert.texCoord1: !SeparateTexCoord
ShaderNode LightMapTF {
Definition : TextureFetch : Common/MatDefs/ShaderNodes/Basic/TextureFetch.j3sn
InputMappings {
textureMap = MatParam.LightMap
texCoord = UnshadedVert.texCoord2 : SeparateTexCoord
lightMap = MatParam.LightMap
color = Global.outColor
texCoord = UnshadedVert.texCoord1 : !SeparateTexCoord
}
OutputMapping{
Global.outColor = color
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 {
Type: Fragment
Shader GLSL100: Common/MatDefs/ShaderNodes/Basic/texture.frag
Shader GLSL150: Common/MatDefs/ShaderNodes/Basic/texture15.frag
Documentation{
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
@output outColor the fetched color
}
Input {
sampler2D texture
sampler2D textureMap
vec2 texCoord
}
Output {

@ -1,3 +1,3 @@
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
#endif
// NOTE: Only define multisample functions if multisample is available and is being used!
#if defined(GL_ARB_texture_multisample) && (defined(RESOLVE_MS) || defined(RESOLVE_DEPTH_MS))
#if __VERSION__ >= 150
#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){
ivec2 iTexC = ivec2(texC * vec2(textureSize(tex)));
vec4 color = vec4(0.0);
@ -44,40 +50,21 @@ vec4 getDepth(in sampler2DMS tex,in vec2 texC){
return textureFetch(tex,texC,m_NumSamplesDepth);
}
#elif __VERSION__ >= 150
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
#endif
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){
return texture2D(tex,texC);
return TEXTURE(tex,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){
return texture2D(tex,texC);
return TEXTURE(tex,texC);
}
#endif

@ -2,26 +2,4 @@ INCLUDE com/jme3/asset/General.cfg
# Desktop-specific loaders
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.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.SceneLoader : scene
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.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