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

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

15
.gitignore vendored

@ -4,12 +4,14 @@
/dist/
/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:
secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s="
on_success: change
on_failure: always
rooms:
secure: "PWEk4+VL986c3gAjWp12nqyifvxCjBqKoESG9d7zWh1uiTLadTHhZJRMdsye36FCpz/c/Jt7zCRO/5y7FaubQptnRrkrRfjp5f99MJRzQVXnUAM+y385qVkXKRKd/PLpM7XPm4AvjvxHCyvzX2wamRvul/TekaXKB9Ti5FCN87s="
install:
- ./gradlew assemble
script:
- ./gradlew check
- ./gradlew createZipDistribution
- "[ $TRAVIS_BRANCH == 'master' ] && [ $TRAVIS_PULL_REQUEST == 'false' ] && ./gradlew uploadArchives || :"
before_deploy:
- export RELEASE_DIST=$(ls build/distributions/*.zip)
deploy:
provider: releases
api_key:
secure: PuEsJd6juXBH29ByITW3ntSAyrwWs0IeFvXJ5Y2YlhojhSMtTwkoWeB6YmDJWP4fhzbajk4TQ1HlOX2IxJXSW/8ShOEIUlGXz9fHiST0dkSM+iRAUgC5enCLW5ITPTiem7eY9ZhS9miIam7ngce9jHNMh75PTzZrEJtezoALT9w=
file_glob: true
file: "${RELEASE_DIST}"
skip_cleanup: true
on:
repo: jMonkeyEngine/jmonkeyengine
tags: true
before_install:
- 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
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')){
apply from: rootProject.file('common.gradle')
// }
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') {
@ -49,15 +60,14 @@ 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"
into("/") {
from {"./dist"}
}
into("/sources") {
from {"$buildDir/libDist/sources"}
}
task createZipDistribution(type:Zip,dependsOn:["dist","libDist"], description:"Package the nightly zip distribution"){
archiveName "jME" + jmeFullVersion + ".zip"
into("/") {
from {"./dist"}
}
into("/sources") {
from {"$buildDir/libDist/sources"}
}
}
task copyLibs(type: Copy){
@ -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,27 +133,13 @@ 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
ndkExists = true
ndkCommandPath = ndkBuildPath
}
}
ext {
ndkCommandPath = findNDK()
ndkExists = checkNdkExists(ndkCommandPath)
}
//class IncrementalReverseTask extends DefaultTask {
// @InputDirectory
// def File inputDir
@ -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
group = 'com.jme3'
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,41 +67,35 @@ artifacts {
}
}
publishing {
publications {
maven(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar
pom.withXml {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
name POM_NAME
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEVELOPER_CONNECTION
}
licenses {
license {
name POM_LICENSE_NAME
url POM_LICENSE_URL
distribution POM_LICENSE_DISTRIBUTION
}
}
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.project {
name POM_NAME
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEVELOPER_CONNECTION
}
licenses {
license {
name POM_LICENSE_NAME
url POM_LICENSE_URL
distribution POM_LICENSE_DISTRIBUTION
}
}
}
}
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 {

@ -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());
}
}
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
if(translationSet) {
translations[index] = localRotation.multLocal(new Vector3f(translation[0], translation[1], translation[2]));
} else {
translations[index] = new Vector3f();
}
if(boneContext != null) {
if(boneContext.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;
@ -38,9 +39,9 @@ import com.jme3.util.TempVars;
* @author Marcin Roguski (Kaelthas)
*/
public class SimulationNode {
private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName());
private static final Logger LOGGER = Logger.getLogger(SimulationNode.class.getName());
private Long featureOMA;
private Long featureOMA;
/** The blender context. */
private BlenderContext blenderContext;
/** The name of the node (for debugging purposes). */
@ -51,11 +52,11 @@ public class SimulationNode {
private List<Animation> animations;
/** The nodes spatial (if null then the boneContext should be set). */
private Spatial spatial;
private Spatial spatial;
/** The skeleton of the bone (not null if the node simulated the bone). */
private Skeleton skeleton;
private Skeleton skeleton;
/** Animation controller for the node's feature. */
private AnimControl animControl;
private AnimControl animControl;
/**
* The star transform of a spatial. Needed to properly reset the spatial to
@ -64,7 +65,7 @@ public class SimulationNode {
private Transform spatialStartTransform;
/** Star transformations for bones. Needed to properly reset the bones. */
private Map<Bone, Transform> boneStartTransforms;
/**
* Builds the nodes tree for the given feature. The feature (bone or
* spatial) is found by its OMA. The feature must be a root bone or a root
@ -208,8 +209,7 @@ public class SimulationNode {
if (animations != null) {
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,34 +294,39 @@ 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) {
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);
}
constraint.apply(frame);
if (constraint.getAlteredOmas() != null) {
alteredOmas.addAll(constraint.getAlteredOmas());
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) {
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, bonesStack);
}
constraint.apply(frame);
if (constraint.getAlteredOmas() != null) {
alteredOmas.addAll(constraint.getAlteredOmas());
}
alteredOmas.add(boneContext.getBoneOma());
}
alteredOmas.add(boneContext.getBoneOma());
}
applied.add(boneContext.getBoneOma());
}
applied.add(boneContext.getBoneOma());
}
List<Bone> children = bone.getChildren();
if (children != null && children.size() > 0) {
for (Bone child : bone.getChildren()) {
this.applyConstraints(child, alteredOmas, applied, frame);
List<Bone> children = bone.getChildren();
if (children != null && children.size() > 0) {
for (Bone child : bone.getChildren()) {
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
@ -53,6 +55,10 @@ public abstract class ConstraintDefinition {
constraintHelper = (ConstraintHelper) (blenderContext == null ? null : blenderContext.getHelper(ConstraintHelper.class));
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

@ -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 int FLAG_USE_TAIL = 0x01;
private static final int FLAG_POSITION = 0x20;
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;
private int bonesAffected;
/** Indicates if the tail of the bone should be used or not. */
private boolean useTail;
private boolean useTail;
/** The amount of iterations of the algorithm. */
private int iterations;
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());
}
}
iterations = 0;
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);
}
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) {
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));
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;
}
Vector3d e = topBoneTransform.getTranslation().addLocal(topBoneTransform.getRotation().mult(Vector3d.UNIT_Y).multLocal(topBone.getLength()));// effector
deltaP.setColumn(0, 0, target.x - e.x, target.y - e.y, target.z - e.z);
int column = 0;
for (BoneContext boneContext : bones) {
DTransform boneWorldTransform = bones.getWorldTransform(boneContext);
Vector3d j = boneWorldTransform.getTranslation(); // current join position
Vector3d 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);
if(bone.equals(this.getOwner())) {
if (boneContext.isLockX()) {
q.set(0, q.getY(), q.getZ(), q.getW());
}
if (boneContext.isLockY()) {
q.set(q.getX(), 0, q.getZ(), q.getW());
}
if (boneContext.isLockZ()) {
q.set(q.getX(), q.getY(), 0, q.getW());
}
}
boneWorldTransform.getRotation().set(q.multLocal(boneWorldTransform.getRotation()));
constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), bone.getName(), Space.CONSTRAINT_SPACE_WORLD, boneWorldTransform.toTransform());
} else {
iterations = 0;
break;
}
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];
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));
tempDQuaternion.fromAngleAxis(angle, rotationVector);
BoneContext boneContext = bones.get(j);
Bone bone = boneContext.getBone();
if (bone.equals(this.getOwner())) {
if (boneContext.isLockX()) {
tempDQuaternion.set(0, tempDQuaternion.getY(), tempDQuaternion.getZ(), tempDQuaternion.getW());
}
if (boneContext.isLockY()) {
tempDQuaternion.set(tempDQuaternion.getX(), 0, tempDQuaternion.getZ(), tempDQuaternion.getW());
}
if (boneContext.isLockZ()) {
tempDQuaternion.set(tempDQuaternion.getX(), tempDQuaternion.getY(), 0, tempDQuaternion.getW());
}
}
DTransform boneTransform = bones.getWorldTransform(boneContext);
boneTransform.getRotation().set(tempDQuaternion.mult(boneTransform.getRotation()));
bones.setWorldTransform(boneContext, boneTransform);
}
}
// applying best solution
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;
}
if (!useTail) {
bone = bone.getParent();
}
chainLength = 0;
while (bone != null) {
BoneContext boneContext = blenderContext.getBoneContext(bone);
chainLength += boneContext.getLength();
bones.add(boneContext);
alteredOmas.add(boneContext.getBoneOma());
if (bonesAffected != 0 && bones.size() >= bonesAffected) {
break;
}
// need to add spaces between bones to the chain length
Transform boneWorldTransform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD);
Vector3f boneWorldTranslation = boneWorldTransform.getTranslation();
private static class BonesChain extends ArrayList<BoneContext> {
private static final long serialVersionUID = -1850524345643600718L;
bone = bone.getParent();
private List<Matrix> bonesMatrices = new ArrayList<Matrix>();
public BonesChain(Bone bone, boolean useTail, int bonesAffected, Collection<Long> alteredOmas, BlenderContext blenderContext) {
if (bone != null) {
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);
ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
if (!useTail) {
bone = bone.getParent();
}
while (bone != null && (bonesAffected <= 0 || this.size() < bonesAffected)) {
BoneContext boneContext = blenderContext.getBoneContext(bone);
this.add(boneContext);
alteredOmas.add(boneContext.getBoneOma());
Space space = this.size() < bonesAffected ? Space.CONSTRAINT_SPACE_LOCAL : Space.CONSTRAINT_SPACE_WORLD;
Transform transform = constraintHelper.getTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), space);
bonesMatrices.add(new DTransform(transform).toMatrix());
bone = bone.getParent();
}
}
}
return bones;
}
@Override
public 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();
}
return trackToBeChanged;
}
@Override
public boolean isTargetRequired() {
return true;
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);
}
bonesMatrices.set(index, boneMatrix);
}
public Matrix getWorldMatrix(int index) {
if (index == this.size() - 1) {
return new Matrix(bonesMatrices.get(this.size() - 1));
}
SimpleMatrix result = this.getWorldMatrix(index + 1);
result = result.mult(bonesMatrices.get(index));
return new Matrix(result);
}
}
}

@ -31,6 +31,7 @@
*/
package com.jme3.scene.plugins.blender.file;
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());
@ -66,7 +76,15 @@ public final class DTransform implements Savable, Cloneable, java.io.Serializabl
public Transform toTransform() {
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,39 +811,72 @@ 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
}
#endif

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

@ -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, factor);
setAngularFactor(objectId, new Vector3f(factor, factor, factor));
}
public void setAngularFactor(Vector3f factor) {
setAngularFactor(objectId, factor);
}
private native void setAngularFactor(long objectId, Vector3f factor);
public Vector3f getLinearFactor() {
Vector3f vec = new Vector3f();
getLinearFactor(objectId, vec);
return vec;
}
private native void setAngularFactor(long objectId, float factor);
private native void getLinearFactor(long objectId, Vector3f vec);
public void setLinearFactor(Vector3f factor) {
setLinearFactor(objectId, factor);
}
private native void setLinearFactor(long objectId, Vector3f factor);
/**
* do not use manually, joints are added automatically
@ -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);
capsule.write(getAngularFactor(), "angularFactor", 1);
Vector3f angularFactor = getAngularFactor(null);
if (angularFactor.x == angularFactor.y && angularFactor.y == angularFactor.z) {
capsule.write(getAngularFactor(), "angularFactor", 1);
} else {
capsule.write(getAngularFactor(null), "angularFactor", Vector3f.UNIT_XYZ);
capsule.write(getLinearFactor(), "linearFactor", Vector3f.UNIT_XYZ);
}
capsule.write(kinematic, "kinematic", false);
capsule.write(getLinearDamping(), "linearDamping", 0);
@ -703,7 +737,13 @@ public class PhysicsRigidBody extends PhysicsCollisionObject {
setKinematic(capsule.readBoolean("kinematic", false));
setRestitution(capsule.readFloat("restitution", 0));
setAngularFactor(capsule.readFloat("angularFactor", 1));
Vector3f angularFactor = (Vector3f) capsule.readSavable("angularFactor", Vector3f.NAN.clone());
if(angularFactor == Vector3f.NAN) {
setAngularFactor(capsule.readFloat("angularFactor", 1));
} else {
setAngularFactor(angularFactor);
setLinearFactor((Vector3f) capsule.readSavable("linearFactor", Vector3f.UNIT_XYZ.clone()));
}
setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0));
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"
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(updateVersion)
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,11 +347,22 @@ 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();
clone.skeleton = ctrl.getSkeleton();
AnimControl ctrl = spatial.getControl(AnimControl.class);
if (ctrl != null) {
// AnimControl is responsible for cloning the skeleton, not
// SkeletonControl.
clone.skeleton = ctrl.getSkeleton();
} else {
// If there's no AnimControl, create the clone ourselves.
clone.skeleton = new Skeleton(skeleton);
}
clone.hwSkinningDesired = this.hwSkinningDesired;
clone.hwSkinningEnabled = this.hwSkinningEnabled;
clone.hwSkinningSupported = this.hwSkinningSupported;
clone.hwSkinningTested = this.hwSkinningTested;
clone.setSpatial(clonedNode);
// Fix attachments for the cloned node

@ -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);
stringBuilder.setLength(0);
// 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;
@ -409,6 +409,14 @@ public class AudioNode extends Node implements AudioSource {
play();
}
}
@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);

@ -95,6 +95,11 @@ public interface AudioSource {
* @return the time offset in the sound sample when to start playing.
*/
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()) {
@ -682,6 +740,8 @@ public class ALAudioRenderer implements AudioRenderer, Runnable {
break;
}
}
stream.setUnqueuedBufferBytes(stream.getUnqueuedBufferBytes() + unqueuedBufferBytes);
return success;
}

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

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

@ -48,6 +48,7 @@ import com.jme3.math.Vector3f;
import com.jme3.scene.CollisionData;
import com.jme3.scene.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,8 +72,10 @@ public class DefaultJoystickAxis implements JoystickAxis {
* @param negativeMapping The mapping to receive events when the axis is positive
*/
public void assignAxis(String positiveMapping, String negativeMapping){
inputManager.addMapping(positiveMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, false));
inputManager.addMapping(negativeMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, true));
if (axisIndex != -1) {
inputManager.addMapping(positiveMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, false));
inputManager.addMapping(negativeMapping, new JoyAxisTrigger(parent.getJoyId(), axisIndex, true));
}
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* Copyright (c) 2009-2012, 2015 jMonkeyEngine
* All rights reserved.
*
* 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,36 +45,121 @@ 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 {
protected Vector3f position = new Vector3f();
protected Vector3f direction = new Vector3f(0,-1,0);
protected Vector3f direction = new Vector3f(0, -1, 0);
protected float spotInnerAngle = FastMath.QUARTER_PI / 8;
protected float spotOuterAngle = FastMath.QUARTER_PI / 6;
protected float spotRange = 100;
protected float invSpotRange = 1 / 100;
protected float packedAngleCos=0;
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);
}

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

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

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

@ -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,9 +90,11 @@ 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);
glFmt = getImageFormat(fmt, false);
logger.log(Level.WARNING, "No sRGB format available for ''{0}''. Failling back to linear.", fmt);
}
if (glFmt == null) {
@ -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) {
@ -242,6 +269,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);

@ -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:
@ -504,13 +494,21 @@ public class BatchNode extends GeometryGroupNode {
if (mode != null && mode != listMode) {
throw new UnsupportedOperationException("Cannot combine different"
+ " primitive types: " + mode + " != " + listMode);
}
}
mode = listMode;
if (mode == Mesh.Mode.Lines) {
if (lineWidth != 1f && listLineWidth != lineWidth) {
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
@ -583,11 +581,13 @@ public class BatchNode extends GeometryGroupNode {
useTangents = true;
}
} else {
inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount);
// for (int vert = 0; vert < geomVertCount; vert++) {
// int curGlobalVertIndex = globalVertIndex + vert;
// inBuf.copyElement(vert, outBuf, curGlobalVertIndex);
// }
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);
}
}
}
@ -745,8 +745,7 @@ public class BatchNode extends GeometryGroupNode {
}
}
}
Geometry geometry;
boolean needMeshUpdate = false;
Geometry geometry;
}
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();
ByteBuffer bb = createByteBuffer(bytes.length);
bb.put(bytes);
bb.flip();
return bb;
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
vViewDir = -wvPosition * tbnMat;
#if defined(NORMALMAP) && !defined(VERTEX_LIGHTING)
vViewDir = -wvPosition * tbnMat;
#if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
vViewDirPrlx = vViewDir;
#endif
lightComputeDir(wvPosition, lightColor.w, wvLightPos, vLightDir, lightVec);
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

@ -17,10 +17,7 @@ varying vec3 SpecularSum;
#ifndef VERTEX_LIGHTING
uniform mat4 g_ViewMatrix;
uniform vec4 g_LightData[NB_LIGHTS];
varying vec3 vPos;
#else
varying vec3 specularAccum;
varying vec4 diffuseAccum;
varying vec3 vPos;
#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 {
@ -17,4 +18,4 @@ MaterialDef Colored Textured {
Technique {
}
}
}

@ -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

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

@ -2,14 +2,15 @@ ShaderNodeDefinitions{
ShaderNodeDefinition TextureFetch {
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