aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Barta <sbarta@google.com>2012-03-09 13:52:20 -0800
committerScott Barta <sbarta@google.com>2012-03-09 14:13:24 -0800
commita6b44658eb1c55295f132a36233a11aa2bd8f9cf (patch)
tree4006b29d319de8635ca7cc2384782618f6c80ee7
parent59b2e6871c65f58fdad78cd7229c292f6a177578 (diff)
downloadjmonkeyengine-jb-mr1-dev.tar.gz
New drop of the jmonkeyengine libraryHEADandroid-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-sdk-support_r11android-sdk-4.4.2_r1.0.1android-sdk-4.4.2_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-preview-1android-n-mr2-preview-2android-n-mr2-preview-1android-n-mr1-preview-2android-n-mr1-preview-1android-n-iot-release-smart-display-r2android-n-iot-release-smart-displayandroid-n-iot-release-polk-at1android-n-iot-release-lg-thinq-wk7android-n-iot-release-ihome-igv1android-n-iot-preview-4android-l-preview_r2android-cts-6.0_r9android-cts-6.0_r8android-cts-6.0_r7android-cts-6.0_r6android-cts-6.0_r5android-cts-6.0_r4android-cts-6.0_r32android-cts-6.0_r31android-cts-6.0_r30android-cts-6.0_r3android-cts-6.0_r29android-cts-6.0_r28android-cts-6.0_r27android-cts-6.0_r26android-cts-6.0_r25android-cts-6.0_r24android-cts-6.0_r23android-cts-6.0_r22android-cts-6.0_r21android-cts-6.0_r20android-cts-6.0_r2android-cts-6.0_r19android-cts-6.0_r18android-cts-6.0_r17android-cts-6.0_r16android-cts-6.0_r15android-cts-6.0_r14android-cts-6.0_r13android-cts-6.0_r12android-cts-6.0_r1android-cts-4.4_r4android-cts-4.4_r1android-cts-4.2_r2android-cts-4.2_r1android-cts-4.1_r4android-cts-4.1_r2android-cts-4.1_r1android-7.1.2_r9android-7.1.2_r8android-7.1.2_r6android-7.1.2_r5android-7.1.2_r4android-7.1.2_r39android-7.1.2_r38android-7.1.2_r37android-7.1.2_r36android-7.1.2_r33android-7.1.2_r32android-7.1.2_r30android-7.1.2_r3android-7.1.2_r29android-7.1.2_r28android-7.1.2_r27android-7.1.2_r25android-7.1.2_r24android-7.1.2_r23android-7.1.2_r2android-7.1.2_r19android-7.1.2_r18android-7.1.2_r17android-7.1.2_r16android-7.1.2_r15android-7.1.2_r14android-7.1.2_r13android-7.1.2_r12android-7.1.2_r11android-7.1.2_r10android-7.1.2_r1android-6.0.1_r9android-6.0.1_r81android-6.0.1_r80android-6.0.1_r8android-6.0.1_r79android-6.0.1_r78android-6.0.1_r77android-6.0.1_r74android-6.0.1_r73android-6.0.1_r72android-6.0.1_r70android-6.0.1_r7android-6.0.1_r69android-6.0.1_r68android-6.0.1_r67android-6.0.1_r66android-6.0.1_r65android-6.0.1_r63android-6.0.1_r62android-6.0.1_r61android-6.0.1_r60android-6.0.1_r59android-6.0.1_r58android-6.0.1_r57android-6.0.1_r56android-6.0.1_r55android-6.0.1_r54android-6.0.1_r53android-6.0.1_r52android-6.0.1_r51android-6.0.1_r50android-6.0.1_r5android-6.0.1_r49android-6.0.1_r48android-6.0.1_r47android-6.0.1_r46android-6.0.1_r45android-6.0.1_r43android-6.0.1_r42android-6.0.1_r41android-6.0.1_r40android-6.0.1_r4android-6.0.1_r33android-6.0.1_r32android-6.0.1_r31android-6.0.1_r30android-6.0.1_r3android-6.0.1_r28android-6.0.1_r27android-6.0.1_r26android-6.0.1_r25android-6.0.1_r24android-6.0.1_r22android-6.0.1_r21android-6.0.1_r20android-6.0.1_r18android-6.0.1_r17android-6.0.1_r16android-6.0.1_r13android-6.0.1_r12android-6.0.1_r11android-6.0.1_r10android-6.0.1_r1android-6.0.0_r7android-6.0.0_r6android-6.0.0_r5android-6.0.0_r41android-6.0.0_r4android-6.0.0_r3android-6.0.0_r26android-6.0.0_r25android-6.0.0_r24android-6.0.0_r23android-6.0.0_r2android-6.0.0_r13android-6.0.0_r12android-6.0.0_r11android-6.0.0_r1android-4.4w_r1android-4.4_r1.2.0.1android-4.4_r1.2android-4.4_r1.1.0.1android-4.4_r1.1android-4.4_r1.0.1android-4.4_r1android-4.4_r0.9android-4.4_r0.8android-4.4_r0.7android-4.4.4_r2.0.1android-4.4.4_r2android-4.4.4_r1.0.1android-4.4.4_r1android-4.4.3_r1.1.0.1android-4.4.3_r1.1android-4.4.3_r1.0.1android-4.4.3_r1android-4.4.2_r2.0.1android-4.4.2_r2android-4.4.2_r1.0.1android-4.4.2_r1android-4.4.1_r1.0.1android-4.4.1_r1android-4.3_r3.1android-4.3_r3android-4.3_r2.3android-4.3_r2.2android-4.3_r2.1android-4.3_r2android-4.3_r1.1android-4.3_r1android-4.3_r0.9.1android-4.3_r0.9android-4.3.1_r1android-4.2_r1android-4.2.2_r1.2android-4.2.2_r1.1android-4.2.2_r1android-4.2.1_r1.2android-4.2.1_r1.1android-4.2.1_r1android-4.1.2_r2.1android-4.1.2_r2android-4.1.2_r1android-4.1.1_r6.1android-4.1.1_r6android-4.1.1_r5android-4.1.1_r4android-4.1.1_r3android-4.1.1_r2android-4.1.1_r1.1android-4.1.1_r1tools_r22.2tools_r22tools_r21nougat-mr2.3-releasenougat-mr2.2-releasenougat-mr2.1-releasenougat-mr2-security-releasenougat-mr2-releasenougat-mr2-pixel-releasenougat-mr2-devnougat-iot-releasen-iot-preview-4mastermarshmallow-releasemarshmallow-mr3-releasemarshmallow-mr2-releasemarshmallow-mr1-releasemarshmallow-mr1-devmarshmallow-dr1.6-releasemarshmallow-dr1.5-releasemarshmallow-dr1.5-devmarshmallow-dr-releasemarshmallow-dr-dragon-releasemarshmallow-dr-devmarshmallow-devmarshmallow-cts-releasemainl-previewkitkat-wearkitkat-releasekitkat-mr2.2-releasekitkat-mr2.1-releasekitkat-mr2-releasekitkat-mr1.1-releasekitkat-mr1-releasekitkat-devkitkat-cts-releasekitkat-cts-devjb-releasejb-mr2.0.0-releasejb-mr2.0-releasejb-mr2-releasejb-mr2-devjb-mr1.1-releasejb-mr1.1-dev-plus-aospjb-mr1.1-devjb-mr1-releasejb-mr1-dev-plus-aospjb-mr1-devjb-mr0-releasejb-devidea133-weekly-releaseidea133
A new drop of the jmonkeyengine library sources, based on a 2012-03-05 snapshot. Fixes a few unnecessary memory allocations in the main rendering loop. Change-Id: I51ac0942fe87204df102cfdce746b59a5cb5ff85
-rw-r--r--engine/src/android/com/jme3/app/AndroidHarness.java12
-rw-r--r--engine/src/android/com/jme3/asset/AndroidAssetManager.java51
-rw-r--r--engine/src/android/com/jme3/asset/plugins/AndroidLocator.java5
-rw-r--r--engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java13
-rw-r--r--engine/src/android/com/jme3/input/android/AndroidInput.java1239
-rw-r--r--engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java11
-rw-r--r--engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java30
-rw-r--r--engine/src/android/com/jme3/renderer/android/TextureUtil.java4
-rw-r--r--engine/src/android/com/jme3/system/android/AndroidConfigChooser.java359
-rw-r--r--engine/src/android/com/jme3/system/android/OGLESContext.java94
-rw-r--r--engine/src/android/com/jme3/util/AndroidLogHandler.java16
-rw-r--r--engine/src/android/com/jme3/util/RingBuffer.java21
-rw-r--r--engine/src/android/res/layout/about.xml32
-rw-r--r--engine/src/android/res/layout/tests.xml18
-rw-r--r--engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java15
-rw-r--r--engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java4
-rw-r--r--engine/src/core-data/Common/MatDefs/Light/Lighting.frag4
-rw-r--r--engine/src/core-data/Common/MatDefs/Misc/Particle.j3md26
-rw-r--r--engine/src/core-data/Common/MatDefs/Misc/SoftParticle.frag50
-rw-r--r--engine/src/core-data/Common/MatDefs/Misc/SoftParticle.vert53
-rw-r--r--engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java75
-rw-r--r--engine/src/core-plugins/com/jme3/asset/plugins/HttpZipLocator.java~355
-rw-r--r--engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java6
-rw-r--r--engine/src/core/com/jme3/app/Application.java15
-rw-r--r--engine/src/core/com/jme3/app/ResetStatsState.java60
-rw-r--r--engine/src/core/com/jme3/app/SimpleApplication.java7
-rw-r--r--engine/src/core/com/jme3/app/StatsView.java2
-rw-r--r--engine/src/core/com/jme3/app/state/AppStateManager.java6
-rw-r--r--engine/src/core/com/jme3/input/InputManager.java1773
-rw-r--r--engine/src/core/com/jme3/input/SoftTextDialogInput.java13
-rw-r--r--engine/src/core/com/jme3/input/TouchInput.java6
-rw-r--r--engine/src/core/com/jme3/input/controls/SoftTextDialogInputListener.java44
-rw-r--r--engine/src/core/com/jme3/math/Transform.java636
-rw-r--r--engine/src/core/com/jme3/post/Filter.java13
-rw-r--r--engine/src/core/com/jme3/post/FilterPostProcessor.java25
-rw-r--r--engine/src/core/com/jme3/renderer/RenderManager.java2348
-rw-r--r--engine/src/core/com/jme3/scene/BatchNode.java13
-rw-r--r--engine/src/core/com/jme3/scene/Mesh.java153
-rw-r--r--engine/src/core/com/jme3/shader/UniformBinding.java338
-rw-r--r--engine/src/core/com/jme3/system/JmeSystem.java283
-rw-r--r--engine/src/core/com/jme3/system/JmeSystemDelegate.java289
-rw-r--r--engine/src/core/com/jme3/util/BufferUtils.java75
-rw-r--r--engine/src/core/com/jme3/util/IntMap.java7
-rw-r--r--engine/src/core/com/jme3/util/TangentBinormalGenerator.java12
-rw-r--r--engine/src/desktop/com/jme3/texture/plugins/AWTLoader.java14
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag13
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.frag6
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.j3md19
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.vert9
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.frag6
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.j3md18
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.vert14
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.frag10
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.j3md (renamed from engine/src/niftygui/Common/MatDefs/Nifty/Nifty.j3md)5
-rw-r--r--engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.vert (renamed from engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert)5
-rw-r--r--engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java507
-rw-r--r--engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java289
-rw-r--r--engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java5
-rw-r--r--engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java27
-rw-r--r--engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java248
-rw-r--r--engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java3
-rw-r--r--engine/src/test/jme3test/app/TestAppStateLifeCycle.java126
-rw-r--r--engine/src/test/jme3test/effect/TestSoftParticles.java130
-rw-r--r--engine/src/test/jme3test/helloworld/HelloMaterial.java3
-rw-r--r--engine/src/test/jme3test/model/shape/TestExpandingTorus.java45
-rw-r--r--engine/src/tools/jme3tools/converters/model/ModelConverter.java4
-rw-r--r--engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java38
67 files changed, 5347 insertions, 4808 deletions
diff --git a/engine/src/android/com/jme3/app/AndroidHarness.java b/engine/src/android/com/jme3/app/AndroidHarness.java
index 6631003..0ad2ba1 100644
--- a/engine/src/android/com/jme3/app/AndroidHarness.java
+++ b/engine/src/android/com/jme3/app/AndroidHarness.java
@@ -70,6 +70,10 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
*/
protected boolean mouseEventsInvertY = true;
/**
+ * if true finish this activity when the jme app is stopped
+ */
+ protected boolean finishOnAppStop = true;
+ /**
* Title of the exit dialog, default is "Do you want to exit?"
*/
protected String exitDialogTitle = "Do you want to exit?";
@@ -131,7 +135,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
boolean bIsLogFormatSet = false;
do {
if (log.getHandlers().length == 0) {
- log = logger.getParent();
+ log = log.getParent();
if (log != null) {
for (Handler h : log.getHandlers()) {
//h.setFormatter(new SimpleFormatter());
@@ -395,4 +399,10 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
}
}
}
+
+ public boolean isFinishOnAppStop() {
+ return finishOnAppStop;
+ }
+
+
}
diff --git a/engine/src/android/com/jme3/asset/AndroidAssetManager.java b/engine/src/android/com/jme3/asset/AndroidAssetManager.java
index c6f0b17..b2140dd 100644
--- a/engine/src/android/com/jme3/asset/AndroidAssetManager.java
+++ b/engine/src/android/com/jme3/asset/AndroidAssetManager.java
@@ -37,6 +37,7 @@ import com.jme3.audio.plugins.AndroidAudioLoader;
import com.jme3.texture.Texture;
import com.jme3.texture.plugins.AndroidImageLoader;
import java.net.URL;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -57,6 +58,14 @@ public class AndroidAssetManager extends DesktopAssetManager {
//this(Thread.currentThread().getContextClassLoader().getResource("com/jme3/asset/Android.cfg"));
this(null);
}
+
+ private void registerLoaderSafe(Class<? extends AssetLoader> loaderClass, String ... extensions) {
+ try {
+ registerLoader(loaderClass, extensions);
+ } catch (Exception e){
+ logger.log(Level.WARNING, "Failed to load AssetLoader", e);
+ }
+ }
/**
* AndroidAssetManager constructor
@@ -67,25 +76,29 @@ public class AndroidAssetManager extends DesktopAssetManager {
System.setProperty("org.xml.sax.driver", "org.xmlpull.v1.sax2.Driver");
// Set Default Android config
- this.registerLocator("", AndroidLocator.class);
- this.registerLocator("", ClasspathLocator.class);
- this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
- this.registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav");
- this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
- this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
- this.registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
- this.registerLoader(com.jme3.texture.plugins.DDSLoader.class, "dds");
- this.registerLoader(com.jme3.texture.plugins.PFMLoader.class, "pfm");
- this.registerLoader(com.jme3.texture.plugins.HDRLoader.class, "hdr");
- this.registerLoader(com.jme3.texture.plugins.TGALoader.class, "tga");
- this.registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
- this.registerLoader(com.jme3.scene.plugins.OBJLoader.class, "obj");
- this.registerLoader(com.jme3.scene.plugins.MTLLoader.class, "mtl");
- this.registerLoader(com.jme3.scene.plugins.ogre.MeshLoader.class, "meshxml", "mesh.xml");
- this.registerLoader(com.jme3.scene.plugins.ogre.SkeletonLoader.class, "skeletonxml", "skeleton.xml");
- this.registerLoader(com.jme3.scene.plugins.ogre.MaterialLoader.class, "material");
- this.registerLoader(com.jme3.scene.plugins.ogre.SceneLoader.class, "scene");
- this.registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
+ registerLocator("", AndroidLocator.class);
+ registerLocator("", ClasspathLocator.class);
+
+ registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
+ registerLoader(AndroidAudioLoader.class, "ogg", "mp3", "wav");
+ registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
+ registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
+ registerLoader(com.jme3.shader.plugins.GLSLLoader.class, "vert", "frag", "glsl", "glsllib");
+ registerLoader(com.jme3.export.binary.BinaryImporter.class, "j3o");
+ registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
+
+ // Less common loaders (especially on Android)
+ registerLoaderSafe(com.jme3.texture.plugins.DDSLoader.class, "dds");
+ registerLoaderSafe(com.jme3.texture.plugins.PFMLoader.class, "pfm");
+ registerLoaderSafe(com.jme3.texture.plugins.HDRLoader.class, "hdr");
+ registerLoaderSafe(com.jme3.texture.plugins.TGALoader.class, "tga");
+ registerLoaderSafe(com.jme3.scene.plugins.OBJLoader.class, "obj");
+ registerLoaderSafe(com.jme3.scene.plugins.MTLLoader.class, "mtl");
+ registerLoaderSafe(com.jme3.scene.plugins.ogre.MeshLoader.class, "mesh.xml");
+ registerLoaderSafe(com.jme3.scene.plugins.ogre.SkeletonLoader.class, "skeleton.xml");
+ registerLoaderSafe(com.jme3.scene.plugins.ogre.MaterialLoader.class, "material");
+ registerLoaderSafe(com.jme3.scene.plugins.ogre.SceneLoader.class, "scene");
+
logger.info("AndroidAssetManager created.");
}
diff --git a/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java b/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java
index 01b1cab..225faf3 100644
--- a/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java
+++ b/engine/src/android/com/jme3/asset/plugins/AndroidLocator.java
@@ -4,9 +4,6 @@ import com.jme3.asset.*;
import com.jme3.system.android.JmeAndroidSystem;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.logging.Level;
import java.util.logging.Logger;
public class AndroidLocator implements AssetLocator {
@@ -80,7 +77,7 @@ public class AndroidLocator implements AssetLocator {
assetPath = assetPath.replace("//", "/");
try {
return create(manager, key, assetPath);
- }catch (IOException ex){
+ } catch (IOException ex) {
// This is different handling than URL locator
// since classpath locating would return null at the getResource()
// call, otherwise there's a more critical error...
diff --git a/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java b/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java
index fc9c03e..a11425b 100644
--- a/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java
+++ b/engine/src/android/com/jme3/audio/plugins/AndroidAudioLoader.java
@@ -5,15 +5,16 @@ import com.jme3.asset.AssetLoader;
import com.jme3.audio.android.AndroidAudioData;
import java.io.IOException;
-public class AndroidAudioLoader implements AssetLoader
-{
+/**
+ * <code>AndroidAudioLoader</code> will create an
+ * {@link AndroidAudioData} object with the specified asset key.
+ */
+public class AndroidAudioLoader implements AssetLoader {
@Override
- public Object load(AssetInfo assetInfo) throws IOException
- {
+ public Object load(AssetInfo assetInfo) throws IOException {
AndroidAudioData result = new AndroidAudioData();
- result.setAssetKey( assetInfo.getKey() );
+ result.setAssetKey(assetInfo.getKey());
return result;
}
-
}
diff --git a/engine/src/android/com/jme3/input/android/AndroidInput.java b/engine/src/android/com/jme3/input/android/AndroidInput.java
index ca1141d..9bbbe4e 100644
--- a/engine/src/android/com/jme3/input/android/AndroidInput.java
+++ b/engine/src/android/com/jme3/input/android/AndroidInput.java
@@ -1,619 +1,620 @@
-package com.jme3.input.android;
-
-import android.content.Context;
-import android.opengl.GLSurfaceView;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import com.jme3.input.KeyInput;
-import com.jme3.input.RawInputListener;
-import com.jme3.input.TouchInput;
-import com.jme3.input.event.MouseButtonEvent;
-import com.jme3.input.event.MouseMotionEvent;
-import com.jme3.input.event.TouchEvent;
-import com.jme3.input.event.TouchEvent.Type;
-import com.jme3.math.Vector2f;
-import com.jme3.util.RingBuffer;
-import java.util.HashMap;
-import java.util.logging.Logger;
-
-/**
- * <code>AndroidInput</code> is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs
- * @author larynx
- *
- */
-public class AndroidInput extends GLSurfaceView implements TouchInput,
- GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener {
-
- final private static int MAX_EVENTS = 1024;
- // Custom settings
- public boolean mouseEventsEnabled = true;
- public boolean mouseEventsInvertX = false;
- public boolean mouseEventsInvertY = false;
- public boolean keyboardEventsEnabled = false;
- public boolean dontSendHistory = false;
- // Used to transfer events from android thread to GLThread
- final private RingBuffer<TouchEvent> eventQueue = new RingBuffer<TouchEvent>(MAX_EVENTS);
- final private RingBuffer<TouchEvent> eventPoolUnConsumed = new RingBuffer<TouchEvent>(MAX_EVENTS);
- final private RingBuffer<TouchEvent> eventPool = new RingBuffer<TouchEvent>(MAX_EVENTS);
- final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>();
- // Internal
- private ScaleGestureDetector scaledetector;
- private GestureDetector detector;
- private int lastX;
- private int lastY;
- private final static Logger logger = Logger.getLogger(AndroidInput.class.getName());
- private boolean isInitialized = false;
- private RawInputListener listener = null;
- private static final int[] ANDROID_TO_JME = {
- 0x0, // unknown
- 0x0, // key code soft left
- 0x0, // key code soft right
- KeyInput.KEY_HOME,
- KeyInput.KEY_ESCAPE, // key back
- 0x0, // key call
- 0x0, // key endcall
- KeyInput.KEY_0,
- KeyInput.KEY_1,
- KeyInput.KEY_2,
- KeyInput.KEY_3,
- KeyInput.KEY_4,
- KeyInput.KEY_5,
- KeyInput.KEY_6,
- KeyInput.KEY_7,
- KeyInput.KEY_8,
- KeyInput.KEY_9,
- KeyInput.KEY_MULTIPLY,
- 0x0, // key pound
- KeyInput.KEY_UP,
- KeyInput.KEY_DOWN,
- KeyInput.KEY_LEFT,
- KeyInput.KEY_RIGHT,
- KeyInput.KEY_RETURN, // dpad center
- 0x0, // volume up
- 0x0, // volume down
- KeyInput.KEY_POWER, // power (?)
- 0x0, // camera
- 0x0, // clear
- KeyInput.KEY_A,
- KeyInput.KEY_B,
- KeyInput.KEY_C,
- KeyInput.KEY_D,
- KeyInput.KEY_E,
- KeyInput.KEY_F,
- KeyInput.KEY_G,
- KeyInput.KEY_H,
- KeyInput.KEY_I,
- KeyInput.KEY_J,
- KeyInput.KEY_K,
- KeyInput.KEY_L,
- KeyInput.KEY_M,
- KeyInput.KEY_N,
- KeyInput.KEY_O,
- KeyInput.KEY_P,
- KeyInput.KEY_Q,
- KeyInput.KEY_R,
- KeyInput.KEY_S,
- KeyInput.KEY_T,
- KeyInput.KEY_U,
- KeyInput.KEY_V,
- KeyInput.KEY_W,
- KeyInput.KEY_X,
- KeyInput.KEY_Y,
- KeyInput.KEY_Z,
- KeyInput.KEY_COMMA,
- KeyInput.KEY_PERIOD,
- KeyInput.KEY_LMENU,
- KeyInput.KEY_RMENU,
- KeyInput.KEY_LSHIFT,
- KeyInput.KEY_RSHIFT,
- // 0x0, // fn
- // 0x0, // cap (?)
-
- KeyInput.KEY_TAB,
- KeyInput.KEY_SPACE,
- 0x0, // sym (?) symbol
- 0x0, // explorer
- 0x0, // envelope
- KeyInput.KEY_RETURN, // newline/enter
- KeyInput.KEY_DELETE,
- KeyInput.KEY_GRAVE,
- KeyInput.KEY_MINUS,
- KeyInput.KEY_EQUALS,
- KeyInput.KEY_LBRACKET,
- KeyInput.KEY_RBRACKET,
- KeyInput.KEY_BACKSLASH,
- KeyInput.KEY_SEMICOLON,
- KeyInput.KEY_APOSTROPHE,
- KeyInput.KEY_SLASH,
- KeyInput.KEY_AT, // at (@)
- KeyInput.KEY_NUMLOCK, //0x0, // num
- 0x0, //headset hook
- 0x0, //focus
- KeyInput.KEY_ADD,
- KeyInput.KEY_LMETA, //menu
- 0x0,//notification
- 0x0,//search
- 0x0,//media play/pause
- 0x0,//media stop
- 0x0,//media next
- 0x0,//media previous
- 0x0,//media rewind
- 0x0,//media fastforward
- 0x0,//mute
- };
-
- public AndroidInput(Context ctx, AttributeSet attribs) {
- super(ctx, attribs);
- detector = new GestureDetector(null, this, null, false);
- scaledetector = new ScaleGestureDetector(ctx, this);
-
- }
-
- public AndroidInput(Context ctx) {
- super(ctx);
- detector = new GestureDetector(null, this, null, false);
- scaledetector = new ScaleGestureDetector(ctx, this);
- }
-
- private TouchEvent getNextFreeTouchEvent() {
- return getNextFreeTouchEvent(false);
- }
-
- /**
- * Fetches a touch event from the reuse pool
- * @param wait if true waits for a reusable event to get available/released by an other thread, if false returns a new one if needed
- * @return a usable TouchEvent
- */
- private TouchEvent getNextFreeTouchEvent(boolean wait) {
- TouchEvent evt = null;
- synchronized (eventPoolUnConsumed) {
- int size = eventPoolUnConsumed.size();
- while (size > 0) {
- evt = eventPoolUnConsumed.pop();
- if (!evt.isConsumed()) {
- eventPoolUnConsumed.push(evt);
- evt = null;
- } else {
- break;
- }
- size--;
- }
- }
-
-
- if (evt == null) {
- if (eventPool.isEmpty() && wait) {
- logger.warning("eventPool buffer underrun");
- boolean isEmpty;
- do {
- synchronized (eventPool) {
- isEmpty = eventPool.isEmpty();
- }
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- }
- } while (isEmpty);
- synchronized (eventPool) {
- evt = eventPool.pop();
- }
- } else if (eventPool.isEmpty()) {
- evt = new TouchEvent();
- logger.warning("eventPool buffer underrun");
- } else {
- synchronized (eventPool) {
- evt = eventPool.pop();
- }
- }
- }
- return evt;
- }
-
- /**
- * onTouchEvent gets called from android thread on touchpad events
- */
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- boolean bWasHandled = false;
- TouchEvent touch;
- // System.out.println("native : " + event.getAction());
- int action = event.getAction() & MotionEvent.ACTION_MASK;
- int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- int pointerId = event.getPointerId(pointerIndex);
-
- // final int historySize = event.getHistorySize();
- //final int pointerCount = event.getPointerCount();
-
-
- switch (action) {
-
- case MotionEvent.ACTION_POINTER_DOWN:
- case MotionEvent.ACTION_DOWN:
-
-
- touch = getNextFreeTouchEvent();
- touch.set(Type.DOWN, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0);
- touch.setPointerId(pointerId);
- touch.setTime(event.getEventTime());
- touch.setPressure(event.getPressure(pointerIndex));
- processEvent(touch);
-
- bWasHandled = true;
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
-
- touch = getNextFreeTouchEvent();
- touch.set(Type.UP, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0);
- touch.setPointerId(pointerId);
- touch.setTime(event.getEventTime());
- touch.setPressure(event.getPressure(pointerIndex));
- processEvent(touch);
-
-
- bWasHandled = true;
- break;
- case MotionEvent.ACTION_MOVE:
-
-
- // Convert all pointers into events
- for (int p = 0; p < event.getPointerCount(); p++) {
- Vector2f lastPos = lastPositions.get(pointerIndex);
- if (lastPos == null) {
- lastPos = new Vector2f(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex));
- lastPositions.put(pointerId, lastPos);
- }
- touch = getNextFreeTouchEvent();
- touch.set(Type.MOVE, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), event.getX(pointerIndex) - lastPos.x, this.getHeight() - event.getY(pointerIndex) - lastPos.y);
- touch.setPointerId(pointerId);
- touch.setTime(event.getEventTime());
- touch.setPressure(event.getPressure(pointerIndex));
- processEvent(touch);
- lastPos.set(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex));
- }
- bWasHandled = true;
- break;
-
-
- case MotionEvent.ACTION_OUTSIDE:
- break;
-
- }
-
- // Try to detect gestures
- this.detector.onTouchEvent(event);
- this.scaledetector.onTouchEvent(event);
-
- return bWasHandled;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- TouchEvent evt;
- evt = getNextFreeTouchEvent();
- evt.set(TouchEvent.Type.KEY_DOWN);
- evt.setKeyCode(keyCode);
- evt.setCharacters(event.getCharacters());
- evt.setTime(event.getEventTime());
-
- // Send the event
- processEvent(evt);
-
- // Handle all keys ourself except Volume Up/Down
- if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
- return false;
- } else {
- return true;
- }
-
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- TouchEvent evt;
- evt = getNextFreeTouchEvent();
- evt.set(TouchEvent.Type.KEY_UP);
- evt.setKeyCode(keyCode);
- evt.setCharacters(event.getCharacters());
- evt.setTime(event.getEventTime());
-
- // Send the event
- processEvent(evt);
-
- // Handle all keys ourself except Volume Up/Down
- if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
- return false;
- } else {
- return true;
- }
- }
-
- // -----------------------------------------
- // JME3 Input interface
- @Override
- public void initialize() {
- TouchEvent item;
- for (int i = 0; i < MAX_EVENTS; i++) {
- item = new TouchEvent();
- eventPool.push(item);
- }
- isInitialized = true;
- }
-
- @Override
- public void destroy() {
- isInitialized = false;
-
- // Clean up queues
- while (!eventPool.isEmpty()) {
- eventPool.pop();
- }
- while (!eventQueue.isEmpty()) {
- eventQueue.pop();
- }
- }
-
- @Override
- public boolean isInitialized() {
- return isInitialized;
- }
-
- @Override
- public void setInputListener(RawInputListener listener) {
- this.listener = listener;
- }
-
- @Override
- public long getInputTimeNanos() {
- return System.nanoTime();
- }
- // -----------------------------------------
-
- private void processEvent(TouchEvent event) {
- synchronized (eventQueue) {
- eventQueue.push(event);
- }
- }
-
- // --------------- INSIDE GLThread ---------------
- @Override
- public void update() {
- generateEvents();
- }
-
- private void generateEvents() {
- if (listener != null) {
- TouchEvent event;
- MouseButtonEvent btn;
- int newX;
- int newY;
-
- while (!eventQueue.isEmpty()) {
- synchronized (eventQueue) {
- event = eventQueue.pop();
- }
- if (event != null) {
- listener.onTouchEvent(event);
-
- if (mouseEventsEnabled) {
- if (mouseEventsInvertX) {
- newX = this.getWidth() - (int) event.getX();
- } else {
- newX = (int) event.getX();
- }
-
- if (mouseEventsInvertY) {
- newY = this.getHeight() - (int) event.getY();
- } else {
- newY = (int) event.getY();
- }
-
- switch (event.getType()) {
- case DOWN:
- // Handle mouse down event
- btn = new MouseButtonEvent(0, true, newX, newY);
- btn.setTime(event.getTime());
- listener.onMouseButtonEvent(btn);
- // Store current pos
- lastX = -1;
- lastY = -1;
- break;
-
- case UP:
- // Handle mouse up event
- btn = new MouseButtonEvent(0, false, newX, newY);
- btn.setTime(event.getTime());
- listener.onMouseButtonEvent(btn);
- // Store current pos
- lastX = -1;
- lastY = -1;
- break;
-
- case MOVE:
- int dx;
- int dy;
- if (lastX != -1) {
- dx = newX - lastX;
- dy = newY - lastY;
- } else {
- dx = 0;
- dy = 0;
- }
- MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0);
- mot.setTime(event.getTime());
- listener.onMouseMotionEvent(mot);
- lastX = newX;
- lastY = newY;
- break;
- }
-
-
- }
- }
-
- if (event.isConsumed() == false) {
- synchronized (eventPoolUnConsumed) {
- eventPoolUnConsumed.push(event);
- }
-
- } else {
- synchronized (eventPool) {
- eventPool.push(event);
- }
- }
- }
-
- }
- }
- // --------------- ENDOF INSIDE GLThread ---------------
-
- // --------------- Gesture detected callback events ---------------
- public boolean onDown(MotionEvent event) {
- return false;
- }
-
- public void onLongPress(MotionEvent event) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.LONGPRESSED, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(event.getEventTime());
- processEvent(touch);
- }
-
- public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.FLING, event.getX(), this.getHeight() - event.getY(), vx, vy);
- touch.setPointerId(0);
- touch.setTime(event.getEventTime());
- processEvent(touch);
-
- return true;
- }
-
- public boolean onSingleTapConfirmed(MotionEvent event) {
- //Nothing to do here the tap has already been detected.
- return false;
- }
-
- public boolean onDoubleTap(MotionEvent event) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.DOUBLETAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(event.getEventTime());
- processEvent(touch);
- return true;
- }
-
- public boolean onDoubleTapEvent(MotionEvent event) {
- return false;
- }
-
- public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.SCALE_START, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(scaleGestureDetector.getEventTime());
- touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
- touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
- processEvent(touch);
- // System.out.println("scaleBegin");
-
- return true;
- }
-
- public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(scaleGestureDetector.getEventTime());
- touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
- touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
- processEvent(touch);
- // System.out.println("scale");
-
- return false;
- }
-
- public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(scaleGestureDetector.getEventTime());
- touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
- touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
- processEvent(touch);
- }
-
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.SCROLL, e1.getX(), this.getHeight() - e1.getY(), distanceX, distanceY * (-1));
- touch.setPointerId(0);
- touch.setTime(e1.getEventTime());
- processEvent(touch);
- //System.out.println("scroll " + e1.getPointerCount());
- return false;
- }
-
- public void onShowPress(MotionEvent event) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.SHOWPRESS, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(event.getEventTime());
- processEvent(touch);
- }
-
- public boolean onSingleTapUp(MotionEvent event) {
- TouchEvent touch = getNextFreeTouchEvent();
- touch.set(Type.TAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
- touch.setPointerId(0);
- touch.setTime(event.getEventTime());
- processEvent(touch);
- return true;
- }
-
- @Override
- public void setSimulateMouse(boolean simulate) {
- mouseEventsEnabled = simulate;
- }
-
- @Override
- public void setSimulateKeyboard(boolean simulate) {
- keyboardEventsEnabled = simulate;
- }
-
- @Override
- public void setOmitHistoricEvents(boolean dontSendHistory) {
- this.dontSendHistory = dontSendHistory;
- }
-
- // TODO: move to TouchInput
- public boolean isMouseEventsEnabled() {
- return mouseEventsEnabled;
- }
-
- public void setMouseEventsEnabled(boolean mouseEventsEnabled) {
- this.mouseEventsEnabled = mouseEventsEnabled;
- }
-
- public boolean isMouseEventsInvertY() {
- return mouseEventsInvertY;
- }
-
- public void setMouseEventsInvertY(boolean mouseEventsInvertY) {
- this.mouseEventsInvertY = mouseEventsInvertY;
- }
-
- public boolean isMouseEventsInvertX() {
- return mouseEventsInvertX;
- }
-
- public void setMouseEventsInvertX(boolean mouseEventsInvertX) {
- this.mouseEventsInvertX = mouseEventsInvertX;
- }
-}
+package com.jme3.input.android;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import com.jme3.input.KeyInput;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.TouchInput;
+import com.jme3.input.event.MouseButtonEvent;
+import com.jme3.input.event.MouseMotionEvent;
+import com.jme3.input.event.TouchEvent;
+import com.jme3.input.event.TouchEvent.Type;
+import com.jme3.math.Vector2f;
+import com.jme3.util.RingBuffer;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+/**
+ * <code>AndroidInput</code> is one of the main components that connect jme with android. Is derived from GLSurfaceView and handles all Inputs
+ * @author larynx
+ *
+ */
+public class AndroidInput extends GLSurfaceView implements
+ TouchInput,
+ GestureDetector.OnGestureListener,
+ GestureDetector.OnDoubleTapListener,
+ ScaleGestureDetector.OnScaleGestureListener {
+
+ final private static int MAX_EVENTS = 1024;
+ // Custom settings
+ public boolean mouseEventsEnabled = true;
+ public boolean mouseEventsInvertX = false;
+ public boolean mouseEventsInvertY = false;
+ public boolean keyboardEventsEnabled = false;
+ public boolean dontSendHistory = false;
+ // Used to transfer events from android thread to GLThread
+ final private RingBuffer<TouchEvent> eventQueue = new RingBuffer<TouchEvent>(MAX_EVENTS);
+ final private RingBuffer<TouchEvent> eventPoolUnConsumed = new RingBuffer<TouchEvent>(MAX_EVENTS);
+ final private RingBuffer<TouchEvent> eventPool = new RingBuffer<TouchEvent>(MAX_EVENTS);
+ final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>();
+ // Internal
+ private ScaleGestureDetector scaledetector;
+ private GestureDetector detector;
+ private int lastX;
+ private int lastY;
+ private final static Logger logger = Logger.getLogger(AndroidInput.class.getName());
+ private boolean isInitialized = false;
+ private RawInputListener listener = null;
+ private static final int[] ANDROID_TO_JME = {
+ 0x0, // unknown
+ 0x0, // key code soft left
+ 0x0, // key code soft right
+ KeyInput.KEY_HOME,
+ KeyInput.KEY_ESCAPE, // key back
+ 0x0, // key call
+ 0x0, // key endcall
+ KeyInput.KEY_0,
+ KeyInput.KEY_1,
+ KeyInput.KEY_2,
+ KeyInput.KEY_3,
+ KeyInput.KEY_4,
+ KeyInput.KEY_5,
+ KeyInput.KEY_6,
+ KeyInput.KEY_7,
+ KeyInput.KEY_8,
+ KeyInput.KEY_9,
+ KeyInput.KEY_MULTIPLY,
+ 0x0, // key pound
+ KeyInput.KEY_UP,
+ KeyInput.KEY_DOWN,
+ KeyInput.KEY_LEFT,
+ KeyInput.KEY_RIGHT,
+ KeyInput.KEY_RETURN, // dpad center
+ 0x0, // volume up
+ 0x0, // volume down
+ KeyInput.KEY_POWER, // power (?)
+ 0x0, // camera
+ 0x0, // clear
+ KeyInput.KEY_A,
+ KeyInput.KEY_B,
+ KeyInput.KEY_C,
+ KeyInput.KEY_D,
+ KeyInput.KEY_E,
+ KeyInput.KEY_F,
+ KeyInput.KEY_G,
+ KeyInput.KEY_H,
+ KeyInput.KEY_I,
+ KeyInput.KEY_J,
+ KeyInput.KEY_K,
+ KeyInput.KEY_L,
+ KeyInput.KEY_M,
+ KeyInput.KEY_N,
+ KeyInput.KEY_O,
+ KeyInput.KEY_P,
+ KeyInput.KEY_Q,
+ KeyInput.KEY_R,
+ KeyInput.KEY_S,
+ KeyInput.KEY_T,
+ KeyInput.KEY_U,
+ KeyInput.KEY_V,
+ KeyInput.KEY_W,
+ KeyInput.KEY_X,
+ KeyInput.KEY_Y,
+ KeyInput.KEY_Z,
+ KeyInput.KEY_COMMA,
+ KeyInput.KEY_PERIOD,
+ KeyInput.KEY_LMENU,
+ KeyInput.KEY_RMENU,
+ KeyInput.KEY_LSHIFT,
+ KeyInput.KEY_RSHIFT,
+ // 0x0, // fn
+ // 0x0, // cap (?)
+
+ KeyInput.KEY_TAB,
+ KeyInput.KEY_SPACE,
+ 0x0, // sym (?) symbol
+ 0x0, // explorer
+ 0x0, // envelope
+ KeyInput.KEY_RETURN, // newline/enter
+ KeyInput.KEY_DELETE,
+ KeyInput.KEY_GRAVE,
+ KeyInput.KEY_MINUS,
+ KeyInput.KEY_EQUALS,
+ KeyInput.KEY_LBRACKET,
+ KeyInput.KEY_RBRACKET,
+ KeyInput.KEY_BACKSLASH,
+ KeyInput.KEY_SEMICOLON,
+ KeyInput.KEY_APOSTROPHE,
+ KeyInput.KEY_SLASH,
+ KeyInput.KEY_AT, // at (@)
+ KeyInput.KEY_NUMLOCK, //0x0, // num
+ 0x0, //headset hook
+ 0x0, //focus
+ KeyInput.KEY_ADD,
+ KeyInput.KEY_LMETA, //menu
+ 0x0,//notification
+ 0x0,//search
+ 0x0,//media play/pause
+ 0x0,//media stop
+ 0x0,//media next
+ 0x0,//media previous
+ 0x0,//media rewind
+ 0x0,//media fastforward
+ 0x0,//mute
+ };
+
+ public AndroidInput(Context ctx, AttributeSet attribs) {
+ super(ctx, attribs);
+ detector = new GestureDetector(null, this, null, false);
+ scaledetector = new ScaleGestureDetector(ctx, this);
+
+ }
+
+ public AndroidInput(Context ctx) {
+ super(ctx);
+ detector = new GestureDetector(null, this, null, false);
+ scaledetector = new ScaleGestureDetector(ctx, this);
+ }
+
+ private TouchEvent getNextFreeTouchEvent() {
+ return getNextFreeTouchEvent(false);
+ }
+
+ /**
+ * Fetches a touch event from the reuse pool
+ * @param wait if true waits for a reusable event to get available/released
+ * by an other thread, if false returns a new one if needed.
+ *
+ * @return a usable TouchEvent
+ */
+ private TouchEvent getNextFreeTouchEvent(boolean wait) {
+ TouchEvent evt = null;
+ synchronized (eventPoolUnConsumed) {
+ int size = eventPoolUnConsumed.size();
+ while (size > 0) {
+ evt = eventPoolUnConsumed.pop();
+ if (!evt.isConsumed()) {
+ eventPoolUnConsumed.push(evt);
+ evt = null;
+ } else {
+ break;
+ }
+ size--;
+ }
+ }
+
+ if (evt == null) {
+ if (eventPool.isEmpty() && wait) {
+ logger.warning("eventPool buffer underrun");
+ boolean isEmpty;
+ do {
+ synchronized (eventPool) {
+ isEmpty = eventPool.isEmpty();
+ }
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ }
+ } while (isEmpty);
+ synchronized (eventPool) {
+ evt = eventPool.pop();
+ }
+ } else if (eventPool.isEmpty()) {
+ evt = new TouchEvent();
+ logger.warning("eventPool buffer underrun");
+ } else {
+ synchronized (eventPool) {
+ evt = eventPool.pop();
+ }
+ }
+ }
+ return evt;
+ }
+
+ /**
+ * onTouchEvent gets called from android thread on touchpad events
+ */
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ boolean bWasHandled = false;
+ TouchEvent touch;
+ // System.out.println("native : " + event.getAction());
+ int action = event.getAction() & MotionEvent.ACTION_MASK;
+ int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ int pointerId = event.getPointerId(pointerIndex);
+
+ // final int historySize = event.getHistorySize();
+ //final int pointerCount = event.getPointerCount();
+
+ switch (action) {
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_DOWN:
+ touch = getNextFreeTouchEvent();
+ touch.set(Type.DOWN, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0);
+ touch.setPointerId(pointerId);
+ touch.setTime(event.getEventTime());
+ touch.setPressure(event.getPressure(pointerIndex));
+ processEvent(touch);
+
+ bWasHandled = true;
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+
+ touch = getNextFreeTouchEvent();
+ touch.set(Type.UP, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0);
+ touch.setPointerId(pointerId);
+ touch.setTime(event.getEventTime());
+ touch.setPressure(event.getPressure(pointerIndex));
+ processEvent(touch);
+
+
+ bWasHandled = true;
+ break;
+ case MotionEvent.ACTION_MOVE:
+
+
+ // Convert all pointers into events
+ for (int p = 0; p < event.getPointerCount(); p++) {
+ Vector2f lastPos = lastPositions.get(pointerIndex);
+ if (lastPos == null) {
+ lastPos = new Vector2f(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex));
+ lastPositions.put(pointerId, lastPos);
+ }
+ touch = getNextFreeTouchEvent();
+ touch.set(Type.MOVE, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), event.getX(pointerIndex) - lastPos.x, this.getHeight() - event.getY(pointerIndex) - lastPos.y);
+ touch.setPointerId(pointerId);
+ touch.setTime(event.getEventTime());
+ touch.setPressure(event.getPressure(pointerIndex));
+ processEvent(touch);
+ lastPos.set(event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex));
+ }
+ bWasHandled = true;
+ break;
+ case MotionEvent.ACTION_OUTSIDE:
+ break;
+
+ }
+
+ // Try to detect gestures
+ this.detector.onTouchEvent(event);
+ this.scaledetector.onTouchEvent(event);
+
+ return bWasHandled;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ TouchEvent evt;
+ evt = getNextFreeTouchEvent();
+ evt.set(TouchEvent.Type.KEY_DOWN);
+ evt.setKeyCode(keyCode);
+ evt.setCharacters(event.getCharacters());
+ evt.setTime(event.getEventTime());
+
+ // Send the event
+ processEvent(evt);
+
+ // Handle all keys ourself except Volume Up/Down
+ if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ TouchEvent evt;
+ evt = getNextFreeTouchEvent();
+ evt.set(TouchEvent.Type.KEY_UP);
+ evt.setKeyCode(keyCode);
+ evt.setCharacters(event.getCharacters());
+ evt.setTime(event.getEventTime());
+
+ // Send the event
+ processEvent(evt);
+
+ // Handle all keys ourself except Volume Up/Down
+ if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP) || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ // -----------------------------------------
+ // JME3 Input interface
+ @Override
+ public void initialize() {
+ TouchEvent item;
+ for (int i = 0; i < MAX_EVENTS; i++) {
+ item = new TouchEvent();
+ eventPool.push(item);
+ }
+ isInitialized = true;
+ }
+
+ @Override
+ public void destroy() {
+ isInitialized = false;
+
+ // Clean up queues
+ while (!eventPool.isEmpty()) {
+ eventPool.pop();
+ }
+ while (!eventQueue.isEmpty()) {
+ eventQueue.pop();
+ }
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return isInitialized;
+ }
+
+ @Override
+ public void setInputListener(RawInputListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public long getInputTimeNanos() {
+ return System.nanoTime();
+ }
+ // -----------------------------------------
+
+ private void processEvent(TouchEvent event) {
+ synchronized (eventQueue) {
+ eventQueue.push(event);
+ }
+ }
+
+ // --------------- INSIDE GLThread ---------------
+ @Override
+ public void update() {
+ generateEvents();
+ }
+
+ private void generateEvents() {
+ if (listener != null) {
+ TouchEvent event;
+ MouseButtonEvent btn;
+ int newX;
+ int newY;
+
+ while (!eventQueue.isEmpty()) {
+ synchronized (eventQueue) {
+ event = eventQueue.pop();
+ }
+ if (event != null) {
+ listener.onTouchEvent(event);
+
+ if (mouseEventsEnabled) {
+ if (mouseEventsInvertX) {
+ newX = this.getWidth() - (int) event.getX();
+ } else {
+ newX = (int) event.getX();
+ }
+
+ if (mouseEventsInvertY) {
+ newY = this.getHeight() - (int) event.getY();
+ } else {
+ newY = (int) event.getY();
+ }
+
+ switch (event.getType()) {
+ case DOWN:
+ // Handle mouse down event
+ btn = new MouseButtonEvent(0, true, newX, newY);
+ btn.setTime(event.getTime());
+ listener.onMouseButtonEvent(btn);
+ // Store current pos
+ lastX = -1;
+ lastY = -1;
+ break;
+
+ case UP:
+ // Handle mouse up event
+ btn = new MouseButtonEvent(0, false, newX, newY);
+ btn.setTime(event.getTime());
+ listener.onMouseButtonEvent(btn);
+ // Store current pos
+ lastX = -1;
+ lastY = -1;
+ break;
+
+ case MOVE:
+ int dx;
+ int dy;
+ if (lastX != -1) {
+ dx = newX - lastX;
+ dy = newY - lastY;
+ } else {
+ dx = 0;
+ dy = 0;
+ }
+ MouseMotionEvent mot = new MouseMotionEvent(newX, newY, dx, dy, 0, 0);
+ mot.setTime(event.getTime());
+ listener.onMouseMotionEvent(mot);
+ lastX = newX;
+ lastY = newY;
+ break;
+ }
+
+
+ }
+ }
+
+ if (event.isConsumed() == false) {
+ synchronized (eventPoolUnConsumed) {
+ eventPoolUnConsumed.push(event);
+ }
+
+ } else {
+ synchronized (eventPool) {
+ eventPool.push(event);
+ }
+ }
+ }
+
+ }
+ }
+ // --------------- ENDOF INSIDE GLThread ---------------
+
+ // --------------- Gesture detected callback events ---------------
+ public boolean onDown(MotionEvent event) {
+ return false;
+ }
+
+ public void onLongPress(MotionEvent event) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.LONGPRESSED, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(event.getEventTime());
+ processEvent(touch);
+ }
+
+ public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.FLING, event.getX(), this.getHeight() - event.getY(), vx, vy);
+ touch.setPointerId(0);
+ touch.setTime(event.getEventTime());
+ processEvent(touch);
+
+ return true;
+ }
+
+ public boolean onSingleTapConfirmed(MotionEvent event) {
+ //Nothing to do here the tap has already been detected.
+ return false;
+ }
+
+ public boolean onDoubleTap(MotionEvent event) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.DOUBLETAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(event.getEventTime());
+ processEvent(touch);
+ return true;
+ }
+
+ public boolean onDoubleTapEvent(MotionEvent event) {
+ return false;
+ }
+
+ public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.SCALE_START, scaleGestureDetector.getFocusX(), scaleGestureDetector.getFocusY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(scaleGestureDetector.getEventTime());
+ touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
+ touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
+ processEvent(touch);
+ // System.out.println("scaleBegin");
+
+ return true;
+ }
+
+ public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(scaleGestureDetector.getEventTime());
+ touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
+ touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
+ processEvent(touch);
+ // System.out.println("scale");
+
+ return false;
+ }
+
+ public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(scaleGestureDetector.getEventTime());
+ touch.setScaleSpan(scaleGestureDetector.getCurrentSpan());
+ touch.setScaleFactor(scaleGestureDetector.getScaleFactor());
+ processEvent(touch);
+ }
+
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.SCROLL, e1.getX(), this.getHeight() - e1.getY(), distanceX, distanceY * (-1));
+ touch.setPointerId(0);
+ touch.setTime(e1.getEventTime());
+ processEvent(touch);
+ //System.out.println("scroll " + e1.getPointerCount());
+ return false;
+ }
+
+ public void onShowPress(MotionEvent event) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.SHOWPRESS, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(event.getEventTime());
+ processEvent(touch);
+ }
+
+ public boolean onSingleTapUp(MotionEvent event) {
+ TouchEvent touch = getNextFreeTouchEvent();
+ touch.set(Type.TAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f);
+ touch.setPointerId(0);
+ touch.setTime(event.getEventTime());
+ processEvent(touch);
+ return true;
+ }
+
+ @Override
+ public void setSimulateMouse(boolean simulate) {
+ mouseEventsEnabled = simulate;
+ }
+ @Override
+ public boolean getSimulateMouse() {
+ return mouseEventsEnabled;
+ }
+
+ @Override
+ public void setSimulateKeyboard(boolean simulate) {
+ keyboardEventsEnabled = simulate;
+ }
+
+ @Override
+ public void setOmitHistoricEvents(boolean dontSendHistory) {
+ this.dontSendHistory = dontSendHistory;
+ }
+
+ // TODO: move to TouchInput
+ public boolean isMouseEventsEnabled() {
+ return mouseEventsEnabled;
+ }
+
+ public void setMouseEventsEnabled(boolean mouseEventsEnabled) {
+ this.mouseEventsEnabled = mouseEventsEnabled;
+ }
+
+ public boolean isMouseEventsInvertY() {
+ return mouseEventsInvertY;
+ }
+
+ public void setMouseEventsInvertY(boolean mouseEventsInvertY) {
+ this.mouseEventsInvertY = mouseEventsInvertY;
+ }
+
+ public boolean isMouseEventsInvertX() {
+ return mouseEventsInvertX;
+ }
+
+ public void setMouseEventsInvertX(boolean mouseEventsInvertX) {
+ this.mouseEventsInvertX = mouseEventsInvertX;
+ }
+}
diff --git a/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java b/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java
index 34e4592..c8b2228 100644
--- a/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java
+++ b/engine/src/android/com/jme3/input/android/AndroidTouchInputListener.java
@@ -6,14 +6,17 @@ import com.jme3.input.RawInputListener;
import com.jme3.input.event.TouchEvent;
/**
- * AndroidTouchInputListener is an inputlistener interface which defines callbacks/events for android touch screens
- * For use with class AndroidInput
+ * AndroidTouchInputListener is an inputlistener interface which defines
+ * callbacks/events for android touch screens For use with class AndroidInput
+ *
* @author larynx
*
*/
-public interface AndroidTouchInputListener extends RawInputListener
-{
+public interface AndroidTouchInputListener extends RawInputListener {
+
public void onTouchEvent(TouchEvent evt);
+
public void onMotionEvent(MotionEvent evt);
+
public void onAndroidKeyEvent(KeyEvent evt);
}
diff --git a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
index b5a8c14..7e7af29 100644
--- a/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
+++ b/engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java
@@ -31,9 +31,7 @@
*/
package com.jme3.renderer.android;
-import android.graphics.Bitmap;
import android.opengl.GLES10;
-import android.opengl.GLES11;
import android.opengl.GLES20;
import android.os.Build;
import com.jme3.asset.AndroidImageInfo;
@@ -60,14 +58,11 @@ import com.jme3.texture.Texture.WrapAxis;
import com.jme3.util.BufferUtils;
import com.jme3.util.ListMap;
import com.jme3.util.NativeObjectManager;
-import com.jme3.util.SafeArrayList;
import java.nio.*;
-import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
-import javax.microedition.khronos.opengles.GL10;
public class OGLESShaderRenderer implements Renderer {
@@ -360,25 +355,10 @@ public class OGLESShaderRenderer implements Renderer {
}
applyRenderState(RenderState.DEFAULT);
-// GLES20.glClearDepthf(1.0f);
-
- if (verboseLogging) {
- logger.info("GLES20.glDisable(GL10.GL_DITHER)");
- }
-
- GLES20.glDisable(GL10.GL_DITHER);
+ GLES20.glDisable(GLES20.GL_DITHER);
checkGLError();
- if (verboseLogging) {
- logger.info("GLES20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST)");
- }
-
- //It seems that GL10.GL_PERSPECTIVE_CORRECTION_HINT gives invalid_enum error on android.
-// GLES20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
-
-// checkGLError();
-
useVBO = false;
// NOTE: SDK_INT is only available since 1.6,
@@ -1779,10 +1759,8 @@ public class OGLESShaderRenderer implements Renderer {
private int convertWrapMode(Texture.WrapMode mode) {
switch (mode) {
-// case BorderClamp:
-// return GLES20.GL_CLAMP_TO_BORDER;
-// case Clamp:
-// return GLES20.GL_CLAMP;
+ case BorderClamp:
+ case Clamp:
case EdgeClamp:
return GLES20.GL_CLAMP_TO_EDGE;
case Repeat:
@@ -2557,7 +2535,7 @@ public class OGLESShaderRenderer implements Renderer {
logger.log(Level.INFO, "glDrawElements(), indexBuf.capacity ({0}), vertCount ({1})", new Object[]{indexBuf.getData().capacity(), vertCount});
}
- GLES11.glDrawElements(
+ GLES20.glDrawElements(
convertElementMode(mesh.getMode()),
indexBuf.getData().capacity(),
convertFormat(indexBuf.getFormat()),
diff --git a/engine/src/android/com/jme3/renderer/android/TextureUtil.java b/engine/src/android/com/jme3/renderer/android/TextureUtil.java
index 53b96b4..4a60d6b 100644
--- a/engine/src/android/com/jme3/renderer/android/TextureUtil.java
+++ b/engine/src/android/com/jme3/renderer/android/TextureUtil.java
@@ -70,7 +70,7 @@ public class TextureUtil {
width /= 2;
Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
- bitmap.recycle();
+ //bitmap.recycle();
bitmap = bitmap2;
}
}
@@ -94,7 +94,7 @@ public class TextureUtil {
width = FastMath.nearestPowerOfTwo(width);
height = FastMath.nearestPowerOfTwo(height);
Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
- bitmap.recycle();
+ //bitmap.recycle();
bitmap = bitmap2;
}
}
diff --git a/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java b/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java
index e55fa55..56ed415 100644
--- a/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java
+++ b/engine/src/android/com/jme3/system/android/AndroidConfigChooser.java
@@ -2,6 +2,7 @@ package com.jme3.system.android;
import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView.EGLConfigChooser;
+import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
@@ -9,26 +10,23 @@ import javax.microedition.khronos.egl.EGLDisplay;
/**
* AndroidConfigChooser is used to determine the best suited EGL Config
- * @author larynx
*
+ * @author larynx
*/
-public class AndroidConfigChooser implements EGLConfigChooser
-{
+public class AndroidConfigChooser implements EGLConfigChooser {
+
private static final Logger logger = Logger.getLogger(AndroidConfigChooser.class.getName());
-
protected int clientOpenGLESVersion = 0;
protected EGLConfig bestConfig = null;
protected EGLConfig fastestConfig = null;
protected EGLConfig choosenConfig = null;
protected ConfigType type;
protected int pixelFormat;
-
protected boolean verbose = false;
-
private final static int EGL_OPENGL_ES2_BIT = 4;
- public enum ConfigType
- {
+ public enum ConfigType {
+
/**
* RGB565, 0 alpha, 16 depth, 0 stencil
*/
@@ -39,94 +37,79 @@ public class AndroidConfigChooser implements EGLConfigChooser
BEST,
/**
* Turn off config chooser and use hardcoded
- * setEGLContextClientVersion(2);
- * setEGLConfigChooser(5, 6, 5, 0, 16, 0);
+ * setEGLContextClientVersion(2); setEGLConfigChooser(5, 6, 5, 0, 16,
+ * 0);
*/
LEGACY
}
-
- public AndroidConfigChooser(ConfigType type, boolean verbose)
- {
+
+ public AndroidConfigChooser(ConfigType type) {
this.type = type;
- this.verbose = verbose;
}
-
+
/**
* Gets called by the GLSurfaceView class to return the best config
- */
+ */
@Override
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display)
- {
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
logger.info("GLSurfaceView asks for egl config, returning: ");
logEGLConfig(choosenConfig, display, egl);
return choosenConfig;
}
-
+
/**
* findConfig is used to locate the best config and init the chooser with
+ *
* @param egl
* @param display
* @return true if successfull, false if no config was found
*/
- public boolean findConfig(EGL10 egl, EGLDisplay display)
- {
-
- if (type == ConfigType.BEST)
- {
- ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0);
- choosenConfig = compChooser.chooseConfig(egl, display);
+ public boolean findConfig(EGL10 egl, EGLDisplay display) {
+
+ if (type == ConfigType.BEST) {
+ ComponentSizeChooser compChooser = new ComponentSizeChooser(8, 8, 8, 8, 32, 0);
+ choosenConfig = compChooser.chooseConfig(egl, display);
- if (choosenConfig == null)
- {
+ if (choosenConfig == null) {
compChooser = new ComponentSizeChooser(8, 8, 8, 0, 32, 0);
choosenConfig = compChooser.chooseConfig(egl, display);
- if (choosenConfig == null)
- {
+ if (choosenConfig == null) {
compChooser = new ComponentSizeChooser(8, 8, 8, 8, 16, 0);
choosenConfig = compChooser.chooseConfig(egl, display);
- if (choosenConfig == null)
- {
+ if (choosenConfig == null) {
compChooser = new ComponentSizeChooser(8, 8, 8, 0, 16, 0);
choosenConfig = compChooser.chooseConfig(egl, display);
}
}
- }
-
+ }
+
logger.info("JME3 using best EGL configuration available here: ");
- }
- else
- {
- ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0);
- choosenConfig = compChooser.chooseConfig(egl, display);
+ } else {
+ ComponentSizeChooser compChooser = new ComponentSizeChooser(5, 6, 5, 0, 16, 0);
+ choosenConfig = compChooser.chooseConfig(egl, display);
logger.info("JME3 using fastest EGL configuration available here: ");
}
-
- if (choosenConfig != null)
- {
- logger.info("JME3 using choosen config: ");
- logEGLConfig(choosenConfig, display, egl);
+
+ if (choosenConfig != null) {
+ logger.info("JME3 using choosen config: ");
+ logEGLConfig(choosenConfig, display, egl);
pixelFormat = getPixelFormat(choosenConfig, display, egl);
clientOpenGLESVersion = getOpenGLVersion(choosenConfig, display, egl);
return true;
- }
- else
- {
+ } else {
logger.severe("###ERROR### Unable to get a valid OpenGL ES 2.0 config, nether Fastest nor Best found! Bug. Please report this.");
clientOpenGLESVersion = 1;
pixelFormat = PixelFormat.UNKNOWN;
return false;
- }
+ }
}
-
-
- private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl)
- {
+
+ private int getPixelFormat(EGLConfig conf, EGLDisplay display, EGL10 egl) {
int[] value = new int[1];
- int result = PixelFormat.RGB_565;
+ int result = PixelFormat.RGB_565;
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value);
- if (value[0] == 8)
- {
+ if (value[0] == 8) {
result = PixelFormat.RGBA_8888;
/*
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value);
@@ -139,165 +122,163 @@ public class AndroidConfigChooser implements EGLConfigChooser
result = PixelFormat.RGB_888;
}*/
}
-
- if (verbose)
- {
- logger.info("Using PixelFormat " + result);
+
+ if (verbose) {
+ logger.log(Level.INFO, "Using PixelFormat {0}", result);
}
-
+
//return result; TODO Test pixelformat
return PixelFormat.TRANSPARENT;
}
-
- private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl)
- {
+
+ private int getOpenGLVersion(EGLConfig conf, EGLDisplay display, EGL10 egl) {
int[] value = new int[1];
int result = 1;
-
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value);
// Check if conf is OpenGL ES 2.0
- if ((value[0] & EGL_OPENGL_ES2_BIT) != 0)
- {
+ if ((value[0] & EGL_OPENGL_ES2_BIT) != 0) {
result = 2;
}
- return result;
+ return result;
}
-
+
/**
* log output with egl config details
+ *
* @param conf
* @param display
* @param egl
*/
- public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl)
- {
+ public void logEGLConfig(EGLConfig conf, EGLDisplay display, EGL10 egl) {
int[] value = new int[1];
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RED_SIZE, value);
- logger.info(String.format("EGL_RED_SIZE = %d", value[0] ) );
-
+ logger.info(String.format("EGL_RED_SIZE = %d", value[0]));
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_GREEN_SIZE, value);
- logger.info(String.format("EGL_GREEN_SIZE = %d", value[0] ) );
-
+ logger.info(String.format("EGL_GREEN_SIZE = %d", value[0]));
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_BLUE_SIZE, value);
- logger.info(String.format("EGL_BLUE_SIZE = %d", value[0] ) );
-
+ logger.info(String.format("EGL_BLUE_SIZE = %d", value[0]));
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_ALPHA_SIZE, value);
- logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0] ) );
-
+ logger.info(String.format("EGL_ALPHA_SIZE = %d", value[0]));
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_DEPTH_SIZE, value);
- logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0] ) );
-
+ logger.info(String.format("EGL_DEPTH_SIZE = %d", value[0]));
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_STENCIL_SIZE, value);
- logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0] ) );
+ logger.info(String.format("EGL_STENCIL_SIZE = %d", value[0]));
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_RENDERABLE_TYPE, value);
- logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0] ) );
-
+ logger.info(String.format("EGL_RENDERABLE_TYPE = %d", value[0]));
+
egl.eglGetConfigAttrib(display, conf, EGL10.EGL_SURFACE_TYPE, value);
- logger.info(String.format("EGL_SURFACE_TYPE = %d", value[0] ) );
+ logger.info(String.format("EGL_SURFACE_TYPE = %d", value[0]));
}
-
- public int getClientOpenGLESVersion()
- {
+
+ public int getClientOpenGLESVersion() {
return clientOpenGLESVersion;
}
- public void setClientOpenGLESVersion(int clientOpenGLESVersion)
- {
+ public void setClientOpenGLESVersion(int clientOpenGLESVersion) {
this.clientOpenGLESVersion = clientOpenGLESVersion;
}
-
- public int getPixelFormat()
- {
+
+ public int getPixelFormat() {
return pixelFormat;
}
-
-
-
- private abstract class BaseConfigChooser implements EGLConfigChooser
- {
+
+ private abstract class BaseConfigChooser implements EGLConfigChooser {
+
private boolean bClientOpenGLESVersionSet;
-
- public BaseConfigChooser(int[] configSpec)
- {
- bClientOpenGLESVersionSet = false;
- mConfigSpec = filterConfigSpec(configSpec);
- }
-
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display)
- {
- int[] num_config = new int[1];
- if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
- num_config)) {
- throw new IllegalArgumentException("eglChooseConfig failed");
- }
-
- int numConfigs = num_config[0];
-
- if (numConfigs <= 0)
- {
- //throw new IllegalArgumentException("No configs match configSpec");
-
- return null;
- }
-
- EGLConfig[] configs = new EGLConfig[numConfigs];
- if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
- num_config)) {
- throw new IllegalArgumentException("eglChooseConfig#2 failed");
- }
- EGLConfig config = chooseConfig(egl, display, configs);
- //if (config == null) {
- // throw new IllegalArgumentException("No config chosen");
- //}
- return config;
- }
-
- abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs);
-
- protected int[] mConfigSpec;
-
- private int[] filterConfigSpec(int[] configSpec)
- {
- if (bClientOpenGLESVersionSet == true) {
- return configSpec;
- }
- /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
- * And we know the configSpec is well formed.
- */
- int len = configSpec.length;
- int[] newConfigSpec = new int[len + 2];
- System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
- newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
- newConfigSpec[len] = 4; /* EGL_OPENGL_ES2_BIT */
- newConfigSpec[len+1] = EGL10.EGL_NONE;
-
- bClientOpenGLESVersionSet = true;
-
- return newConfigSpec;
- }
+
+ public BaseConfigChooser(int[] configSpec) {
+ bClientOpenGLESVersionSet = false;
+ mConfigSpec = filterConfigSpec(configSpec);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+ int[] num_config = new int[1];
+ if (!egl.eglChooseConfig(display, mConfigSpec, null, 0,
+ num_config)) {
+ throw new IllegalArgumentException("eglChooseConfig failed");
+ }
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ //throw new IllegalArgumentException("No configs match configSpec");
+
+ return null;
+ }
+
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs,
+ num_config)) {
+ throw new IllegalArgumentException("eglChooseConfig#2 failed");
+ }
+ EGLConfig config = chooseConfig(egl, display, configs);
+ //if (config == null) {
+ // throw new IllegalArgumentException("No config chosen");
+ //}
+ return config;
+ }
+
+ abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs);
+ protected int[] mConfigSpec;
+
+ private int[] filterConfigSpec(int[] configSpec) {
+ if (bClientOpenGLESVersionSet == true) {
+ return configSpec;
+ }
+ /*
+ * We know none of the subclasses define EGL_RENDERABLE_TYPE. And we
+ * know the configSpec is well formed.
+ */
+ int len = configSpec.length;
+ int[] newConfigSpec = new int[len + 2];
+ System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);
+ newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;
+ newConfigSpec[len] = 4; /*
+ * EGL_OPENGL_ES2_BIT
+ */
+ newConfigSpec[len + 1] = EGL10.EGL_NONE;
+
+ bClientOpenGLESVersionSet = true;
+
+ return newConfigSpec;
+ }
}
-
+
/**
- * Choose a configuration with exactly the specified r,g,b,a sizes,
- * and at least the specified depth and stencil sizes.
+ * Choose a configuration with exactly the specified r,g,b,a sizes, and at
+ * least the specified depth and stencil sizes.
*/
- private class ComponentSizeChooser extends BaseConfigChooser
- {
+ private class ComponentSizeChooser extends BaseConfigChooser {
+
+ private int[] mValue;
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+
public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
- int alphaSize, int depthSize, int stencilSize)
- {
- super(new int[] {
- EGL10.EGL_RED_SIZE, redSize,
- EGL10.EGL_GREEN_SIZE, greenSize,
- EGL10.EGL_BLUE_SIZE, blueSize,
- EGL10.EGL_ALPHA_SIZE, alphaSize,
- EGL10.EGL_DEPTH_SIZE, depthSize,
- EGL10.EGL_STENCIL_SIZE, stencilSize,
- EGL10.EGL_NONE});
+ int alphaSize, int depthSize, int stencilSize) {
+ super(new int[]{
+ EGL10.EGL_RED_SIZE, redSize,
+ EGL10.EGL_GREEN_SIZE, greenSize,
+ EGL10.EGL_BLUE_SIZE, blueSize,
+ EGL10.EGL_ALPHA_SIZE, alphaSize,
+ EGL10.EGL_DEPTH_SIZE, depthSize,
+ EGL10.EGL_STENCIL_SIZE, stencilSize,
+ EGL10.EGL_NONE});
mValue = new int[1];
mRedSize = redSize;
mGreenSize = greenSize;
@@ -305,25 +286,22 @@ public class AndroidConfigChooser implements EGLConfigChooser
mAlphaSize = alphaSize;
mDepthSize = depthSize;
mStencilSize = stencilSize;
- }
+ }
@Override
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)
- {
- for (EGLConfig config : configs)
- {
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
+ for (EGLConfig config : configs) {
int d = findConfigAttrib(egl, display, config,
EGL10.EGL_DEPTH_SIZE, 0);
int s = findConfigAttrib(egl, display, config,
EGL10.EGL_STENCIL_SIZE, 0);
- if ((d >= mDepthSize) && (s >= mStencilSize))
- {
+ if ((d >= mDepthSize) && (s >= mStencilSize)) {
int r = findConfigAttrib(egl, display, config,
EGL10.EGL_RED_SIZE, 0);
int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
+ EGL10.EGL_GREEN_SIZE, 0);
int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
+ EGL10.EGL_BLUE_SIZE, 0);
int a = findConfigAttrib(egl, display, config,
EGL10.EGL_ALPHA_SIZE, 0);
if ((r == mRedSize) && (g == mGreenSize)
@@ -336,27 +314,12 @@ public class AndroidConfigChooser implements EGLConfigChooser
}
private int findConfigAttrib(EGL10 egl, EGLDisplay display,
- EGLConfig config, int attribute, int defaultValue)
- {
+ EGLConfig config, int attribute, int defaultValue) {
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue))
- {
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
return mValue[0];
}
return defaultValue;
}
-
- private int[] mValue;
- // Subclasses can adjust these values:
- protected int mRedSize;
- protected int mGreenSize;
- protected int mBlueSize;
- protected int mAlphaSize;
- protected int mDepthSize;
- protected int mStencilSize;
}
-
-
-
-
}
diff --git a/engine/src/android/com/jme3/system/android/OGLESContext.java b/engine/src/android/com/jme3/system/android/OGLESContext.java
index 668b68d..1ecf2e1 100644
--- a/engine/src/android/com/jme3/system/android/OGLESContext.java
+++ b/engine/src/android/com/jme3/system/android/OGLESContext.java
@@ -32,26 +32,37 @@
package com.jme3.system.android;
import android.app.Activity;
+import android.app.AlertDialog;
import android.content.Context;
+import android.content.DialogInterface;
import android.opengl.GLSurfaceView;
+import android.text.InputType;
+import android.view.Gravity;
import android.view.SurfaceHolder;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.EditText;
+import android.widget.FrameLayout;
import com.jme3.app.AndroidHarness;
import com.jme3.app.Application;
import com.jme3.input.JoyInput;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
+import com.jme3.input.SoftTextDialogInput;
import com.jme3.input.TouchInput;
import com.jme3.input.android.AndroidInput;
+import com.jme3.input.controls.SoftTextDialogInputListener;
import com.jme3.input.controls.TouchTrigger;
import com.jme3.input.dummy.DummyKeyInput;
import com.jme3.input.dummy.DummyMouseInput;
import com.jme3.renderer.android.OGLESShaderRenderer;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeContext;
+import com.jme3.system.JmeSystem;
import com.jme3.system.SystemListener;
import com.jme3.system.Timer;
import com.jme3.system.android.AndroidConfigChooser.ConfigType;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
@@ -59,7 +70,7 @@ import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;
-public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
+public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTextDialogInput {
private static final Logger logger = Logger.getLogger(OGLESContext.class.getName());
protected final AtomicBoolean created = new AtomicBoolean(false);
@@ -76,7 +87,6 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
protected boolean autoFlush = true;
protected AndroidInput view;
private boolean firstDrawFrame = true;
-
//protected int minFrameDuration = 1000 / frameRate; // Set a max FPS of 33
protected int minFrameDuration = 0; // No FPS cap
/**
@@ -145,12 +155,12 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
int[] version = new int[2];
if (egl.eglInitialize(display, version) == true) {
- logger.info("Display EGL Version: " + version[0] + "." + version[1]);
+ logger.log(Level.INFO, "Display EGL Version: {0}.{1}", new Object[]{version[0], version[1]});
}
try {
// Create a config chooser
- AndroidConfigChooser configChooser = new AndroidConfigChooser(configType, eglConfigVerboseLogging);
+ AndroidConfigChooser configChooser = new AndroidConfigChooser(configType);
// Init chooser
if (!configChooser.findConfig(egl, display)) {
listener.handleError("Unable to find suitable EGL config", null);
@@ -162,7 +172,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
listener.handleError("OpenGL ES 2.0 is not supported on this device", null);
return null;
}
-
+
// Requesting client version from GLSurfaceView which is extended by
// AndroidInput.
view.setEGLContextClientVersion(clientOpenGLESVersion);
@@ -210,12 +220,14 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
// Setup unhandled Exception Handler
if (ctx instanceof AndroidHarness) {
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+
public void uncaughtException(Thread thread, Throwable thrown) {
((AndroidHarness) ctx).handleError("Exception thrown in " + thread.toString(), thrown);
}
});
} else {
Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+
public void uncaughtException(Thread thread, Throwable thrown) {
listener.handleError("Exception thrown in " + thread.toString(), thrown);
}
@@ -244,6 +256,8 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
}
}
+ JmeSystem.setSoftTextDialogInput(this);
+
needClose.set(false);
renderable.set(true);
}
@@ -268,6 +282,13 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
logger.info("Display destroyed.");
renderable.set(false);
+ final Context ctx = this.view.getContext();
+ if (ctx instanceof AndroidHarness) {
+ AndroidHarness harness = (AndroidHarness) ctx;
+ if (harness.isFinishOnAppStop()) {
+ harness.finish();
+ }
+ }
}
}
@@ -442,4 +463,67 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer {
public int getClientOpenGLESVersion() {
return clientOpenGLESVersion;
}
+
+ public void requestDialog(final int id, final String title, final String initialValue, final SoftTextDialogInputListener listener) {
+ logger.log(Level.INFO, "requestDialog: title: {0}, initialValue: {1}",
+ new Object[]{title, initialValue});
+
+ JmeAndroidSystem.getActivity().runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+
+ final FrameLayout layoutTextDialogInput = new FrameLayout(JmeAndroidSystem.getActivity());
+ final EditText editTextDialogInput = new EditText(JmeAndroidSystem.getActivity());
+ editTextDialogInput.setWidth(LayoutParams.FILL_PARENT);
+ editTextDialogInput.setHeight(LayoutParams.FILL_PARENT);
+ editTextDialogInput.setPadding(20, 20, 20, 20);
+ editTextDialogInput.setGravity(Gravity.FILL_HORIZONTAL);
+
+ editTextDialogInput.setText(initialValue);
+
+ switch (id) {
+ case SoftTextDialogInput.TEXT_ENTRY_DIALOG:
+
+ editTextDialogInput.setInputType(InputType.TYPE_CLASS_TEXT);
+ break;
+
+ case SoftTextDialogInput.NUMERIC_ENTRY_DIALOG:
+
+ editTextDialogInput.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);
+ break;
+
+ case SoftTextDialogInput.NUMERIC_KEYPAD_DIALOG:
+
+ editTextDialogInput.setInputType(InputType.TYPE_CLASS_PHONE);
+ break;
+
+ default:
+ break;
+ }
+
+ layoutTextDialogInput.addView(editTextDialogInput);
+
+ AlertDialog dialogTextInput = new AlertDialog.Builder(JmeAndroidSystem.getActivity()).setTitle(title).setView(layoutTextDialogInput).setPositiveButton("OK",
+ new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int whichButton) {
+ /* User clicked OK, send COMPLETE action
+ * and text */
+ listener.onSoftText(SoftTextDialogInputListener.COMPLETE, editTextDialogInput.getText().toString());
+ }
+ }).setNegativeButton("Cancel",
+ new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface dialog, int whichButton) {
+ /* User clicked CANCEL, send CANCEL action
+ * and text */
+ listener.onSoftText(SoftTextDialogInputListener.CANCEL, editTextDialogInput.getText().toString());
+ }
+ }).create();
+
+ dialogTextInput.show();
+ }
+ });
+ }
}
diff --git a/engine/src/android/com/jme3/util/AndroidLogHandler.java b/engine/src/android/com/jme3/util/AndroidLogHandler.java
index 8fb21c2..1da1299 100644
--- a/engine/src/android/com/jme3/util/AndroidLogHandler.java
+++ b/engine/src/android/com/jme3/util/AndroidLogHandler.java
@@ -4,7 +4,12 @@ import android.util.Log;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+/**
+ * Converts from Java based logging ({@link Logger} to Android based
+ * logging {@link Log}.
+ */
public class AndroidLogHandler extends Handler {
@Override
@@ -21,17 +26,16 @@ public class AndroidLogHandler extends Handler {
String clsName = record.getSourceClassName();
String msg = record.getMessage();
Throwable t = record.getThrown();
- if (level == Level.INFO){
+ if (level == Level.INFO) {
Log.i(clsName, msg, t);
- }else if (level == Level.SEVERE){
+ } else if (level == Level.SEVERE) {
Log.e(clsName, msg, t);
- }else if (level == Level.WARNING){
+ } else if (level == Level.WARNING) {
Log.w(clsName, msg, t);
- }else if (level == Level.CONFIG){
+ } else if (level == Level.CONFIG) {
Log.d(clsName, msg, t);
- }else if (level == Level.FINE || level == Level.FINER || level == Level.FINEST){
+ } else if (level == Level.FINE || level == Level.FINER || level == Level.FINEST) {
Log.v(clsName, msg, t);
}
}
-
}
diff --git a/engine/src/android/com/jme3/util/RingBuffer.java b/engine/src/android/com/jme3/util/RingBuffer.java
index 786417b..1d3c22d 100644
--- a/engine/src/android/com/jme3/util/RingBuffer.java
+++ b/engine/src/android/com/jme3/util/RingBuffer.java
@@ -4,20 +4,21 @@ import java.util.Iterator;
import java.util.NoSuchElementException;
/**
- * Ring buffer (fixed size queue) implementation using a circular array (array with wrap-around).
+ * Ring buffer (fixed size queue) implementation using a circular array (array
+ * with wrap-around).
*/
// suppress unchecked warnings in Java 1.5.0_6 and later
@SuppressWarnings("unchecked")
-public class RingBuffer<Item> implements Iterable<Item> {
+public class RingBuffer<T> implements Iterable<T> {
- private Item[] buffer; // queue elements
+ private T[] buffer; // queue elements
private int count = 0; // number of elements on queue
private int indexOut = 0; // index of first element of queue
private int indexIn = 0; // index of next available slot
// cast needed since no generic array creation in Java
public RingBuffer(int capacity) {
- buffer = (Item[]) new Object[capacity];
+ buffer = (T[]) new Object[capacity];
}
public boolean isEmpty() {
@@ -28,7 +29,7 @@ public class RingBuffer<Item> implements Iterable<Item> {
return count;
}
- public void push(Item item) {
+ public void push(T item) {
if (count == buffer.length) {
throw new RuntimeException("Ring buffer overflow");
}
@@ -37,23 +38,23 @@ public class RingBuffer<Item> implements Iterable<Item> {
count++;
}
- public Item pop() {
+ public T pop() {
if (isEmpty()) {
throw new RuntimeException("Ring buffer underflow");
}
- Item item = buffer[indexOut];
+ T item = buffer[indexOut];
buffer[indexOut] = null; // to help with garbage collection
count--;
indexOut = (indexOut + 1) % buffer.length; // wrap-around
return item;
}
- public Iterator<Item> iterator() {
+ public Iterator<T> iterator() {
return new RingBufferIterator();
}
// an iterator, doesn't implement remove() since it's optional
- private class RingBufferIterator implements Iterator<Item> {
+ private class RingBufferIterator implements Iterator<T> {
private int i = 0;
@@ -65,7 +66,7 @@ public class RingBuffer<Item> implements Iterable<Item> {
throw new UnsupportedOperationException();
}
- public Item next() {
+ public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
diff --git a/engine/src/android/res/layout/about.xml b/engine/src/android/res/layout/about.xml
index 1d8c2b0..ca249e7 100644
--- a/engine/src/android/res/layout/about.xml
+++ b/engine/src/android/res/layout/about.xml
@@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
>
<LinearLayout
- android:id="@+id/buttonsContainer"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
+ android:id="@+id/buttonsContainer"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
<TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="copyright (c) 2009-2010 JMonkeyEngine"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="copyright (c) 2009-2010 JMonkeyEngine"
/>
<TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="http://www.jmonkeyengine.org"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="http://www.jmonkeyengine.org"
/>
</LinearLayout>
diff --git a/engine/src/android/res/layout/tests.xml b/engine/src/android/res/layout/tests.xml
index 70bd5ec..f38e233 100644
--- a/engine/src/android/res/layout/tests.xml
+++ b/engine/src/android/res/layout/tests.xml
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
>
<LinearLayout
- android:id="@+id/buttonsContainer"
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:id="@+id/buttonsContainer"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
<!--
<Button
android:id="@+id/SimpleTextured"
diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java
index 484e942..7f9e8ac 100644
--- a/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java
@@ -31,6 +31,14 @@
*/
package com.jme3.scene.plugins.blender.meshes;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
import com.jme3.asset.BlenderKey.FeaturesToLoad;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
@@ -57,10 +65,6 @@ import com.jme3.scene.plugins.blender.textures.TextureHelper;
import com.jme3.scene.plugins.blender.textures.UVCoordinatesGenerator;
import com.jme3.texture.Texture;
import com.jme3.util.BufferUtils;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.util.*;
-import java.util.Map.Entry;
/**
* A class that is used in mesh calculations.
@@ -300,12 +304,13 @@ public class MeshHelper extends AbstractBlenderHelper {
// generating meshes
//FloatBuffer verticesColorsBuffer = this.createFloatBuffer(verticesColors);
ByteBuffer verticesColorsBuffer = createByteBuffer(verticesColors);
+ verticesAmount = vertexList.size();
for (Entry<Integer, List<Integer>> meshEntry : meshesMap.entrySet()) {
Mesh mesh = new Mesh();
// creating vertices indices for this mesh
List<Integer> indexList = meshEntry.getValue();
- if(verticesAmount < Short.MAX_VALUE * 2) {
+ if(verticesAmount <= Short.MAX_VALUE) {
short[] indices = new short[indexList.size()];
for (int i = 0; i < indexList.size(); ++i) {
indices[i] = indexList.get(i).shortValue();
diff --git a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java b/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java
index 75fc0c5..918072e 100644
--- a/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java
+++ b/engine/src/blender/com/jme3/scene/plugins/blender/textures/blending/TextureBlenderAWT.java
@@ -56,8 +56,8 @@ public class TextureBlenderAWT extends AbstractTextureBlender {
float[] resultPixel = new float[4];
int dataIndex = 0;
while (data.hasRemaining()) {
- float tin = this.setupMaterialColor(data, format, neg, pixelColor);
- this.blendPixel(resultPixel, materialColor, color, tin, blendType, blenderContext);
+ this.setupMaterialColor(data, format, neg, pixelColor);
+ this.blendPixel(resultPixel, materialColor, pixelColor, affectFactor, blendType, blenderContext);
newData.put(dataIndex++, (byte) (resultPixel[0] * 255.0f));
newData.put(dataIndex++, (byte) (resultPixel[1] * 255.0f));
newData.put(dataIndex++, (byte) (resultPixel[2] * 255.0f));
diff --git a/engine/src/core-data/Common/MatDefs/Light/Lighting.frag b/engine/src/core-data/Common/MatDefs/Light/Lighting.frag
index 76f0e15..eb1c3fd 100644
--- a/engine/src/core-data/Common/MatDefs/Light/Lighting.frag
+++ b/engine/src/core-data/Common/MatDefs/Light/Lighting.frag
@@ -126,6 +126,10 @@ vec2 computeLighting(in vec3 wvNorm, in vec3 wvViewDir, in vec3 wvLightDir){
float att = vLightDir.w;
#endif
+ if (m_Shininess <= 1.0) {
+ specularFactor = 0.0; // should be one instruction on most cards ..
+ }
+
specularFactor *= diffuseFactor;
return vec2(diffuseFactor, specularFactor) * vec2(att);
diff --git a/engine/src/core-data/Common/MatDefs/Misc/Particle.j3md b/engine/src/core-data/Common/MatDefs/Misc/Particle.j3md
index e28d41a..73674f9 100644
--- a/engine/src/core-data/Common/MatDefs/Misc/Particle.j3md
+++ b/engine/src/core-data/Common/MatDefs/Misc/Particle.j3md
@@ -4,6 +4,10 @@ MaterialDef Point Sprite {
Texture2D Texture
Float Quadratic
Boolean PointSprite
+
+ //only used for soft particles
+ Texture2D DepthTexture
+ Float Softness
// Texture of the glowing parts of the material
Texture2D GlowMap
@@ -58,6 +62,28 @@ MaterialDef Point Sprite {
}
}
+ Technique SoftParticles{
+
+ VertexShader GLSL100 : Common/MatDefs/Misc/SoftParticle.vert
+ FragmentShader GLSL100 : Common/MatDefs/Misc/SoftParticle.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ WorldViewMatrix
+ WorldMatrix
+ CameraPosition
+ }
+
+ RenderState {
+ Blend AlphaAdditive
+ DepthWrite Off
+ }
+
+ Defines {
+ USE_TEXTURE : Texture
+ }
+ }
+
Technique FixedFunc {
RenderState {
Blend AlphaAdditive
diff --git a/engine/src/core-data/Common/MatDefs/Misc/SoftParticle.frag b/engine/src/core-data/Common/MatDefs/Misc/SoftParticle.frag
new file mode 100644
index 0000000..d3108b5
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Misc/SoftParticle.frag
@@ -0,0 +1,50 @@
+uniform sampler2D m_DepthTexture;
+uniform float m_Softness; // Power used in the contrast function
+varying vec2 vPos; // Position of the pixel
+varying vec2 projPos;// z and w valus in projection space
+
+#ifdef USE_TEXTURE
+uniform sampler2D m_Texture;
+varying vec4 texCoord;
+#endif
+
+varying vec4 color;
+
+float Contrast(float d){
+ float val = clamp( 2.0*( (d > 0.5) ? 1.0-d : d ), 0.0, 1.0);
+ float a = 0.5 * pow(val, m_Softness);
+ return (d > 0.5) ? 1.0 - a : a;
+}
+
+float stdDiff(float d){
+ return clamp((d)*m_Softness,0.0,1.0);
+}
+
+
+void main(){
+ if (color.a <= 0.01)
+ discard;
+
+ vec4 c = vec4(1.0,1.0,1.0,1.0);//color;
+ #ifdef USE_TEXTURE
+ #ifdef POINT_SPRITE
+ vec2 uv = mix(texCoord.xy, texCoord.zw, gl_PointCoord.xy);
+ #else
+ vec2 uv = texCoord.xy;
+ #endif
+ c = texture2D(m_Texture, uv) * color;
+ #endif
+
+
+ float depthv = texture2D(m_DepthTexture, vPos).x*2.0-1.0; // Scene depth
+ depthv*=projPos.y;
+ float particleDepth = projPos.x;
+
+ float zdiff =depthv-particleDepth;
+ if(zdiff<=0.0){
+ discard;
+ }
+ // Computes alpha based on the particles distance to the rest of the scene
+ c.a = c.a * stdDiff(zdiff);// Contrast(zdiff);
+ gl_FragColor =c;
+} \ No newline at end of file
diff --git a/engine/src/core-data/Common/MatDefs/Misc/SoftParticle.vert b/engine/src/core-data/Common/MatDefs/Misc/SoftParticle.vert
new file mode 100644
index 0000000..4f0dfd5
--- /dev/null
+++ b/engine/src/core-data/Common/MatDefs/Misc/SoftParticle.vert
@@ -0,0 +1,53 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+attribute vec3 inPosition;
+attribute vec4 inColor;
+attribute vec4 inTexCoord;
+
+varying vec4 color;
+// z and w values in projection space
+varying vec2 projPos;
+varying vec2 vPos; // Position of the pixel in clip space
+
+
+
+#ifdef USE_TEXTURE
+varying vec4 texCoord;
+#endif
+
+#ifdef POINT_SPRITE
+uniform mat4 g_WorldViewMatrix;
+uniform mat4 g_WorldMatrix;
+uniform vec3 g_CameraPosition;
+uniform float m_Quadratic;
+const float SIZE_MULTIPLIER = 4.0;
+attribute float inSize;
+#endif
+
+void main(){
+ vec4 pos = vec4(inPosition, 1.0);
+
+ gl_Position = g_WorldViewProjectionMatrix * pos;
+ color = inColor;
+
+ projPos = gl_Position.zw;
+ // projPos.x = 0.5 * (projPos.x) + 0.5;
+
+ // Transforms the vPosition data to the range [0,1]
+ vPos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0;
+
+ #ifdef USE_TEXTURE
+ texCoord = inTexCoord;
+ #endif
+
+ #ifdef POINT_SPRITE
+ vec4 worldPos = g_WorldMatrix * pos;
+ float d = distance(g_CameraPosition.xyz, worldPos.xyz);
+ gl_PointSize = max(1.0, (inSize * SIZE_MULTIPLIER * m_Quadratic) / d);
+
+ //vec4 worldViewPos = g_WorldViewMatrix * pos;
+ //gl_PointSize = (inSize * SIZE_MULTIPLIER * m_Quadratic)*100.0 / worldViewPos.z;
+
+ color.a *= min(gl_PointSize, 1.0);
+ #endif
+} \ No newline at end of file
diff --git a/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java b/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
index 47be413..c377a58 100644
--- a/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
+++ b/engine/src/core-effects/com/jme3/post/filters/TranslucentBucketFilter.java
@@ -5,6 +5,7 @@
package com.jme3.post.filters;
import com.jme3.asset.AssetManager;
+import com.jme3.effect.ParticleEmitter;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.post.Filter;
@@ -12,8 +13,14 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.scene.Node;
+
+import com.jme3.scene.Spatial;
import com.jme3.texture.FrameBuffer;
+import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* A filter to handle translucent objects when rendering a scene with filters that uses depth like WaterFilter and SSAOFilter
@@ -22,11 +29,25 @@ import com.jme3.texture.Texture2D;
*/
public final class TranslucentBucketFilter extends Filter {
+ private final static Logger logger = Logger.getLogger(TranslucentBucketFilter.class.getName());
private RenderManager renderManager;
+ private boolean enabledSoftParticles = false;
+ private Texture depthTexture;
+ private ViewPort viewPort;
+
+ public TranslucentBucketFilter() {
+ super("TranslucentBucketFilter");
+ }
+
+ public TranslucentBucketFilter(boolean enabledSoftParticles) {
+ this();
+ this.enabledSoftParticles = enabledSoftParticles;
+ }
@Override
protected void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
this.renderManager = rm;
+ this.viewPort = vp;
material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
material.setColor("Color", ColorRGBA.White);
Texture2D tex = processor.getFilterTexture();
@@ -37,6 +58,26 @@ public final class TranslucentBucketFilter extends Filter {
material.clearParam("NumSamples");
}
renderManager.setHandleTranslucentBucket(false);
+ if (enabledSoftParticles && depthTexture != null) {
+ initSoftParticles(vp, true);
+ }
+ }
+
+ private void initSoftParticles(ViewPort vp, boolean enabledSP) {
+ if (depthTexture != null) {
+ for (Spatial scene : vp.getScenes()) {
+ makeSoftParticleEmitter(scene, enabledSP && enabled);
+ }
+ }
+
+ }
+
+ @Override
+ protected void setDepthTexture(Texture depthTexture) {
+ this.depthTexture = depthTexture;
+ if (enabledSoftParticles && depthTexture != null) {
+ initSoftParticles(viewPort, true);
+ }
}
/**
@@ -49,6 +90,11 @@ public final class TranslucentBucketFilter extends Filter {
}
@Override
+ protected boolean isRequiresDepthTexture() {
+ return enabledSoftParticles;
+ }
+
+ @Override
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
renderManager.setCamera(viewPort.getCamera(), false);
if (prevFilterBuffer != sceneBuffer) {
@@ -63,6 +109,8 @@ public final class TranslucentBucketFilter extends Filter {
if (renderManager != null) {
renderManager.setHandleTranslucentBucket(true);
}
+
+ initSoftParticles(viewPort, false);
}
@Override
@@ -76,5 +124,32 @@ public final class TranslucentBucketFilter extends Filter {
if (renderManager != null) {
renderManager.setHandleTranslucentBucket(!enabled);
}
+ initSoftParticles(viewPort, enabledSoftParticles);
+ }
+
+ private void makeSoftParticleEmitter(Spatial scene, boolean enabled) {
+ if (scene instanceof Node) {
+ Node n = (Node) scene;
+ for (Spatial child : n.getChildren()) {
+ makeSoftParticleEmitter(child, enabled);
+ }
+ }
+ if (scene instanceof ParticleEmitter) {
+ ParticleEmitter emitter = (ParticleEmitter) scene;
+ if (enabled) {
+ enabledSoftParticles = enabled;
+
+ emitter.getMaterial().selectTechnique("SoftParticles", renderManager);
+ emitter.getMaterial().setTexture("DepthTexture", processor.getDepthTexture());
+ emitter.setQueueBucket(RenderQueue.Bucket.Translucent);
+
+ logger.log(Level.INFO, "Made particle Emitter {0} soft.", emitter.getName());
+ } else {
+ emitter.getMaterial().clearParam("DepthTexture");
+ emitter.getMaterial().selectTechnique("Default", renderManager);
+ // emitter.setQueueBucket(RenderQueue.Bucket.Transparent);
+ logger.log(Level.INFO, "Particle Emitter {0} is not soft anymore.", emitter.getName());
+ }
+ }
}
}
diff --git a/engine/src/core-plugins/com/jme3/asset/plugins/HttpZipLocator.java~ b/engine/src/core-plugins/com/jme3/asset/plugins/HttpZipLocator.java~
deleted file mode 100644
index f5fbfd1..0000000
--- a/engine/src/core-plugins/com/jme3/asset/plugins/HttpZipLocator.java~
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (c) 2009-2010 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.asset.plugins;
-
-import com.jme3.asset.AssetInfo;
-import com.jme3.asset.AssetKey;
-import com.jme3.asset.AssetLocator;
-import com.jme3.asset.AssetManager;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.CharacterCodingException;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.util.HashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-import java.util.zip.ZipEntry;
-
-public class HttpZipLocator implements AssetLocator {
-
- private static final Logger logger = Logger.getLogger(HttpZipLocator.class.getName());
-
- private URL zipUrl;
- private String rootPath = "";
- private int numEntries;
- private int tableOffset;
- private int tableLength;
- private HashMap<String, ZipEntry2> entries;
-
- private static final ByteBuffer byteBuf = ByteBuffer.allocate(250);
- private static final CharBuffer charBuf = CharBuffer.allocate(250);
- private static final CharsetDecoder utf8Decoder;
-
- static {
- Charset utf8 = Charset.forName("UTF-8");
- utf8Decoder = utf8.newDecoder();
- }
-
- private static class ZipEntry2 {
- String name;
- int length;
- int offset;
- int compSize;
- long crc;
- boolean deflate;
-
- @Override
- public String toString(){
- return "ZipEntry[name=" + name +
- ", length=" + length +
- ", compSize=" + compSize +
- ", offset=" + offset + "]";
- }
- }
-
- private static int get16(byte[] b, int off) {
- return (b[off++] & 0xff) |
- ((b[off] & 0xff) << 8);
- }
-
- private static int get32(byte[] b, int off) {
- return (b[off++] & 0xff) |
- ((b[off++] & 0xff) << 8) |
- ((b[off++] & 0xff) << 16) |
- ((b[off] & 0xff) << 24);
- }
-
- private static long getu32(byte[] b, int off) throws IOException{
- return (b[off++]&0xff) |
- ((b[off++]&0xff) << 8) |
- ((b[off++]&0xff) << 16) |
- (((long)(b[off]&0xff)) << 24);
- }
-
- private static String getUTF8String(byte[] b, int off, int len) throws CharacterCodingException {
- StringBuilder sb = new StringBuilder();
-
- int read = 0;
- while (read < len){
- // Either read n remaining bytes in b or 250 if n is higher.
- int toRead = Math.min(len - read, byteBuf.capacity());
-
- boolean endOfInput = toRead < byteBuf.capacity();
-
- // read 'toRead' bytes into byteBuf
- byteBuf.put(b, off + read, toRead);
-
- // set limit to position and set position to 0
- // so data can be decoded
- byteBuf.flip();
-
- // decode data in byteBuf
- CoderResult result = utf8Decoder.decode(byteBuf, charBuf, endOfInput);
-
- // if the result is not an underflow its an error
- // that cannot be handled.
- // if the error is an underflow and its the end of input
- // then the decoder expects more bytes but there are no more => error
- if (!result.isUnderflow() || !endOfInput){
- result.throwException();
- }
-
- // flip the char buf to get the string just decoded
- charBuf.flip();
-
- // append the decoded data into the StringBuilder
- sb.append(charBuf.toString());
-
- // clear buffers for next use
- byteBuf.clear();
- charBuf.clear();
-
- read += toRead;
- }
-
- return sb.toString();
- }
-
- private InputStream readData(int offset, int length) throws IOException{
- HttpURLConnection conn = (HttpURLConnection) zipUrl.openConnection();
- conn.setDoOutput(false);
- conn.setUseCaches(false);
- conn.setInstanceFollowRedirects(false);
- String range = "-";
- if (offset != Integer.MAX_VALUE){
- range = offset + range;
- }
- if (length != Integer.MAX_VALUE){
- if (offset != Integer.MAX_VALUE){
- range = range + (offset + length - 1);
- }else{
- range = range + length;
- }
- }
-
- conn.setRequestProperty("Range", "bytes=" + range);
- conn.connect();
- if (conn.getResponseCode() == HttpURLConnection.HTTP_PARTIAL){
- return conn.getInputStream();
- }else if (conn.getResponseCode() == HttpURLConnection.HTTP_OK){
- throw new IOException("Your server does not support HTTP feature Content-Range. Please contact your server administrator.");
- }else{
- throw new IOException(conn.getResponseCode() + " " + conn.getResponseMessage());
- }
- }
-
- private int readTableEntry(byte[] table, int offset) throws IOException{
- if (get32(table, offset) != ZipEntry.CENSIG){
- throw new IOException("Central directory error, expected 'PK12'");
- }
-
- int nameLen = get16(table, offset + ZipEntry.CENNAM);
- int extraLen = get16(table, offset + ZipEntry.CENEXT);
- int commentLen = get16(table, offset + ZipEntry.CENCOM);
- int newOffset = offset + ZipEntry.CENHDR + nameLen + extraLen + commentLen;
-
- int flags = get16(table, offset + ZipEntry.CENFLG);
- if ((flags & 1) == 1){
- // ignore this entry, it uses encryption
- return newOffset;
- }
-
- int method = get16(table, offset + ZipEntry.CENHOW);
- if (method != ZipEntry.DEFLATED && method != ZipEntry.STORED){
- // ignore this entry, it uses unknown compression method
- return newOffset;
- }
-
- String name = getUTF8String(table, offset + ZipEntry.CENHDR, nameLen);
- if (name.charAt(name.length()-1) == '/'){
- // ignore this entry, it is directory node
- // or it has no name (?)
- return newOffset;
- }
-
- ZipEntry2 entry = new ZipEntry2();
- entry.name = name;
- entry.deflate = (method == ZipEntry.DEFLATED);
- entry.crc = getu32(table, offset + ZipEntry.CENCRC);
- entry.length = get32(table, offset + ZipEntry.CENLEN);
- entry.compSize = get32(table, offset + ZipEntry.CENSIZ);
- entry.offset = get32(table, offset + ZipEntry.CENOFF);
-
- // we want offset directly into file data ..
- // move the offset forward to skip the LOC header
- entry.offset += ZipEntry.LOCHDR + nameLen + extraLen;
-
- entries.put(entry.name, entry);
-
- return newOffset;
- }
-
- private void fillByteArray(byte[] array, InputStream source) throws IOException{
- int total = 0;
- int length = array.length;
- while (total < length) {
- int read = source.read(array, total, length - total);
- if (read < 0)
- throw new IOException("Failed to read entire array");
-
- total += read;
- }
- }
-
- private void readCentralDirectory() throws IOException{
- InputStream in = readData(tableOffset, tableLength);
- byte[] header = new byte[tableLength];
-
- // Fix for "PK12 bug in town.zip": sometimes
- // not entire byte array will be read with InputStream.read()
- // (especially for big headers)
- fillByteArray(header, in);
-
-// in.read(header);
- in.close();
-
- entries = new HashMap<String, ZipEntry2>(numEntries);
- int offset = 0;
- for (int i = 0; i < numEntries; i++){
- offset = readTableEntry(header, offset);
- }
- }
-
- private void readEndHeader() throws IOException{
-
-// InputStream in = readData(Integer.MAX_VALUE, ZipEntry.ENDHDR);
-// byte[] header = new byte[ZipEntry.ENDHDR];
-// fillByteArray(header, in);
-// in.close();
-//
-// if (get32(header, 0) != ZipEntry.ENDSIG){
-// throw new IOException("End header error, expected 'PK56'");
-// }
-
- // Fix for "PK56 bug in town.zip":
- // If there's a zip comment inside the end header,
- // PK56 won't appear in the -22 position relative to the end of the
- // file!
- // In that case, we have to search for it.
- // Increase search space to 200 bytes
-
- InputStream in = readData(Integer.MAX_VALUE, 200);
- byte[] header = new byte[200];
- fillByteArray(header, in);
- in.close();
-
- int offset = -1;
- for (int i = 200 - 22; i >= 0; i--){
- if (header[i] == (byte) (ZipEntry.ENDSIG & 0xff)
- && get32(header, i) == ZipEntry.ENDSIG){
- // found location
- offset = i;
- break;
- }
- }
- if (offset == -1)
- throw new IOException("Cannot find Zip End Header in file!");
-
- numEntries = get16(header, offset + ZipEntry.ENDTOT);
- tableLength = get32(header, offset + ZipEntry.ENDSIZ);
- tableOffset = get32(header, offset + ZipEntry.ENDOFF);
- }
-
- public void load(URL url) throws IOException {
- if (!url.getProtocol().equals("http"))
- throw new UnsupportedOperationException();
-
- zipUrl = url;
- readEndHeader();
- readCentralDirectory();
- }
-
- private InputStream openStream(ZipEntry2 entry) throws IOException{
- InputStream in = readData(entry.offset, entry.compSize);
- if (entry.deflate){
- return new InflaterInputStream(in, new Inflater(true));
- }
- return in;
- }
-
- public InputStream openStream(String name) throws IOException{
- ZipEntry2 entry = entries.get(name);
- if (entry == null)
- throw new RuntimeException("Entry not found: "+name);
-
- return openStream(entry);
- }
-
- public void setRootPath(String path){
- if (!rootPath.equals(path)){
- rootPath = path;
- try {
- load(new URL(path));
- } catch (IOException ex) {
- logger.log(Level.WARNING, "Failed to set root path "+path, ex);
- }
- }
- }
-
- public AssetInfo locate(AssetManager manager, AssetKey key){
- final ZipEntry2 entry = entries.get(key.getName());
- if (entry == null)
- return null;
-
- return new AssetInfo(manager, key){
- @Override
- public InputStream openStream() {
- try {
- return HttpZipLocator.this.openStream(entry);
- } catch (IOException ex) {
- logger.log(Level.WARNING, "Error retrieving "+entry.name, ex);
- return null;
- }
- }
- };
- }
-
-}
diff --git a/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java b/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java
index 3ce7f52..47165f6 100644
--- a/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java
+++ b/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java
@@ -454,9 +454,11 @@ public final class OBJLoader implements AssetLoader {
if (hasNormals){
normBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3);
+ m.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
}
if (hasTexCoord){
tcBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 2);
+ m.setBuffer(VertexBuffer.Type.TexCoord, 2, tcBuf);
}
IndexBuffer indexBuf = null;
@@ -517,9 +519,7 @@ public final class OBJLoader implements AssetLoader {
}
m.setBuffer(VertexBuffer.Type.Position, 3, posBuf);
- m.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
- m.setBuffer(VertexBuffer.Type.TexCoord, 2, tcBuf);
- // index buffer was set on creation
+ // index buffer and others were set on creation
m.setStatic();
m.updateBound();
diff --git a/engine/src/core/com/jme3/app/Application.java b/engine/src/core/com/jme3/app/Application.java
index 517ec61..5100725 100644
--- a/engine/src/core/com/jme3/app/Application.java
+++ b/engine/src/core/com/jme3/app/Application.java
@@ -290,6 +290,10 @@ public class Application implements SystemListener {
private void initStateManager(){
stateManager = new AppStateManager(this);
+
+ // Always register a ResetStatsState to make sure
+ // that the stats are cleared every frame
+ stateManager.attach(new ResetStatsState());
}
/**
@@ -580,6 +584,17 @@ public class Application implements SystemListener {
}
task.invoke();
} while (((task = taskQueue.poll()) != null));
+
+ /* I think the above is really just doing this:
+ AppTask<?> task;
+ while( (task = taskQueue.poll()) != null ) {
+ if (!task.isCancelled()) {
+ task.invoke();
+ }
+ }
+ //...but it's hard to say for sure. It's so twisted
+ //up that I don't trust my eyes. -pspeed
+ */
if (speed == 0 || paused)
return;
diff --git a/engine/src/core/com/jme3/app/ResetStatsState.java b/engine/src/core/com/jme3/app/ResetStatsState.java
new file mode 100644
index 0000000..03f3013
--- /dev/null
+++ b/engine/src/core/com/jme3/app/ResetStatsState.java
@@ -0,0 +1,60 @@
+/*
+ * 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.app;
+
+import com.jme3.app.state.AbstractAppState;
+import com.jme3.renderer.RenderManager;
+
+
+/**
+ * Resets (clearFrame()) the render's stats object every frame
+ * during AppState.render(). This state is registered once
+ * with Application to ensure that the stats are cleared once
+ * a frame. Using this makes sure that any Appliction based
+ * application that properly runs its state manager will have
+ * stats reset no matter how many views it has or if it even
+ * has views.
+ *
+ * @author Paul Speed
+ */
+public class ResetStatsState extends AbstractAppState {
+
+ public ResetStatsState() {
+ }
+
+ @Override
+ public void render(RenderManager rm) {
+ super.render(rm);
+ rm.getRenderer().getStatistics().clearFrame();
+ }
+
+}
diff --git a/engine/src/core/com/jme3/app/SimpleApplication.java b/engine/src/core/com/jme3/app/SimpleApplication.java
index c79ce83..aa8e749 100644
--- a/engine/src/core/com/jme3/app/SimpleApplication.java
+++ b/engine/src/core/com/jme3/app/SimpleApplication.java
@@ -241,13 +241,6 @@ public abstract class SimpleApplication extends Application {
rootNode.updateGeometricState();
guiNode.updateGeometricState();
- // Moving this here to make sure it is always done.
- // Now the sets are cleared every frame (guaranteed)
- // and more than one viewer can access the data. This
- // used to be cleared by StatsView but then only StatsView
- // could get accurate counts.
- renderer.getStatistics().clearFrame();
-
// render states
stateManager.render(renderManager);
renderManager.render(tpf, context.isRenderable());
diff --git a/engine/src/core/com/jme3/app/StatsView.java b/engine/src/core/com/jme3/app/StatsView.java
index 49eeb13..f2b2ba5 100644
--- a/engine/src/core/com/jme3/app/StatsView.java
+++ b/engine/src/core/com/jme3/app/StatsView.java
@@ -105,7 +105,7 @@ public class StatsView extends Node implements Control {
labels[i].setText(stringBuilder);
}
- // Moved to SimpleApplication to make sure it is
+ // Moved to ResetStatsState to make sure it is
// done even if there is no StatsView or the StatsView
// is disable.
//statistics.clearFrame();
diff --git a/engine/src/core/com/jme3/app/state/AppStateManager.java b/engine/src/core/com/jme3/app/state/AppStateManager.java
index 81228af..92a00f5 100644
--- a/engine/src/core/com/jme3/app/state/AppStateManager.java
+++ b/engine/src/core/com/jme3/app/state/AppStateManager.java
@@ -202,6 +202,9 @@ public class AppStateManager {
protected void initializePending(){
AppState[] array = getInitializing();
+ if (array.length == 0)
+ return;
+
synchronized( states ) {
// Move the states that will be initialized
// into the active array. In all but one case the
@@ -219,6 +222,9 @@ public class AppStateManager {
protected void terminatePending(){
AppState[] array = getTerminating();
+ if (array.length == 0)
+ return;
+
for (AppState state : array) {
state.cleanup();
}
diff --git a/engine/src/core/com/jme3/input/InputManager.java b/engine/src/core/com/jme3/input/InputManager.java
index 23f2988..a0c8788 100644
--- a/engine/src/core/com/jme3/input/InputManager.java
+++ b/engine/src/core/com/jme3/input/InputManager.java
@@ -1,881 +1,892 @@
-/*
- * 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.input;
-
-import com.jme3.app.Application;
-import com.jme3.input.controls.*;
-import com.jme3.input.event.*;
-import com.jme3.math.FastMath;
-import com.jme3.math.Vector2f;
-import com.jme3.util.IntMap;
-import com.jme3.util.IntMap.Entry;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * The <code>InputManager</code> is responsible for converting input events
- * received from the Key, Mouse and Joy Input implementations into an
- * abstract, input device independent representation that user code can use.
- * <p>
- * By default an <code>InputManager</code> is included with every Application instance for use
- * in user code to query input, unless the Application is created as headless
- * or with input explicitly disabled.
- * <p>
- * The input manager has two concepts, a {@link Trigger} and a mapping.
- * A trigger represents a specific input trigger, such as a key button,
- * or a mouse axis. A mapping represents a link onto one or several triggers,
- * when the appropriate trigger is activated (e.g. a key is pressed), the
- * mapping will be invoked. Any listeners registered to receive an event
- * from the mapping will have an event raised.
- * <p>
- * There are two types of events that {@link InputListener input listeners}
- * can receive, one is {@link ActionListener#onAction(java.lang.String, boolean, float) action}
- * events and another is {@link AnalogListener#onAnalog(java.lang.String, float, float) analog}
- * events.
- * <p>
- * <code>onAction</code> events are raised when the specific input
- * activates or deactivates. For a digital input such as key press, the <code>onAction()</code>
- * event will be raised with the <code>isPressed</code> argument equal to true,
- * when the key is released, <code>onAction</code> is called again but this time
- * with the <code>isPressed</code> argument set to false.
- * For analog inputs, the <code>onAction</code> method will be called any time
- * the input is non-zero, however an exception to this is for joystick axis inputs,
- * which are only called when the input is above the {@link InputManager#setAxisDeadZone(float) dead zone}.
- * <p>
- * <code>onAnalog</code> events are raised every frame while the input is activated.
- * For digital inputs, every frame that the input is active will cause the
- * <code>onAnalog</code> method to be called, the argument <code>value</code>
- * argument will equal to the frame's time per frame (TPF) value but only
- * for digital inputs. For analog inputs however, the <code>value</code> argument
- * will equal the actual analog value.
- */
-public class InputManager implements RawInputListener {
-
- private static final Logger logger = Logger.getLogger(InputManager.class.getName());
- private final KeyInput keys;
- private final MouseInput mouse;
- private final JoyInput joystick;
- private final TouchInput touch;
- private float frameTPF;
- private long lastLastUpdateTime = 0;
- private long lastUpdateTime = 0;
- private long frameDelta = 0;
- private long firstTime = 0;
- private boolean eventsPermitted = false;
- private boolean mouseVisible = true;
- private boolean safeMode = false;
- private float axisDeadZone = 0.05f;
- private Vector2f cursorPos = new Vector2f();
- private Joystick[] joysticks;
- private final IntMap<ArrayList<Mapping>> bindings = new IntMap<ArrayList<Mapping>>();
- private final HashMap<String, Mapping> mappings = new HashMap<String, Mapping>();
- private final IntMap<Long> pressedButtons = new IntMap<Long>();
- private final IntMap<Float> axisValues = new IntMap<Float>();
- private ArrayList<RawInputListener> rawListeners = new ArrayList<RawInputListener>();
- private RawInputListener[] rawListenerArray = null;
- private ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
-
- private static class Mapping {
-
- private final String name;
- private final ArrayList<Integer> triggers = new ArrayList<Integer>();
- private final ArrayList<InputListener> listeners = new ArrayList<InputListener>();
-
- public Mapping(String name) {
- this.name = name;
- }
- }
-
- /**
- * Initializes the InputManager.
- *
- * <p>This should only be called internally in {@link Application}.
- *
- * @param mouse
- * @param keys
- * @param joystick
- * @param touch
- * @throws IllegalArgumentException If either mouseInput or keyInput are null.
- */
- public InputManager(MouseInput mouse, KeyInput keys, JoyInput joystick, TouchInput touch) {
- if (keys == null || mouse == null) {
- throw new NullPointerException("Mouse or keyboard cannot be null");
- }
-
- this.keys = keys;
- this.mouse = mouse;
- this.joystick = joystick;
- this.touch = touch;
-
- keys.setInputListener(this);
- mouse.setInputListener(this);
- if (joystick != null) {
- joystick.setInputListener(this);
- joysticks = joystick.loadJoysticks(this);
- }
- if (touch != null) {
- touch.setInputListener(this);
- }
-
- firstTime = keys.getInputTimeNanos();
- }
-
- private void invokeActions(int hash, boolean pressed) {
- ArrayList<Mapping> maps = bindings.get(hash);
- if (maps == null) {
- return;
- }
-
- int size = maps.size();
- for (int i = size - 1; i >= 0; i--) {
- Mapping mapping = maps.get(i);
- ArrayList<InputListener> listeners = mapping.listeners;
- int listenerSize = listeners.size();
- for (int j = listenerSize - 1; j >= 0; j--) {
- InputListener listener = listeners.get(j);
- if (listener instanceof ActionListener) {
- ((ActionListener) listener).onAction(mapping.name, pressed, frameTPF);
- }
- }
- }
- }
-
- private float computeAnalogValue(long timeDelta) {
- if (safeMode || frameDelta == 0) {
- return 1f;
- } else {
- return FastMath.clamp((float) timeDelta / (float) frameDelta, 0, 1);
- }
- }
-
- private void invokeTimedActions(int hash, long time, boolean pressed) {
- if (!bindings.containsKey(hash)) {
- return;
- }
-
- if (pressed) {
- pressedButtons.put(hash, time);
- } else {
- Long pressTimeObj = pressedButtons.remove(hash);
- if (pressTimeObj == null) {
- return; // under certain circumstances it can be null, ignore
- } // the event then.
-
- long pressTime = pressTimeObj;
- long lastUpdate = lastLastUpdateTime;
- long releaseTime = time;
- long timeDelta = releaseTime - Math.max(pressTime, lastUpdate);
-
- if (timeDelta > 0) {
- invokeAnalogs(hash, computeAnalogValue(timeDelta), false);
- }
- }
- }
-
- private void invokeUpdateActions() {
- for (Entry<Long> pressedButton : pressedButtons) {
- int hash = pressedButton.getKey();
-
- long pressTime = pressedButton.getValue();
- long timeDelta = lastUpdateTime - Math.max(lastLastUpdateTime, pressTime);
-
- if (timeDelta > 0) {
- invokeAnalogs(hash, computeAnalogValue(timeDelta), false);
- }
- }
-
- for (Entry<Float> axisValue : axisValues) {
- int hash = axisValue.getKey();
- float value = axisValue.getValue();
- invokeAnalogs(hash, value * frameTPF, true);
- }
- }
-
- private void invokeAnalogs(int hash, float value, boolean isAxis) {
- ArrayList<Mapping> maps = bindings.get(hash);
- if (maps == null) {
- return;
- }
-
- if (!isAxis) {
- value *= frameTPF;
- }
-
- int size = maps.size();
- for (int i = size - 1; i >= 0; i--) {
- Mapping mapping = maps.get(i);
- ArrayList<InputListener> listeners = mapping.listeners;
- int listenerSize = listeners.size();
- for (int j = listenerSize - 1; j >= 0; j--) {
- InputListener listener = listeners.get(j);
- if (listener instanceof AnalogListener) {
- // NOTE: multiply by TPF for any button bindings
- ((AnalogListener) listener).onAnalog(mapping.name, value, frameTPF);
- }
- }
- }
- }
-
- private void invokeAnalogsAndActions(int hash, float value, boolean applyTpf) {
- if (value < axisDeadZone) {
- invokeAnalogs(hash, value, !applyTpf);
- return;
- }
-
- ArrayList<Mapping> maps = bindings.get(hash);
- if (maps == null) {
- return;
- }
-
- boolean valueChanged = !axisValues.containsKey(hash);
- if (applyTpf) {
- value *= frameTPF;
- }
-
- int size = maps.size();
- for (int i = size - 1; i >= 0; i--) {
- Mapping mapping = maps.get(i);
- ArrayList<InputListener> listeners = mapping.listeners;
- int listenerSize = listeners.size();
- for (int j = listenerSize - 1; j >= 0; j--) {
- InputListener listener = listeners.get(j);
-
- if (listener instanceof ActionListener && valueChanged) {
- ((ActionListener) listener).onAction(mapping.name, true, frameTPF);
- }
-
- if (listener instanceof AnalogListener) {
- ((AnalogListener) listener).onAnalog(mapping.name, value, frameTPF);
- }
-
- }
- }
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void beginInput() {
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void endInput() {
- }
-
- private void onJoyAxisEventQueued(JoyAxisEvent evt) {
-// for (int i = 0; i < rawListeners.size(); i++){
-// rawListeners.get(i).onJoyAxisEvent(evt);
-// }
-
- int joyId = evt.getJoyIndex();
- int axis = evt.getAxisIndex();
- float value = evt.getValue();
- if (value < axisDeadZone && value > -axisDeadZone) {
- int hash1 = JoyAxisTrigger.joyAxisHash(joyId, axis, true);
- int hash2 = JoyAxisTrigger.joyAxisHash(joyId, axis, false);
-
- Float val1 = axisValues.get(hash1);
- Float val2 = axisValues.get(hash2);
-
- if (val1 != null && val1.floatValue() > axisDeadZone) {
- invokeActions(hash1, false);
- }
- if (val2 != null && val2.floatValue() > axisDeadZone) {
- invokeActions(hash2, false);
- }
-
- axisValues.remove(hash1);
- axisValues.remove(hash2);
-
- } else if (value < 0) {
- int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, true);
- int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, false);
- invokeAnalogsAndActions(hash, -value, true);
- axisValues.put(hash, -value);
- axisValues.remove(otherHash);
- } else {
- int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, false);
- int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, true);
- invokeAnalogsAndActions(hash, value, true);
- axisValues.put(hash, value);
- axisValues.remove(otherHash);
- }
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void onJoyAxisEvent(JoyAxisEvent evt) {
- if (!eventsPermitted) {
- throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time.");
- }
-
- inputQueue.add(evt);
- }
-
- private void onJoyButtonEventQueued(JoyButtonEvent evt) {
-// for (int i = 0; i < rawListeners.size(); i++){
-// rawListeners.get(i).onJoyButtonEvent(evt);
-// }
-
- int hash = JoyButtonTrigger.joyButtonHash(evt.getJoyIndex(), evt.getButtonIndex());
- invokeActions(hash, evt.isPressed());
- invokeTimedActions(hash, evt.getTime(), evt.isPressed());
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void onJoyButtonEvent(JoyButtonEvent evt) {
- if (!eventsPermitted) {
- throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time.");
- }
-
- inputQueue.add(evt);
- }
-
- private void onMouseMotionEventQueued(MouseMotionEvent evt) {
-// for (int i = 0; i < rawListeners.size(); i++){
-// rawListeners.get(i).onMouseMotionEvent(evt);
-// }
-
- if (evt.getDX() != 0) {
- float val = Math.abs(evt.getDX()) / 1024f;
- invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_X, evt.getDX() < 0), val, false);
- }
- if (evt.getDY() != 0) {
- float val = Math.abs(evt.getDY()) / 1024f;
- invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_Y, evt.getDY() < 0), val, false);
- }
- if (evt.getDeltaWheel() != 0) {
- float val = Math.abs(evt.getDeltaWheel()) / 100f;
- invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_WHEEL, evt.getDeltaWheel() < 0), val, false);
- }
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void onMouseMotionEvent(MouseMotionEvent evt) {
- if (!eventsPermitted) {
- throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time.");
- }
-
- cursorPos.set(evt.getX(), evt.getY());
- inputQueue.add(evt);
- }
-
- private void onMouseButtonEventQueued(MouseButtonEvent evt) {
- int hash = MouseButtonTrigger.mouseButtonHash(evt.getButtonIndex());
- invokeActions(hash, evt.isPressed());
- invokeTimedActions(hash, evt.getTime(), evt.isPressed());
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void onMouseButtonEvent(MouseButtonEvent evt) {
- if (!eventsPermitted) {
- throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time.");
- }
- //updating cursor pos on click, so that non android touch events can properly update cursor position.
- cursorPos.set(evt.getX(), evt.getY());
- inputQueue.add(evt);
- }
-
- private void onKeyEventQueued(KeyInputEvent evt) {
- if (evt.isRepeating()) {
- return; // repeat events not used for bindings
- }
-
- int hash = KeyTrigger.keyHash(evt.getKeyCode());
- invokeActions(hash, evt.isPressed());
- invokeTimedActions(hash, evt.getTime(), evt.isPressed());
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- public void onKeyEvent(KeyInputEvent evt) {
- if (!eventsPermitted) {
- throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time.");
- }
-
- inputQueue.add(evt);
- }
-
- /**
- * Set the deadzone for joystick axes.
- *
- * <p>{@link ActionListener#onAction(java.lang.String, boolean, float) }
- * events will only be raised if the joystick axis value is greater than
- * the <code>deadZone</code>.
- *
- * @param deadZone the deadzone for joystick axes.
- */
- public void setAxisDeadZone(float deadZone) {
- this.axisDeadZone = deadZone;
- }
-
- /**
- * Returns the deadzone for joystick axes.
- *
- * @return the deadzone for joystick axes.
- */
- public float getAxisDeadZone() {
- return axisDeadZone;
- }
-
- /**
- * Adds a new listener to receive events on the given mappings.
- *
- * <p>The given InputListener will be registered to receive events
- * on the specified mapping names. When a mapping raises an event, the
- * listener will have its appropriate method invoked, either
- * {@link ActionListener#onAction(java.lang.String, boolean, float) }
- * or {@link AnalogListener#onAnalog(java.lang.String, float, float) }
- * depending on which interface the <code>listener</code> implements.
- * If the listener implements both interfaces, then it will receive the
- * appropriate event for each method.
- *
- * @param listener The listener to register to receive input events.
- * @param mappingNames The mapping names which the listener will receive
- * events from.
- *
- * @see InputManager#removeListener(com.jme3.input.controls.InputListener)
- */
- public void addListener(InputListener listener, String... mappingNames) {
- for (String mappingName : mappingNames) {
- Mapping mapping = mappings.get(mappingName);
- if (mapping == null) {
- mapping = new Mapping(mappingName);
- mappings.put(mappingName, mapping);
- }
- if (!mapping.listeners.contains(listener)) {
- mapping.listeners.add(listener);
- }
- }
- }
-
- /**
- * Removes a listener from receiving events.
- *
- * <p>This will unregister the listener from any mappings that it
- * was previously registered with via
- * {@link InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) }.
- *
- * @param listener The listener to unregister.
- *
- * @see InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[])
- */
- public void removeListener(InputListener listener) {
- for (Mapping mapping : mappings.values()) {
- mapping.listeners.remove(listener);
- }
- }
-
- /**
- * Create a new mapping to the given triggers.
- *
- * <p>
- * The given mapping will be assigned to the given triggers, when
- * any of the triggers given raise an event, the listeners
- * registered to the mappings will receive appropriate events.
- *
- * @param mappingName The mapping name to assign.
- * @param triggers The triggers to which the mapping is to be registered.
- *
- * @see InputManager#deleteMapping(java.lang.String)
- */
- public void addMapping(String mappingName, Trigger... triggers) {
- Mapping mapping = mappings.get(mappingName);
- if (mapping == null) {
- mapping = new Mapping(mappingName);
- mappings.put(mappingName, mapping);
- }
-
- for (Trigger trigger : triggers) {
- int hash = trigger.triggerHashCode();
- ArrayList<Mapping> names = bindings.get(hash);
- if (names == null) {
- names = new ArrayList<Mapping>();
- bindings.put(hash, names);
- }
- if (!names.contains(mapping)) {
- names.add(mapping);
- mapping.triggers.add(hash);
- } else {
- logger.log(Level.WARNING, "Attempted to add mapping \"{0}\" twice to trigger.", mappingName);
- }
- }
- }
-
- /**
- * Returns true if this InputManager has a mapping registered
- * for the given mappingName.
- *
- * @param mappingName The mapping name to check.
- *
- * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[])
- * @see InputManager#deleteMapping(java.lang.String)
- */
- public boolean hasMapping(String mappingName) {
- return mappings.containsKey(mappingName);
- }
-
- /**
- * Deletes a mapping from receiving trigger events.
- *
- * <p>
- * The given mapping will no longer be assigned to receive trigger
- * events.
- *
- * @param mappingName The mapping name to unregister.
- *
- * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[])
- */
- public void deleteMapping(String mappingName) {
- Mapping mapping = mappings.remove(mappingName);
- if (mapping == null) {
- throw new IllegalArgumentException("Cannot find mapping: " + mappingName);
- }
-
- ArrayList<Integer> triggers = mapping.triggers;
- for (int i = triggers.size() - 1; i >= 0; i--) {
- int hash = triggers.get(i);
- ArrayList<Mapping> maps = bindings.get(hash);
- maps.remove(mapping);
- }
- }
-
- /**
- * Deletes a specific trigger registered to a mapping.
- *
- * <p>
- * The given mapping will no longer receive events raised by the
- * trigger.
- *
- * @param mappingName The mapping name to cease receiving events from the
- * trigger.
- * @param trigger The trigger to no longer invoke events on the mapping.
- */
- public void deleteTrigger(String mappingName, Trigger trigger) {
- Mapping mapping = mappings.get(mappingName);
- if (mapping == null) {
- throw new IllegalArgumentException("Cannot find mapping: " + mappingName);
- }
-
- ArrayList<Mapping> maps = bindings.get(trigger.triggerHashCode());
- maps.remove(mapping);
-
- }
-
- /**
- * Clears all the input mappings from this InputManager.
- * Consequently, also clears all of the
- * InputListeners as well.
- */
- public void clearMappings() {
- mappings.clear();
- bindings.clear();
- reset();
- }
-
- /**
- * Do not use.
- * Called to reset pressed keys or buttons when focus is restored.
- */
- public void reset() {
- pressedButtons.clear();
- axisValues.clear();
- }
-
- /**
- * Returns whether the mouse cursor is visible or not.
- *
- * <p>By default the cursor is visible.
- *
- * @return whether the mouse cursor is visible or not.
- *
- * @see InputManager#setCursorVisible(boolean)
- */
- public boolean isCursorVisible() {
- return mouseVisible;
- }
-
- /**
- * Set whether the mouse cursor should be visible or not.
- *
- * @param visible whether the mouse cursor should be visible or not.
- */
- public void setCursorVisible(boolean visible) {
- if (mouseVisible != visible) {
- mouseVisible = visible;
- mouse.setCursorVisible(mouseVisible);
- }
- }
-
- /**
- * Returns the current cursor position. The position is relative to the
- * bottom-left of the screen and is in pixels.
- *
- * @return the current cursor position
- */
- public Vector2f getCursorPosition() {
- return cursorPos;
- }
-
- /**
- * Returns an array of all joysticks installed on the system.
- *
- * @return an array of all joysticks installed on the system.
- */
- public Joystick[] getJoysticks() {
- return joysticks;
- }
-
- /**
- * Adds a {@link RawInputListener} to receive raw input events.
- *
- * <p>
- * Any raw input listeners registered to this <code>InputManager</code>
- * will receive raw input events first, before they get handled
- * by the <code>InputManager</code> itself. The listeners are
- * each processed in the order they were added, e.g. FIFO.
- * <p>
- * If a raw input listener has handled the event and does not wish
- * other listeners down the list to process the event, it may set the
- * {@link InputEvent#setConsumed() consumed flag} to indicate the
- * event was consumed and shouldn't be processed any further.
- * The listener may do this either at each of the event callbacks
- * or at the {@link RawInputListener#endInput() } method.
- *
- * @param listener A listener to receive raw input events.
- *
- * @see RawInputListener
- */
- public void addRawInputListener(RawInputListener listener) {
- rawListeners.add(listener);
- rawListenerArray = null;
- }
-
- /**
- * Removes a {@link RawInputListener} so that it no longer
- * receives raw input events.
- *
- * @param listener The listener to cease receiving raw input events.
- *
- * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener)
- */
- public void removeRawInputListener(RawInputListener listener) {
- rawListeners.remove(listener);
- rawListenerArray = null;
- }
-
- /**
- * Clears all {@link RawInputListener}s.
- *
- * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener)
- */
- public void clearRawInputListeners() {
- rawListeners.clear();
- rawListenerArray = null;
- }
-
- private RawInputListener[] getRawListenerArray() {
- if (rawListenerArray == null)
- rawListenerArray = rawListeners.toArray(new RawInputListener[rawListeners.size()]);
- return rawListenerArray;
- }
-
- /**
- * Enable simulation of mouse events. Used for touchscreen input only.
- *
- * @param value True to enable simulation of mouse events
- */
- public void setSimulateMouse(boolean value) {
- if (touch != null) {
- touch.setSimulateMouse(value);
- }
- }
-
- /**
- * Enable simulation of keyboard events. Used for touchscreen input only.
- *
- * @param value True to enable simulation of keyboard events
- */
- public void setSimulateKeyboard(boolean value) {
- if (touch != null) {
- touch.setSimulateKeyboard(value);
- }
- }
-
- private void processQueue() {
- int queueSize = inputQueue.size();
- RawInputListener[] array = getRawListenerArray();
-
- for (RawInputListener listener : array) {
- listener.beginInput();
-
- for (int j = 0; j < queueSize; j++) {
- InputEvent event = inputQueue.get(j);
- if (event.isConsumed()) {
- continue;
- }
-
- if (event instanceof MouseMotionEvent) {
- listener.onMouseMotionEvent((MouseMotionEvent) event);
- } else if (event instanceof KeyInputEvent) {
- listener.onKeyEvent((KeyInputEvent) event);
- } else if (event instanceof MouseButtonEvent) {
- listener.onMouseButtonEvent((MouseButtonEvent) event);
- } else if (event instanceof JoyAxisEvent) {
- listener.onJoyAxisEvent((JoyAxisEvent) event);
- } else if (event instanceof JoyButtonEvent) {
- listener.onJoyButtonEvent((JoyButtonEvent) event);
- } else if (event instanceof TouchEvent) {
- listener.onTouchEvent((TouchEvent) event);
- } else {
- assert false;
- }
- }
-
- listener.endInput();
- }
-
- for (int i = 0; i < queueSize; i++) {
- InputEvent event = inputQueue.get(i);
- if (event.isConsumed()) {
- continue;
- }
-
- if (event instanceof MouseMotionEvent) {
- onMouseMotionEventQueued((MouseMotionEvent) event);
- } else if (event instanceof KeyInputEvent) {
- onKeyEventQueued((KeyInputEvent) event);
- } else if (event instanceof MouseButtonEvent) {
- onMouseButtonEventQueued((MouseButtonEvent) event);
- } else if (event instanceof JoyAxisEvent) {
- onJoyAxisEventQueued((JoyAxisEvent) event);
- } else if (event instanceof JoyButtonEvent) {
- onJoyButtonEventQueued((JoyButtonEvent) event);
- } else if (event instanceof TouchEvent) {
- onTouchEventQueued((TouchEvent) event);
- } else {
- assert false;
- }
- // larynx, 2011.06.10 - flag event as reusable because
- // the android input uses a non-allocating ringbuffer which
- // needs to know when the event is not anymore in inputQueue
- // and therefor can be reused.
- event.setConsumed();
- }
-
- inputQueue.clear();
- }
-
- /**
- * Updates the <code>InputManager</code>.
- * This will query current input devices and send
- * appropriate events to registered listeners.
- *
- * @param tpf Time per frame value.
- */
- public void update(float tpf) {
- frameTPF = tpf;
-
- // Activate safemode if the TPF value is so small
- // that rounding errors are inevitable
- safeMode = tpf < 0.015f;
-
- long currentTime = keys.getInputTimeNanos();
- frameDelta = currentTime - lastUpdateTime;
-
- eventsPermitted = true;
-
- keys.update();
- mouse.update();
- if (joystick != null) {
- joystick.update();
- }
- if (touch != null) {
- touch.update();
- }
-
- eventsPermitted = false;
-
- processQueue();
- invokeUpdateActions();
-
- lastLastUpdateTime = lastUpdateTime;
- lastUpdateTime = currentTime;
- }
-
- /**
- * Dispatches touch events to touch listeners
- * @param evt The touch event to be dispatched to all onTouch listeners
- */
- public void onTouchEventQueued(TouchEvent evt) {
- ArrayList<Mapping> maps = bindings.get(TouchTrigger.touchHash(evt.getKeyCode()));
- if (maps == null) {
- return;
- }
-
- int size = maps.size();
- for (int i = size - 1; i >= 0; i--) {
- Mapping mapping = maps.get(i);
- ArrayList<InputListener> listeners = mapping.listeners;
- int listenerSize = listeners.size();
- for (int j = listenerSize - 1; j >= 0; j--) {
- InputListener listener = listeners.get(j);
- if (listener instanceof TouchListener) {
- ((TouchListener) listener).onTouch(mapping.name, evt, frameTPF);
- }
- }
- }
- }
-
- /**
- * Callback from RawInputListener. Do not use.
- */
- @Override
- public void onTouchEvent(TouchEvent evt) {
- if (!eventsPermitted) {
- throw new UnsupportedOperationException("TouchInput has raised an event at an illegal time.");
- }
- inputQueue.add(evt);
- }
-}
+/*
+ * 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.input;
+
+import com.jme3.app.Application;
+import com.jme3.input.controls.*;
+import com.jme3.input.event.*;
+import com.jme3.math.FastMath;
+import com.jme3.math.Vector2f;
+import com.jme3.util.IntMap;
+import com.jme3.util.IntMap.Entry;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * The <code>InputManager</code> is responsible for converting input events
+ * received from the Key, Mouse and Joy Input implementations into an
+ * abstract, input device independent representation that user code can use.
+ * <p>
+ * By default an <code>InputManager</code> is included with every Application instance for use
+ * in user code to query input, unless the Application is created as headless
+ * or with input explicitly disabled.
+ * <p>
+ * The input manager has two concepts, a {@link Trigger} and a mapping.
+ * A trigger represents a specific input trigger, such as a key button,
+ * or a mouse axis. A mapping represents a link onto one or several triggers,
+ * when the appropriate trigger is activated (e.g. a key is pressed), the
+ * mapping will be invoked. Any listeners registered to receive an event
+ * from the mapping will have an event raised.
+ * <p>
+ * There are two types of events that {@link InputListener input listeners}
+ * can receive, one is {@link ActionListener#onAction(java.lang.String, boolean, float) action}
+ * events and another is {@link AnalogListener#onAnalog(java.lang.String, float, float) analog}
+ * events.
+ * <p>
+ * <code>onAction</code> events are raised when the specific input
+ * activates or deactivates. For a digital input such as key press, the <code>onAction()</code>
+ * event will be raised with the <code>isPressed</code> argument equal to true,
+ * when the key is released, <code>onAction</code> is called again but this time
+ * with the <code>isPressed</code> argument set to false.
+ * For analog inputs, the <code>onAction</code> method will be called any time
+ * the input is non-zero, however an exception to this is for joystick axis inputs,
+ * which are only called when the input is above the {@link InputManager#setAxisDeadZone(float) dead zone}.
+ * <p>
+ * <code>onAnalog</code> events are raised every frame while the input is activated.
+ * For digital inputs, every frame that the input is active will cause the
+ * <code>onAnalog</code> method to be called, the argument <code>value</code>
+ * argument will equal to the frame's time per frame (TPF) value but only
+ * for digital inputs. For analog inputs however, the <code>value</code> argument
+ * will equal the actual analog value.
+ */
+public class InputManager implements RawInputListener {
+
+ private static final Logger logger = Logger.getLogger(InputManager.class.getName());
+ private final KeyInput keys;
+ private final MouseInput mouse;
+ private final JoyInput joystick;
+ private final TouchInput touch;
+ private float frameTPF;
+ private long lastLastUpdateTime = 0;
+ private long lastUpdateTime = 0;
+ private long frameDelta = 0;
+ private long firstTime = 0;
+ private boolean eventsPermitted = false;
+ private boolean mouseVisible = true;
+ private boolean safeMode = false;
+ private float axisDeadZone = 0.05f;
+ private Vector2f cursorPos = new Vector2f();
+ private Joystick[] joysticks;
+ private final IntMap<ArrayList<Mapping>> bindings = new IntMap<ArrayList<Mapping>>();
+ private final HashMap<String, Mapping> mappings = new HashMap<String, Mapping>();
+ private final IntMap<Long> pressedButtons = new IntMap<Long>();
+ private final IntMap<Float> axisValues = new IntMap<Float>();
+ private ArrayList<RawInputListener> rawListeners = new ArrayList<RawInputListener>();
+ private RawInputListener[] rawListenerArray = null;
+ private ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
+
+ private static class Mapping {
+
+ private final String name;
+ private final ArrayList<Integer> triggers = new ArrayList<Integer>();
+ private final ArrayList<InputListener> listeners = new ArrayList<InputListener>();
+
+ public Mapping(String name) {
+ this.name = name;
+ }
+ }
+
+ /**
+ * Initializes the InputManager.
+ *
+ * <p>This should only be called internally in {@link Application}.
+ *
+ * @param mouse
+ * @param keys
+ * @param joystick
+ * @param touch
+ * @throws IllegalArgumentException If either mouseInput or keyInput are null.
+ */
+ public InputManager(MouseInput mouse, KeyInput keys, JoyInput joystick, TouchInput touch) {
+ if (keys == null || mouse == null) {
+ throw new NullPointerException("Mouse or keyboard cannot be null");
+ }
+
+ this.keys = keys;
+ this.mouse = mouse;
+ this.joystick = joystick;
+ this.touch = touch;
+
+ keys.setInputListener(this);
+ mouse.setInputListener(this);
+ if (joystick != null) {
+ joystick.setInputListener(this);
+ joysticks = joystick.loadJoysticks(this);
+ }
+ if (touch != null) {
+ touch.setInputListener(this);
+ }
+
+ firstTime = keys.getInputTimeNanos();
+ }
+
+ private void invokeActions(int hash, boolean pressed) {
+ ArrayList<Mapping> maps = bindings.get(hash);
+ if (maps == null) {
+ return;
+ }
+
+ int size = maps.size();
+ for (int i = size - 1; i >= 0; i--) {
+ Mapping mapping = maps.get(i);
+ ArrayList<InputListener> listeners = mapping.listeners;
+ int listenerSize = listeners.size();
+ for (int j = listenerSize - 1; j >= 0; j--) {
+ InputListener listener = listeners.get(j);
+ if (listener instanceof ActionListener) {
+ ((ActionListener) listener).onAction(mapping.name, pressed, frameTPF);
+ }
+ }
+ }
+ }
+
+ private float computeAnalogValue(long timeDelta) {
+ if (safeMode || frameDelta == 0) {
+ return 1f;
+ } else {
+ return FastMath.clamp((float) timeDelta / (float) frameDelta, 0, 1);
+ }
+ }
+
+ private void invokeTimedActions(int hash, long time, boolean pressed) {
+ if (!bindings.containsKey(hash)) {
+ return;
+ }
+
+ if (pressed) {
+ pressedButtons.put(hash, time);
+ } else {
+ Long pressTimeObj = pressedButtons.remove(hash);
+ if (pressTimeObj == null) {
+ return; // under certain circumstances it can be null, ignore
+ } // the event then.
+
+ long pressTime = pressTimeObj;
+ long lastUpdate = lastLastUpdateTime;
+ long releaseTime = time;
+ long timeDelta = releaseTime - Math.max(pressTime, lastUpdate);
+
+ if (timeDelta > 0) {
+ invokeAnalogs(hash, computeAnalogValue(timeDelta), false);
+ }
+ }
+ }
+
+ private void invokeUpdateActions() {
+ if (pressedButtons.size() > 0) for (Entry<Long> pressedButton : pressedButtons) {
+ int hash = pressedButton.getKey();
+
+ long pressTime = pressedButton.getValue();
+ long timeDelta = lastUpdateTime - Math.max(lastLastUpdateTime, pressTime);
+
+ if (timeDelta > 0) {
+ invokeAnalogs(hash, computeAnalogValue(timeDelta), false);
+ }
+ }
+
+ if (axisValues.size() > 0) for (Entry<Float> axisValue : axisValues) {
+ int hash = axisValue.getKey();
+ float value = axisValue.getValue();
+ invokeAnalogs(hash, value * frameTPF, true);
+ }
+ }
+
+ private void invokeAnalogs(int hash, float value, boolean isAxis) {
+ ArrayList<Mapping> maps = bindings.get(hash);
+ if (maps == null) {
+ return;
+ }
+
+ if (!isAxis) {
+ value *= frameTPF;
+ }
+
+ int size = maps.size();
+ for (int i = size - 1; i >= 0; i--) {
+ Mapping mapping = maps.get(i);
+ ArrayList<InputListener> listeners = mapping.listeners;
+ int listenerSize = listeners.size();
+ for (int j = listenerSize - 1; j >= 0; j--) {
+ InputListener listener = listeners.get(j);
+ if (listener instanceof AnalogListener) {
+ // NOTE: multiply by TPF for any button bindings
+ ((AnalogListener) listener).onAnalog(mapping.name, value, frameTPF);
+ }
+ }
+ }
+ }
+
+ private void invokeAnalogsAndActions(int hash, float value, boolean applyTpf) {
+ if (value < axisDeadZone) {
+ invokeAnalogs(hash, value, !applyTpf);
+ return;
+ }
+
+ ArrayList<Mapping> maps = bindings.get(hash);
+ if (maps == null) {
+ return;
+ }
+
+ boolean valueChanged = !axisValues.containsKey(hash);
+ if (applyTpf) {
+ value *= frameTPF;
+ }
+
+ int size = maps.size();
+ for (int i = size - 1; i >= 0; i--) {
+ Mapping mapping = maps.get(i);
+ ArrayList<InputListener> listeners = mapping.listeners;
+ int listenerSize = listeners.size();
+ for (int j = listenerSize - 1; j >= 0; j--) {
+ InputListener listener = listeners.get(j);
+
+ if (listener instanceof ActionListener && valueChanged) {
+ ((ActionListener) listener).onAction(mapping.name, true, frameTPF);
+ }
+
+ if (listener instanceof AnalogListener) {
+ ((AnalogListener) listener).onAnalog(mapping.name, value, frameTPF);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void beginInput() {
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void endInput() {
+ }
+
+ private void onJoyAxisEventQueued(JoyAxisEvent evt) {
+// for (int i = 0; i < rawListeners.size(); i++){
+// rawListeners.get(i).onJoyAxisEvent(evt);
+// }
+
+ int joyId = evt.getJoyIndex();
+ int axis = evt.getAxisIndex();
+ float value = evt.getValue();
+ if (value < axisDeadZone && value > -axisDeadZone) {
+ int hash1 = JoyAxisTrigger.joyAxisHash(joyId, axis, true);
+ int hash2 = JoyAxisTrigger.joyAxisHash(joyId, axis, false);
+
+ Float val1 = axisValues.get(hash1);
+ Float val2 = axisValues.get(hash2);
+
+ if (val1 != null && val1.floatValue() > axisDeadZone) {
+ invokeActions(hash1, false);
+ }
+ if (val2 != null && val2.floatValue() > axisDeadZone) {
+ invokeActions(hash2, false);
+ }
+
+ axisValues.remove(hash1);
+ axisValues.remove(hash2);
+
+ } else if (value < 0) {
+ int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, true);
+ int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, false);
+ invokeAnalogsAndActions(hash, -value, true);
+ axisValues.put(hash, -value);
+ axisValues.remove(otherHash);
+ } else {
+ int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, false);
+ int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, true);
+ invokeAnalogsAndActions(hash, value, true);
+ axisValues.put(hash, value);
+ axisValues.remove(otherHash);
+ }
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void onJoyAxisEvent(JoyAxisEvent evt) {
+ if (!eventsPermitted) {
+ throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time.");
+ }
+
+ inputQueue.add(evt);
+ }
+
+ private void onJoyButtonEventQueued(JoyButtonEvent evt) {
+// for (int i = 0; i < rawListeners.size(); i++){
+// rawListeners.get(i).onJoyButtonEvent(evt);
+// }
+
+ int hash = JoyButtonTrigger.joyButtonHash(evt.getJoyIndex(), evt.getButtonIndex());
+ invokeActions(hash, evt.isPressed());
+ invokeTimedActions(hash, evt.getTime(), evt.isPressed());
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void onJoyButtonEvent(JoyButtonEvent evt) {
+ if (!eventsPermitted) {
+ throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time.");
+ }
+
+ inputQueue.add(evt);
+ }
+
+ private void onMouseMotionEventQueued(MouseMotionEvent evt) {
+// for (int i = 0; i < rawListeners.size(); i++){
+// rawListeners.get(i).onMouseMotionEvent(evt);
+// }
+
+ if (evt.getDX() != 0) {
+ float val = Math.abs(evt.getDX()) / 1024f;
+ invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_X, evt.getDX() < 0), val, false);
+ }
+ if (evt.getDY() != 0) {
+ float val = Math.abs(evt.getDY()) / 1024f;
+ invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_Y, evt.getDY() < 0), val, false);
+ }
+ if (evt.getDeltaWheel() != 0) {
+ float val = Math.abs(evt.getDeltaWheel()) / 100f;
+ invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_WHEEL, evt.getDeltaWheel() < 0), val, false);
+ }
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void onMouseMotionEvent(MouseMotionEvent evt) {
+ if (!eventsPermitted) {
+ throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time.");
+ }
+
+ cursorPos.set(evt.getX(), evt.getY());
+ inputQueue.add(evt);
+ }
+
+ private void onMouseButtonEventQueued(MouseButtonEvent evt) {
+ int hash = MouseButtonTrigger.mouseButtonHash(evt.getButtonIndex());
+ invokeActions(hash, evt.isPressed());
+ invokeTimedActions(hash, evt.getTime(), evt.isPressed());
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void onMouseButtonEvent(MouseButtonEvent evt) {
+ if (!eventsPermitted) {
+ throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time.");
+ }
+ //updating cursor pos on click, so that non android touch events can properly update cursor position.
+ cursorPos.set(evt.getX(), evt.getY());
+ inputQueue.add(evt);
+ }
+
+ private void onKeyEventQueued(KeyInputEvent evt) {
+ if (evt.isRepeating()) {
+ return; // repeat events not used for bindings
+ }
+
+ int hash = KeyTrigger.keyHash(evt.getKeyCode());
+ invokeActions(hash, evt.isPressed());
+ invokeTimedActions(hash, evt.getTime(), evt.isPressed());
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ public void onKeyEvent(KeyInputEvent evt) {
+ if (!eventsPermitted) {
+ throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time.");
+ }
+
+ inputQueue.add(evt);
+ }
+
+ /**
+ * Set the deadzone for joystick axes.
+ *
+ * <p>{@link ActionListener#onAction(java.lang.String, boolean, float) }
+ * events will only be raised if the joystick axis value is greater than
+ * the <code>deadZone</code>.
+ *
+ * @param deadZone the deadzone for joystick axes.
+ */
+ public void setAxisDeadZone(float deadZone) {
+ this.axisDeadZone = deadZone;
+ }
+
+ /**
+ * Returns the deadzone for joystick axes.
+ *
+ * @return the deadzone for joystick axes.
+ */
+ public float getAxisDeadZone() {
+ return axisDeadZone;
+ }
+
+ /**
+ * Adds a new listener to receive events on the given mappings.
+ *
+ * <p>The given InputListener will be registered to receive events
+ * on the specified mapping names. When a mapping raises an event, the
+ * listener will have its appropriate method invoked, either
+ * {@link ActionListener#onAction(java.lang.String, boolean, float) }
+ * or {@link AnalogListener#onAnalog(java.lang.String, float, float) }
+ * depending on which interface the <code>listener</code> implements.
+ * If the listener implements both interfaces, then it will receive the
+ * appropriate event for each method.
+ *
+ * @param listener The listener to register to receive input events.
+ * @param mappingNames The mapping names which the listener will receive
+ * events from.
+ *
+ * @see InputManager#removeListener(com.jme3.input.controls.InputListener)
+ */
+ public void addListener(InputListener listener, String... mappingNames) {
+ for (String mappingName : mappingNames) {
+ Mapping mapping = mappings.get(mappingName);
+ if (mapping == null) {
+ mapping = new Mapping(mappingName);
+ mappings.put(mappingName, mapping);
+ }
+ if (!mapping.listeners.contains(listener)) {
+ mapping.listeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes a listener from receiving events.
+ *
+ * <p>This will unregister the listener from any mappings that it
+ * was previously registered with via
+ * {@link InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) }.
+ *
+ * @param listener The listener to unregister.
+ *
+ * @see InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[])
+ */
+ public void removeListener(InputListener listener) {
+ for (Mapping mapping : mappings.values()) {
+ mapping.listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Create a new mapping to the given triggers.
+ *
+ * <p>
+ * The given mapping will be assigned to the given triggers, when
+ * any of the triggers given raise an event, the listeners
+ * registered to the mappings will receive appropriate events.
+ *
+ * @param mappingName The mapping name to assign.
+ * @param triggers The triggers to which the mapping is to be registered.
+ *
+ * @see InputManager#deleteMapping(java.lang.String)
+ */
+ public void addMapping(String mappingName, Trigger... triggers) {
+ Mapping mapping = mappings.get(mappingName);
+ if (mapping == null) {
+ mapping = new Mapping(mappingName);
+ mappings.put(mappingName, mapping);
+ }
+
+ for (Trigger trigger : triggers) {
+ int hash = trigger.triggerHashCode();
+ ArrayList<Mapping> names = bindings.get(hash);
+ if (names == null) {
+ names = new ArrayList<Mapping>();
+ bindings.put(hash, names);
+ }
+ if (!names.contains(mapping)) {
+ names.add(mapping);
+ mapping.triggers.add(hash);
+ } else {
+ logger.log(Level.WARNING, "Attempted to add mapping \"{0}\" twice to trigger.", mappingName);
+ }
+ }
+ }
+
+ /**
+ * Returns true if this InputManager has a mapping registered
+ * for the given mappingName.
+ *
+ * @param mappingName The mapping name to check.
+ *
+ * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[])
+ * @see InputManager#deleteMapping(java.lang.String)
+ */
+ public boolean hasMapping(String mappingName) {
+ return mappings.containsKey(mappingName);
+ }
+
+ /**
+ * Deletes a mapping from receiving trigger events.
+ *
+ * <p>
+ * The given mapping will no longer be assigned to receive trigger
+ * events.
+ *
+ * @param mappingName The mapping name to unregister.
+ *
+ * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[])
+ */
+ public void deleteMapping(String mappingName) {
+ Mapping mapping = mappings.remove(mappingName);
+ if (mapping == null) {
+ throw new IllegalArgumentException("Cannot find mapping: " + mappingName);
+ }
+
+ ArrayList<Integer> triggers = mapping.triggers;
+ for (int i = triggers.size() - 1; i >= 0; i--) {
+ int hash = triggers.get(i);
+ ArrayList<Mapping> maps = bindings.get(hash);
+ maps.remove(mapping);
+ }
+ }
+
+ /**
+ * Deletes a specific trigger registered to a mapping.
+ *
+ * <p>
+ * The given mapping will no longer receive events raised by the
+ * trigger.
+ *
+ * @param mappingName The mapping name to cease receiving events from the
+ * trigger.
+ * @param trigger The trigger to no longer invoke events on the mapping.
+ */
+ public void deleteTrigger(String mappingName, Trigger trigger) {
+ Mapping mapping = mappings.get(mappingName);
+ if (mapping == null) {
+ throw new IllegalArgumentException("Cannot find mapping: " + mappingName);
+ }
+
+ ArrayList<Mapping> maps = bindings.get(trigger.triggerHashCode());
+ maps.remove(mapping);
+
+ }
+
+ /**
+ * Clears all the input mappings from this InputManager.
+ * Consequently, also clears all of the
+ * InputListeners as well.
+ */
+ public void clearMappings() {
+ mappings.clear();
+ bindings.clear();
+ reset();
+ }
+
+ /**
+ * Do not use.
+ * Called to reset pressed keys or buttons when focus is restored.
+ */
+ public void reset() {
+ pressedButtons.clear();
+ axisValues.clear();
+ }
+
+ /**
+ * Returns whether the mouse cursor is visible or not.
+ *
+ * <p>By default the cursor is visible.
+ *
+ * @return whether the mouse cursor is visible or not.
+ *
+ * @see InputManager#setCursorVisible(boolean)
+ */
+ public boolean isCursorVisible() {
+ return mouseVisible;
+ }
+
+ /**
+ * Set whether the mouse cursor should be visible or not.
+ *
+ * @param visible whether the mouse cursor should be visible or not.
+ */
+ public void setCursorVisible(boolean visible) {
+ if (mouseVisible != visible) {
+ mouseVisible = visible;
+ mouse.setCursorVisible(mouseVisible);
+ }
+ }
+
+ /**
+ * Returns the current cursor position. The position is relative to the
+ * bottom-left of the screen and is in pixels.
+ *
+ * @return the current cursor position
+ */
+ public Vector2f getCursorPosition() {
+ return cursorPos;
+ }
+
+ /**
+ * Returns an array of all joysticks installed on the system.
+ *
+ * @return an array of all joysticks installed on the system.
+ */
+ public Joystick[] getJoysticks() {
+ return joysticks;
+ }
+
+ /**
+ * Adds a {@link RawInputListener} to receive raw input events.
+ *
+ * <p>
+ * Any raw input listeners registered to this <code>InputManager</code>
+ * will receive raw input events first, before they get handled
+ * by the <code>InputManager</code> itself. The listeners are
+ * each processed in the order they were added, e.g. FIFO.
+ * <p>
+ * If a raw input listener has handled the event and does not wish
+ * other listeners down the list to process the event, it may set the
+ * {@link InputEvent#setConsumed() consumed flag} to indicate the
+ * event was consumed and shouldn't be processed any further.
+ * The listener may do this either at each of the event callbacks
+ * or at the {@link RawInputListener#endInput() } method.
+ *
+ * @param listener A listener to receive raw input events.
+ *
+ * @see RawInputListener
+ */
+ public void addRawInputListener(RawInputListener listener) {
+ rawListeners.add(listener);
+ rawListenerArray = null;
+ }
+
+ /**
+ * Removes a {@link RawInputListener} so that it no longer
+ * receives raw input events.
+ *
+ * @param listener The listener to cease receiving raw input events.
+ *
+ * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener)
+ */
+ public void removeRawInputListener(RawInputListener listener) {
+ rawListeners.remove(listener);
+ rawListenerArray = null;
+ }
+
+ /**
+ * Clears all {@link RawInputListener}s.
+ *
+ * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener)
+ */
+ public void clearRawInputListeners() {
+ rawListeners.clear();
+ rawListenerArray = null;
+ }
+
+ private RawInputListener[] getRawListenerArray() {
+ if (rawListenerArray == null)
+ rawListenerArray = rawListeners.toArray(new RawInputListener[rawListeners.size()]);
+ return rawListenerArray;
+ }
+
+ /**
+ * Enable simulation of mouse events. Used for touchscreen input only.
+ *
+ * @param value True to enable simulation of mouse events
+ */
+ public void setSimulateMouse(boolean value) {
+ if (touch != null) {
+ touch.setSimulateMouse(value);
+ }
+ }
+ /**
+ * Returns state of simulation of mouse events. Used for touchscreen input only.
+ *
+ */
+ public boolean getSimulateMouse() {
+ if (touch != null) {
+ return touch.getSimulateMouse();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Enable simulation of keyboard events. Used for touchscreen input only.
+ *
+ * @param value True to enable simulation of keyboard events
+ */
+ public void setSimulateKeyboard(boolean value) {
+ if (touch != null) {
+ touch.setSimulateKeyboard(value);
+ }
+ }
+
+ private void processQueue() {
+ int queueSize = inputQueue.size();
+ RawInputListener[] array = getRawListenerArray();
+
+ for (RawInputListener listener : array) {
+ listener.beginInput();
+
+ for (int j = 0; j < queueSize; j++) {
+ InputEvent event = inputQueue.get(j);
+ if (event.isConsumed()) {
+ continue;
+ }
+
+ if (event instanceof MouseMotionEvent) {
+ listener.onMouseMotionEvent((MouseMotionEvent) event);
+ } else if (event instanceof KeyInputEvent) {
+ listener.onKeyEvent((KeyInputEvent) event);
+ } else if (event instanceof MouseButtonEvent) {
+ listener.onMouseButtonEvent((MouseButtonEvent) event);
+ } else if (event instanceof JoyAxisEvent) {
+ listener.onJoyAxisEvent((JoyAxisEvent) event);
+ } else if (event instanceof JoyButtonEvent) {
+ listener.onJoyButtonEvent((JoyButtonEvent) event);
+ } else if (event instanceof TouchEvent) {
+ listener.onTouchEvent((TouchEvent) event);
+ } else {
+ assert false;
+ }
+ }
+
+ listener.endInput();
+ }
+
+ for (int i = 0; i < queueSize; i++) {
+ InputEvent event = inputQueue.get(i);
+ if (event.isConsumed()) {
+ continue;
+ }
+
+ if (event instanceof MouseMotionEvent) {
+ onMouseMotionEventQueued((MouseMotionEvent) event);
+ } else if (event instanceof KeyInputEvent) {
+ onKeyEventQueued((KeyInputEvent) event);
+ } else if (event instanceof MouseButtonEvent) {
+ onMouseButtonEventQueued((MouseButtonEvent) event);
+ } else if (event instanceof JoyAxisEvent) {
+ onJoyAxisEventQueued((JoyAxisEvent) event);
+ } else if (event instanceof JoyButtonEvent) {
+ onJoyButtonEventQueued((JoyButtonEvent) event);
+ } else if (event instanceof TouchEvent) {
+ onTouchEventQueued((TouchEvent) event);
+ } else {
+ assert false;
+ }
+ // larynx, 2011.06.10 - flag event as reusable because
+ // the android input uses a non-allocating ringbuffer which
+ // needs to know when the event is not anymore in inputQueue
+ // and therefor can be reused.
+ event.setConsumed();
+ }
+
+ inputQueue.clear();
+ }
+
+ /**
+ * Updates the <code>InputManager</code>.
+ * This will query current input devices and send
+ * appropriate events to registered listeners.
+ *
+ * @param tpf Time per frame value.
+ */
+ public void update(float tpf) {
+ frameTPF = tpf;
+
+ // Activate safemode if the TPF value is so small
+ // that rounding errors are inevitable
+ safeMode = tpf < 0.015f;
+
+ long currentTime = keys.getInputTimeNanos();
+ frameDelta = currentTime - lastUpdateTime;
+
+ eventsPermitted = true;
+
+ keys.update();
+ mouse.update();
+ if (joystick != null) {
+ joystick.update();
+ }
+ if (touch != null) {
+ touch.update();
+ }
+
+ eventsPermitted = false;
+
+ processQueue();
+ invokeUpdateActions();
+
+ lastLastUpdateTime = lastUpdateTime;
+ lastUpdateTime = currentTime;
+ }
+
+ /**
+ * Dispatches touch events to touch listeners
+ * @param evt The touch event to be dispatched to all onTouch listeners
+ */
+ public void onTouchEventQueued(TouchEvent evt) {
+ ArrayList<Mapping> maps = bindings.get(TouchTrigger.touchHash(evt.getKeyCode()));
+ if (maps == null) {
+ return;
+ }
+
+ int size = maps.size();
+ for (int i = size - 1; i >= 0; i--) {
+ Mapping mapping = maps.get(i);
+ ArrayList<InputListener> listeners = mapping.listeners;
+ int listenerSize = listeners.size();
+ for (int j = listenerSize - 1; j >= 0; j--) {
+ InputListener listener = listeners.get(j);
+ if (listener instanceof TouchListener) {
+ ((TouchListener) listener).onTouch(mapping.name, evt, frameTPF);
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback from RawInputListener. Do not use.
+ */
+ @Override
+ public void onTouchEvent(TouchEvent evt) {
+ if (!eventsPermitted) {
+ throw new UnsupportedOperationException("TouchInput has raised an event at an illegal time.");
+ }
+ inputQueue.add(evt);
+ }
+}
diff --git a/engine/src/core/com/jme3/input/SoftTextDialogInput.java b/engine/src/core/com/jme3/input/SoftTextDialogInput.java
new file mode 100644
index 0000000..d166b97
--- /dev/null
+++ b/engine/src/core/com/jme3/input/SoftTextDialogInput.java
@@ -0,0 +1,13 @@
+package com.jme3.input;
+
+import com.jme3.input.controls.SoftTextDialogInputListener;
+
+public interface SoftTextDialogInput {
+
+ public static int TEXT_ENTRY_DIALOG = 0;
+ public static int NUMERIC_ENTRY_DIALOG = 1;
+ public static int NUMERIC_KEYPAD_DIALOG = 2;
+
+ public void requestDialog(int id, String title, String initialValue, SoftTextDialogInputListener listener);
+
+}
diff --git a/engine/src/core/com/jme3/input/TouchInput.java b/engine/src/core/com/jme3/input/TouchInput.java
index 2f45b44..e69c4b3 100644
--- a/engine/src/core/com/jme3/input/TouchInput.java
+++ b/engine/src/core/com/jme3/input/TouchInput.java
@@ -73,6 +73,12 @@ public interface TouchInput extends Input {
* @param simulate if mouse events should be generated
*/
public void setSimulateMouse(boolean simulate);
+
+ /**
+ * Get if mouse events are generated
+ *
+ */
+ public boolean getSimulateMouse();
/**
* Set if keyboard events should be generated
diff --git a/engine/src/core/com/jme3/input/controls/SoftTextDialogInputListener.java b/engine/src/core/com/jme3/input/controls/SoftTextDialogInputListener.java
new file mode 100644
index 0000000..d33844d
--- /dev/null
+++ b/engine/src/core/com/jme3/input/controls/SoftTextDialogInputListener.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009-2010 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.input.controls;
+
+/**
+ *
+ * @author potterec (aka iwgeric)
+ */
+public interface SoftTextDialogInputListener {
+
+ public static int COMPLETE = 0;
+ public static int CANCEL = 1;
+
+ public void onSoftText(int action, String text);
+}
diff --git a/engine/src/core/com/jme3/math/Transform.java b/engine/src/core/com/jme3/math/Transform.java
index 7ccd847..3573d8c 100644
--- a/engine/src/core/com/jme3/math/Transform.java
+++ b/engine/src/core/com/jme3/math/Transform.java
@@ -1,318 +1,318 @@
-/*
- * Copyright (c) 2009-2010 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.math;
-
-import com.jme3.export.*;
-import java.io.IOException;
-
-/**
- * Started Date: Jul 16, 2004<br><br>
- * Represents a translation, rotation and scale in one object.
- *
- * @author Jack Lindamood
- * @author Joshua Slack
- */
-public final class Transform implements Savable, Cloneable, java.io.Serializable {
-
- static final long serialVersionUID = 1;
-
- public static final Transform IDENTITY = new Transform();
-
- private Quaternion rot = new Quaternion();
- private Vector3f translation = new Vector3f();
- private Vector3f scale = new Vector3f(1,1,1);
-
- public Transform(Vector3f translation, Quaternion rot){
- this.translation.set(translation);
- this.rot.set(rot);
- }
-
- public Transform(Vector3f translation, Quaternion rot, Vector3f scale){
- this(translation, rot);
- this.scale.set(scale);
- }
-
- public Transform(Vector3f translation){
- this(translation, Quaternion.IDENTITY);
- }
-
- public Transform(Quaternion rot){
- this(Vector3f.ZERO, rot);
- }
-
- public Transform(){
- this(Vector3f.ZERO, Quaternion.IDENTITY);
- }
-
- /**
- * Sets this rotation to the given Quaternion value.
- * @param rot The new rotation for this matrix.
- * @return this
- */
- public Transform setRotation(Quaternion rot) {
- this.rot.set(rot);
- return this;
- }
-
- /**
- * Sets this translation to the given value.
- * @param trans The new translation for this matrix.
- * @return this
- */
- public Transform setTranslation(Vector3f trans) {
- this.translation.set(trans);
- return this;
- }
-
- /**
- * Return the translation vector in this matrix.
- * @return translation vector.
- */
- public Vector3f getTranslation() {
- return translation;
- }
-
- /**
- * Sets this scale to the given value.
- * @param scale The new scale for this matrix.
- * @return this
- */
- public Transform setScale(Vector3f scale) {
- this.scale.set(scale);
- return this;
- }
-
- /**
- * Sets this scale to the given value.
- * @param scale The new scale for this matrix.
- * @return this
- */
- public Transform setScale(float scale) {
- this.scale.set(scale, scale, scale);
- return this;
- }
-
- /**
- * Return the scale vector in this matrix.
- * @return scale vector.
- */
- public Vector3f getScale() {
- return scale;
- }
-
- /**
- * Stores this translation value into the given vector3f. If trans is null, a new vector3f is created to
- * hold the value. The value, once stored, is returned.
- * @param trans The store location for this matrix's translation.
- * @return The value of this matrix's translation.
- */
- public Vector3f getTranslation(Vector3f trans) {
- if (trans==null) trans=new Vector3f();
- trans.set(this.translation);
- return trans;
- }
-
- /**
- * Stores this rotation value into the given Quaternion. If quat is null, a new Quaternion is created to
- * hold the value. The value, once stored, is returned.
- * @param quat The store location for this matrix's rotation.
- * @return The value of this matrix's rotation.
- */
- public Quaternion getRotation(Quaternion quat) {
- if (quat==null) quat=new Quaternion();
- quat.set(rot);
- return quat;
- }
-
- /**
- * Return the rotation quaternion in this matrix.
- * @return rotation quaternion.
- */
- public Quaternion getRotation() {
- return rot;
- }
-
- /**
- * Stores this scale value into the given vector3f. If scale is null, a new vector3f is created to
- * hold the value. The value, once stored, is returned.
- * @param scale The store location for this matrix's scale.
- * @return The value of this matrix's scale.
- */
- public Vector3f getScale(Vector3f scale) {
- if (scale==null) scale=new Vector3f();
- scale.set(this.scale);
- return scale;
- }
-
- /**
- * Sets this matrix to the interpolation between the first matrix and the second by delta amount.
- * @param t1 The begining transform.
- * @param t2 The ending transform.
- * @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2.
- */
- public void interpolateTransforms(Transform t1, Transform t2, float delta) {
- this.rot.slerp(t1.rot,t2.rot,delta);
- this.translation.interpolate(t1.translation,t2.translation,delta);
- this.scale.interpolate(t1.scale,t2.scale,delta);
- }
-
- /**
- * Changes the values of this matrix acording to it's parent. Very similar to the concept of Node/Spatial transforms.
- * @param parent The parent matrix.
- * @return This matrix, after combining.
- */
- public Transform combineWithParent(Transform parent) {
- scale.multLocal(parent.scale);
-// rot.multLocal(parent.rot);
- parent.rot.mult(rot, rot);
-
- // This here, is evil code
-// parent
-// .rot
-// .multLocal(translation)
-// .multLocal(parent.scale)
-// .addLocal(parent.translation);
-
- translation.multLocal(parent.scale);
- parent
- .rot
- .multLocal(translation)
- .addLocal(parent.translation);
- return this;
- }
-
- /**
- * Sets this matrix's translation to the given x,y,z values.
- * @param x This matrix's new x translation.
- * @param y This matrix's new y translation.
- * @param z This matrix's new z translation.
- * @return this
- */
- public Transform setTranslation(float x,float y, float z) {
- translation.set(x,y,z);
- return this;
- }
-
- /**
- * Sets this matrix's scale to the given x,y,z values.
- * @param x This matrix's new x scale.
- * @param y This matrix's new y scale.
- * @param z This matrix's new z scale.
- * @return this
- */
- public Transform setScale(float x, float y, float z) {
- scale.set(x,y,z);
- return this;
- }
-
- public Vector3f transformVector(final Vector3f in, Vector3f store){
- if (store == null)
- store = new Vector3f();
-
- // multiply with scale first, then rotate, finally translate (cf.
- // Eberly)
- return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation);
- }
-
- public Vector3f transformInverseVector(final Vector3f in, Vector3f store){
- if (store == null)
- store = new Vector3f();
-
- // The author of this code should look above and take the inverse of that
- // But for some reason, they didnt ..
-// in.subtract(translation, store).divideLocal(scale);
-// rot.inverse().mult(store, store);
-
- in.subtract(translation, store);
- rot.inverse().mult(store, store);
- store.divideLocal(scale);
-
- return store;
- }
-
- /**
- * Loads the identity. Equal to translation=1,1,1 scale=0,0,0 rot=0,0,0,1.
- */
- public void loadIdentity() {
- translation.set(0,0,0);
- scale.set(1,1,1);
- rot.set(0,0,0,1);
- }
-
- @Override
- public String toString(){
- return getClass().getSimpleName() + "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n"
- + "[ " + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "]\n"
- + "[ " + scale.x + " , " + scale.y + ", " + scale.z + "]";
- }
-
- /**
- * Sets this matrix to be equal to the given matrix.
- * @param matrixQuat The matrix to be equal to.
- * @return this
- */
- public Transform set(Transform matrixQuat) {
- this.translation.set(matrixQuat.translation);
- this.rot.set(matrixQuat.rot);
- this.scale.set(matrixQuat.scale);
- return this;
- }
-
- public void write(JmeExporter e) throws IOException {
- OutputCapsule capsule = e.getCapsule(this);
- capsule.write(rot, "rot", new Quaternion());
- capsule.write(translation, "translation", Vector3f.ZERO);
- capsule.write(scale, "scale", Vector3f.UNIT_XYZ);
- }
-
- public void read(JmeImporter e) throws IOException {
- InputCapsule capsule = e.getCapsule(this);
-
- rot = (Quaternion)capsule.readSavable("rot", new Quaternion());
- translation = (Vector3f)capsule.readSavable("translation", Vector3f.ZERO);
- scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ);
- }
-
- @Override
- public Transform clone() {
- try {
- Transform tq = (Transform) super.clone();
- tq.rot = rot.clone();
- tq.scale = scale.clone();
- tq.translation = translation.clone();
- return tq;
- } catch (CloneNotSupportedException e) {
- throw new AssertionError();
- }
- }
-}
+/*
+ * Copyright (c) 2009-2010 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.math;
+
+import com.jme3.export.*;
+import java.io.IOException;
+
+/**
+ * Started Date: Jul 16, 2004<br><br>
+ * Represents a translation, rotation and scale in one object.
+ *
+ * @author Jack Lindamood
+ * @author Joshua Slack
+ */
+public final class Transform implements Savable, Cloneable, java.io.Serializable {
+
+ static final long serialVersionUID = 1;
+
+ public static final Transform IDENTITY = new Transform();
+
+ private Quaternion rot = new Quaternion();
+ private Vector3f translation = new Vector3f();
+ private Vector3f scale = new Vector3f(1,1,1);
+
+ public Transform(Vector3f translation, Quaternion rot){
+ this.translation.set(translation);
+ this.rot.set(rot);
+ }
+
+ public Transform(Vector3f translation, Quaternion rot, Vector3f scale){
+ this(translation, rot);
+ this.scale.set(scale);
+ }
+
+ public Transform(Vector3f translation){
+ this(translation, Quaternion.IDENTITY);
+ }
+
+ public Transform(Quaternion rot){
+ this(Vector3f.ZERO, rot);
+ }
+
+ public Transform(){
+ this(Vector3f.ZERO, Quaternion.IDENTITY);
+ }
+
+ /**
+ * Sets this rotation to the given Quaternion value.
+ * @param rot The new rotation for this matrix.
+ * @return this
+ */
+ public Transform setRotation(Quaternion rot) {
+ this.rot.set(rot);
+ return this;
+ }
+
+ /**
+ * Sets this translation to the given value.
+ * @param trans The new translation for this matrix.
+ * @return this
+ */
+ public Transform setTranslation(Vector3f trans) {
+ this.translation.set(trans);
+ return this;
+ }
+
+ /**
+ * Return the translation vector in this matrix.
+ * @return translation vector.
+ */
+ public Vector3f getTranslation() {
+ return translation;
+ }
+
+ /**
+ * Sets this scale to the given value.
+ * @param scale The new scale for this matrix.
+ * @return this
+ */
+ public Transform setScale(Vector3f scale) {
+ this.scale.set(scale);
+ return this;
+ }
+
+ /**
+ * Sets this scale to the given value.
+ * @param scale The new scale for this matrix.
+ * @return this
+ */
+ public Transform setScale(float scale) {
+ this.scale.set(scale, scale, scale);
+ return this;
+ }
+
+ /**
+ * Return the scale vector in this matrix.
+ * @return scale vector.
+ */
+ public Vector3f getScale() {
+ return scale;
+ }
+
+ /**
+ * Stores this translation value into the given vector3f. If trans is null, a new vector3f is created to
+ * hold the value. The value, once stored, is returned.
+ * @param trans The store location for this matrix's translation.
+ * @return The value of this matrix's translation.
+ */
+ public Vector3f getTranslation(Vector3f trans) {
+ if (trans==null) trans=new Vector3f();
+ trans.set(this.translation);
+ return trans;
+ }
+
+ /**
+ * Stores this rotation value into the given Quaternion. If quat is null, a new Quaternion is created to
+ * hold the value. The value, once stored, is returned.
+ * @param quat The store location for this matrix's rotation.
+ * @return The value of this matrix's rotation.
+ */
+ public Quaternion getRotation(Quaternion quat) {
+ if (quat==null) quat=new Quaternion();
+ quat.set(rot);
+ return quat;
+ }
+
+ /**
+ * Return the rotation quaternion in this matrix.
+ * @return rotation quaternion.
+ */
+ public Quaternion getRotation() {
+ return rot;
+ }
+
+ /**
+ * Stores this scale value into the given vector3f. If scale is null, a new vector3f is created to
+ * hold the value. The value, once stored, is returned.
+ * @param scale The store location for this matrix's scale.
+ * @return The value of this matrix's scale.
+ */
+ public Vector3f getScale(Vector3f scale) {
+ if (scale==null) scale=new Vector3f();
+ scale.set(this.scale);
+ return scale;
+ }
+
+ /**
+ * Sets this matrix to the interpolation between the first matrix and the second by delta amount.
+ * @param t1 The begining transform.
+ * @param t2 The ending transform.
+ * @param delta An amount between 0 and 1 representing how far to interpolate from t1 to t2.
+ */
+ public void interpolateTransforms(Transform t1, Transform t2, float delta) {
+ this.rot.slerp(t1.rot,t2.rot,delta);
+ this.translation.interpolate(t1.translation,t2.translation,delta);
+ this.scale.interpolate(t1.scale,t2.scale,delta);
+ }
+
+ /**
+ * Changes the values of this matrix acording to it's parent. Very similar to the concept of Node/Spatial transforms.
+ * @param parent The parent matrix.
+ * @return This matrix, after combining.
+ */
+ public Transform combineWithParent(Transform parent) {
+ scale.multLocal(parent.scale);
+// rot.multLocal(parent.rot);
+ parent.rot.mult(rot, rot);
+
+ // This here, is evil code
+// parent
+// .rot
+// .multLocal(translation)
+// .multLocal(parent.scale)
+// .addLocal(parent.translation);
+
+ translation.multLocal(parent.scale);
+ parent
+ .rot
+ .multLocal(translation)
+ .addLocal(parent.translation);
+ return this;
+ }
+
+ /**
+ * Sets this matrix's translation to the given x,y,z values.
+ * @param x This matrix's new x translation.
+ * @param y This matrix's new y translation.
+ * @param z This matrix's new z translation.
+ * @return this
+ */
+ public Transform setTranslation(float x,float y, float z) {
+ translation.set(x,y,z);
+ return this;
+ }
+
+ /**
+ * Sets this matrix's scale to the given x,y,z values.
+ * @param x This matrix's new x scale.
+ * @param y This matrix's new y scale.
+ * @param z This matrix's new z scale.
+ * @return this
+ */
+ public Transform setScale(float x, float y, float z) {
+ scale.set(x,y,z);
+ return this;
+ }
+
+ public Vector3f transformVector(final Vector3f in, Vector3f store){
+ if (store == null)
+ store = new Vector3f();
+
+ // multiply with scale first, then rotate, finally translate (cf.
+ // Eberly)
+ return rot.mult(store.set(in).multLocal(scale), store).addLocal(translation);
+ }
+
+ public Vector3f transformInverseVector(final Vector3f in, Vector3f store){
+ if (store == null)
+ store = new Vector3f();
+
+ // The author of this code should look above and take the inverse of that
+ // But for some reason, they didnt ..
+// in.subtract(translation, store).divideLocal(scale);
+// rot.inverse().mult(store, store);
+
+ in.subtract(translation, store);
+ rot.inverse().mult(store, store);
+ store.divideLocal(scale);
+
+ return store;
+ }
+
+ /**
+ * 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);
+ }
+
+ @Override
+ public String toString(){
+ return getClass().getSimpleName() + "[ " + translation.x + ", " + translation.y + ", " + translation.z + "]\n"
+ + "[ " + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "]\n"
+ + "[ " + scale.x + " , " + scale.y + ", " + scale.z + "]";
+ }
+
+ /**
+ * Sets this matrix to be equal to the given matrix.
+ * @param matrixQuat The matrix to be equal to.
+ * @return this
+ */
+ public Transform set(Transform matrixQuat) {
+ this.translation.set(matrixQuat.translation);
+ this.rot.set(matrixQuat.rot);
+ this.scale.set(matrixQuat.scale);
+ return this;
+ }
+
+ public void write(JmeExporter e) throws IOException {
+ OutputCapsule capsule = e.getCapsule(this);
+ capsule.write(rot, "rot", new Quaternion());
+ capsule.write(translation, "translation", Vector3f.ZERO);
+ capsule.write(scale, "scale", Vector3f.UNIT_XYZ);
+ }
+
+ public void read(JmeImporter e) throws IOException {
+ InputCapsule capsule = e.getCapsule(this);
+
+ rot = (Quaternion)capsule.readSavable("rot", new Quaternion());
+ translation = (Vector3f)capsule.readSavable("translation", Vector3f.ZERO);
+ scale = (Vector3f)capsule.readSavable("scale", Vector3f.UNIT_XYZ);
+ }
+
+ @Override
+ public Transform clone() {
+ try {
+ Transform tq = (Transform) super.clone();
+ tq.rot = rot.clone();
+ tq.scale = scale.clone();
+ tq.translation = translation.clone();
+ return tq;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/engine/src/core/com/jme3/post/Filter.java b/engine/src/core/com/jme3/post/Filter.java
index ef9a6ff..12babf5 100644
--- a/engine/src/core/com/jme3/post/Filter.java
+++ b/engine/src/core/com/jme3/post/Filter.java
@@ -40,6 +40,7 @@ import com.jme3.renderer.Renderer;
import com.jme3.renderer.ViewPort;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
+import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import java.io.IOException;
import java.util.Collection;
@@ -236,7 +237,7 @@ public abstract class Filter implements Savable {
* cleanup this filter
* @param r
*/
- protected final void cleanup(Renderer r) {
+ protected final void cleanup(Renderer r) {
processor = null;
if (defaultPass != null) {
defaultPass.cleanup(r);
@@ -269,8 +270,6 @@ public abstract class Filter implements Savable {
protected void cleanUpFilter(Renderer r) {
}
- ;
-
/**
* Must return the material used for this filter.
* this method is called every frame.
@@ -278,6 +277,14 @@ public abstract class Filter implements Savable {
* @return the material used for this filter.
*/
protected abstract Material getMaterial();
+
+ /**
+ * Override if you want to do something special with the depth texture;
+ * @param depthTexture
+ */
+ protected void setDepthTexture(Texture depthTexture){
+ getMaterial().setTexture("DepthTexture", depthTexture);
+ }
/**
* Override this method if you want to make a pre pass, before the actual rendering of the frame
diff --git a/engine/src/core/com/jme3/post/FilterPostProcessor.java b/engine/src/core/com/jme3/post/FilterPostProcessor.java
index 2e48f0f..d97e8e9 100644
--- a/engine/src/core/com/jme3/post/FilterPostProcessor.java
+++ b/engine/src/core/com/jme3/post/FilterPostProcessor.java
@@ -77,7 +77,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
private int originalHeight;
private int lastFilterIndex = -1;
private boolean cameraInit = false;
-
+
/**
* Create a FilterProcessor
* @param assetManager the assetManager
@@ -98,8 +98,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
* @param filter the filter to add
*/
public void addFilter(Filter filter) {
- filters.add(filter);
- filter.setProcessor(this);
+ filters.add(filter);
if (isInitialized()) {
initFilter(filter, viewPort);
@@ -148,14 +147,17 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
* @param vp
*/
private void initFilter(Filter filter, ViewPort vp) {
- filter.init(assetManager, renderManager, vp, width, height);
+ filter.setProcessor(this);
if (filter.isRequiresDepthTexture()) {
- if (!computeDepth && renderFrameBuffer != null) {
+ if (!computeDepth && renderFrameBuffer != null) {
depthTexture = new Texture2D(width, height, Format.Depth24);
renderFrameBuffer.setDepthTexture(depthTexture);
}
computeDepth = true;
- filter.getMaterial().setTexture("DepthTexture", depthTexture);
+ filter.init(assetManager, renderManager, vp, width, height);
+ filter.setDepthTexture(depthTexture);
+ } else {
+ filter.init(assetManager, renderManager, vp, width, height);
}
}
@@ -281,9 +283,9 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
} else if (renderFrameBufferMS != null) {
sceneBuffer = renderFrameBufferMS;
}
- renderFilterChain(renderer, sceneBuffer);
+ renderFilterChain(renderer, sceneBuffer);
renderer.setFrameBuffer(outputBuffer);
-
+
//viewport can be null if no filters are enabled
if (viewPort != null) {
renderManager.setCamera(viewPort.getCamera(), false);
@@ -356,8 +358,11 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
//reseting the viewport camera viewport to its initial value
viewPort.getCamera().resize(originalWidth, originalHeight, true);
viewPort.getCamera().setViewPort(left, right, bottom, top);
- viewPort.setOutputFrameBuffer(outputBuffer);
+ viewPort.setOutputFrameBuffer(outputBuffer);
viewPort = null;
+ for (Filter filter : filters) {
+ filter.cleanup(renderer);
+ }
}
}
@@ -484,7 +489,7 @@ public class FilterPostProcessor implements SceneProcessor, Savable {
* For internal use only<br>
* returns the depth texture of the scene
* @return
- */
+ */
public Texture2D getDepthTexture() {
return depthTexture;
}
diff --git a/engine/src/core/com/jme3/renderer/RenderManager.java b/engine/src/core/com/jme3/renderer/RenderManager.java
index 1d58d22..a0f5fdf 100644
--- a/engine/src/core/com/jme3/renderer/RenderManager.java
+++ b/engine/src/core/com/jme3/renderer/RenderManager.java
@@ -1,1170 +1,1178 @@
-/*
- * 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.renderer;
-
-import com.jme3.material.Material;
-import com.jme3.material.MaterialDef;
-import com.jme3.material.RenderState;
-import com.jme3.material.Technique;
-import com.jme3.math.*;
-import com.jme3.post.SceneProcessor;
-import com.jme3.renderer.queue.GeometryList;
-import com.jme3.renderer.queue.RenderQueue;
-import com.jme3.renderer.queue.RenderQueue.Bucket;
-import com.jme3.renderer.queue.RenderQueue.ShadowMode;
-import com.jme3.scene.*;
-import com.jme3.shader.Uniform;
-import com.jme3.shader.UniformBinding;
-import com.jme3.shader.VarType;
-import com.jme3.system.NullRenderer;
-import com.jme3.system.Timer;
-import com.jme3.util.IntMap.Entry;
-import com.jme3.util.TempVars;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Logger;
-
-/**
- * <code>RenderManager</code> is a high-level rendering interface that is
- * above the Renderer implementation. RenderManager takes care
- * of rendering the scene graphs attached to each viewport and
- * handling SceneProcessors.
- *
- * @see SceneProcessor
- * @see ViewPort
- * @see Spatial
- */
-public class RenderManager {
-
- private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
-
- private Renderer renderer;
- private Timer timer;
- private ArrayList<ViewPort> preViewPorts = new ArrayList<ViewPort>();
- private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
- private ArrayList<ViewPort> postViewPorts = new ArrayList<ViewPort>();
- private Camera prevCam = null;
- private Material forcedMaterial = null;
- private String forcedTechnique = null;
- private RenderState forcedRenderState = null;
- private boolean shader;
- private int viewX, viewY, viewWidth, viewHeight;
- private float near, far;
- private Matrix4f orthoMatrix = new Matrix4f();
- private Matrix4f viewMatrix = new Matrix4f();
- private Matrix4f projMatrix = new Matrix4f();
- private Matrix4f viewProjMatrix = new Matrix4f();
- private Matrix4f worldMatrix = new Matrix4f();
- private Vector3f camUp = new Vector3f(),
- camLeft = new Vector3f(),
- camDir = new Vector3f(),
- camLoc = new Vector3f();
- //temp technique
- private String tmpTech;
- private boolean handleTranlucentBucket = true;
-
- /**
- * Create a high-level rendering interface over the
- * low-level rendering interface.
- * @param renderer
- */
- public RenderManager(Renderer renderer) {
- this.renderer = renderer;
- //this.shader = renderer.getCaps().contains(Caps.GLSL100);
- }
-
- /**
- * Returns the pre ViewPort with the given name.
- *
- * @param viewName The name of the pre ViewPort to look up
- * @return The ViewPort, or null if not found.
- *
- * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
- */
- public ViewPort getPreView(String viewName) {
- for (int i = 0; i < preViewPorts.size(); i++) {
- if (preViewPorts.get(i).getName().equals(viewName)) {
- return preViewPorts.get(i);
- }
- }
- return null;
- }
-
- /**
- * Removes the specified pre ViewPort.
- *
- * @param view The pre ViewPort to remove
- * @return True if the ViewPort was removed successfully.
- *
- * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
- */
- public boolean removePreView(ViewPort view) {
- return preViewPorts.remove(view);
- }
-
- /**
- * Returns the main ViewPort with the given name.
- *
- * @param viewName The name of the main ViewPort to look up
- * @return The ViewPort, or null if not found.
- *
- * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
- */
- public ViewPort getMainView(String viewName) {
- for (int i = 0; i < viewPorts.size(); i++) {
- if (viewPorts.get(i).getName().equals(viewName)) {
- return viewPorts.get(i);
- }
- }
- return null;
- }
-
- /**
- * Removes the main ViewPort with the specified name.
- *
- * @param viewName The main ViewPort name to remove
- * @return True if the ViewPort was removed successfully.
- *
- * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
- */
- public boolean removeMainView(String viewName) {
- for (int i = 0; i < viewPorts.size(); i++) {
- if (viewPorts.get(i).getName().equals(viewName)) {
- viewPorts.remove(i);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Removes the specified main ViewPort.
- *
- * @param view The main ViewPort to remove
- * @return True if the ViewPort was removed successfully.
- *
- * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
- */
- public boolean removeMainView(ViewPort view) {
- return viewPorts.remove(view);
- }
-
- /**
- * Returns the post ViewPort with the given name.
- *
- * @param viewName The name of the post ViewPort to look up
- * @return The ViewPort, or null if not found.
- *
- * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
- */
- public ViewPort getPostView(String viewName) {
- for (int i = 0; i < postViewPorts.size(); i++) {
- if (postViewPorts.get(i).getName().equals(viewName)) {
- return postViewPorts.get(i);
- }
- }
- return null;
- }
-
- /**
- * Removes the post ViewPort with the specified name.
- *
- * @param viewName The post ViewPort name to remove
- * @return True if the ViewPort was removed successfully.
- *
- * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
- */
- public boolean removePostView(String viewName) {
- for (int i = 0; i < postViewPorts.size(); i++) {
- if (postViewPorts.get(i).getName().equals(viewName)) {
- postViewPorts.remove(i);
-
- return true;
- }
- }
- return false;
- }
-
- /**
- * Removes the specified post ViewPort.
- *
- * @param view The post ViewPort to remove
- * @return True if the ViewPort was removed successfully.
- *
- * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
- */
- public boolean removePostView(ViewPort view) {
- return postViewPorts.remove(view);
- }
-
- /**
- * Returns a read-only list of all pre ViewPorts
- * @return a read-only list of all pre ViewPorts
- * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
- */
- public List<ViewPort> getPreViews() {
- return Collections.unmodifiableList(preViewPorts);
- }
-
- /**
- * Returns a read-only list of all main ViewPorts
- * @return a read-only list of all main ViewPorts
- * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
- */
- public List<ViewPort> getMainViews() {
- return Collections.unmodifiableList(viewPorts);
- }
-
- /**
- * Returns a read-only list of all post ViewPorts
- * @return a read-only list of all post ViewPorts
- * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
- */
- public List<ViewPort> getPostViews() {
- return Collections.unmodifiableList(postViewPorts);
- }
-
- /**
- * Creates a new pre ViewPort, to display the given camera's content.
- * <p>
- * The view will be processed before the main and post viewports.
- */
- public ViewPort createPreView(String viewName, Camera cam) {
- ViewPort vp = new ViewPort(viewName, cam);
- preViewPorts.add(vp);
- return vp;
- }
-
- /**
- * Creates a new main ViewPort, to display the given camera's content.
- * <p>
- * The view will be processed before the post viewports but after
- * the pre viewports.
- */
- public ViewPort createMainView(String viewName, Camera cam) {
- ViewPort vp = new ViewPort(viewName, cam);
- viewPorts.add(vp);
- return vp;
- }
-
- /**
- * Creates a new post ViewPort, to display the given camera's content.
- * <p>
- * The view will be processed after the pre and main viewports.
- */
- public ViewPort createPostView(String viewName, Camera cam) {
- ViewPort vp = new ViewPort(viewName, cam);
- postViewPorts.add(vp);
- return vp;
- }
-
- private void notifyReshape(ViewPort vp, int w, int h) {
- List<SceneProcessor> processors = vp.getProcessors();
- for (SceneProcessor proc : processors) {
- if (!proc.isInitialized()) {
- proc.initialize(this, vp);
- } else {
- proc.reshape(vp, w, h);
- }
- }
- }
-
- /**
- * Internal use only.
- * Updates the resolution of all on-screen cameras to match
- * the given width and height.
- */
- public void notifyReshape(int w, int h) {
- for (ViewPort vp : preViewPorts) {
- if (vp.getOutputFrameBuffer() == null) {
- Camera cam = vp.getCamera();
- cam.resize(w, h, true);
- }
- notifyReshape(vp, w, h);
- }
- for (ViewPort vp : viewPorts) {
- if (vp.getOutputFrameBuffer() == null) {
- Camera cam = vp.getCamera();
- cam.resize(w, h, true);
- }
- notifyReshape(vp, w, h);
- }
- for (ViewPort vp : postViewPorts) {
- if (vp.getOutputFrameBuffer() == null) {
- Camera cam = vp.getCamera();
- cam.resize(w, h, true);
- }
- notifyReshape(vp, w, h);
- }
- }
-
- /**
- * Internal use only.
- * Updates the given list of uniforms with {@link UniformBinding uniform bindings}
- * based on the current world state.
- */
- public void updateUniformBindings(List<Uniform> params) {
- // assums worldMatrix is properly set.
- TempVars vars = TempVars.get();
-
- Matrix4f tempMat4 = vars.tempMat4;
- Matrix3f tempMat3 = vars.tempMat3;
- Vector2f tempVec2 = vars.vect2d;
- Quaternion tempVec4 = vars.quat1;
-
- for (int i = 0; i < params.size(); i++) {
- Uniform u = params.get(i);
- switch (u.getBinding()) {
- case WorldMatrix:
- u.setValue(VarType.Matrix4, worldMatrix);
- break;
- case ViewMatrix:
- u.setValue(VarType.Matrix4, viewMatrix);
- break;
- case ProjectionMatrix:
- u.setValue(VarType.Matrix4, projMatrix);
- break;
- case ViewProjectionMatrix:
- u.setValue(VarType.Matrix4, viewProjMatrix);
- break;
- case WorldViewMatrix:
- tempMat4.set(viewMatrix);
- tempMat4.multLocal(worldMatrix);
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case NormalMatrix:
- tempMat4.set(viewMatrix);
- tempMat4.multLocal(worldMatrix);
- tempMat4.toRotationMatrix(tempMat3);
- tempMat3.invertLocal();
- tempMat3.transposeLocal();
- u.setValue(VarType.Matrix3, tempMat3);
- break;
- case WorldViewProjectionMatrix:
- tempMat4.set(viewProjMatrix);
- tempMat4.multLocal(worldMatrix);
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case WorldMatrixInverse:
- tempMat4.multLocal(worldMatrix);
- tempMat4.invertLocal();
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case ViewMatrixInverse:
- tempMat4.set(viewMatrix);
- tempMat4.invertLocal();
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case ProjectionMatrixInverse:
- tempMat4.set(projMatrix);
- tempMat4.invertLocal();
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case ViewProjectionMatrixInverse:
- tempMat4.set(viewProjMatrix);
- tempMat4.invertLocal();
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case WorldViewMatrixInverse:
- tempMat4.set(viewMatrix);
- tempMat4.multLocal(worldMatrix);
- tempMat4.invertLocal();
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case NormalMatrixInverse:
- tempMat4.set(viewMatrix);
- tempMat4.multLocal(worldMatrix);
- tempMat4.toRotationMatrix(tempMat3);
- tempMat3.invertLocal();
- tempMat3.transposeLocal();
- tempMat3.invertLocal();
- u.setValue(VarType.Matrix3, tempMat3);
- break;
- case WorldViewProjectionMatrixInverse:
- tempMat4.set(viewProjMatrix);
- tempMat4.multLocal(worldMatrix);
- tempMat4.invertLocal();
- u.setValue(VarType.Matrix4, tempMat4);
- break;
- case ViewPort:
- tempVec4.set(viewX, viewY, viewWidth, viewHeight);
- u.setValue(VarType.Vector4, tempVec4);
- break;
- case Resolution:
- tempVec2.set(viewWidth, viewHeight);
- u.setValue(VarType.Vector2, tempVec2);
- break;
- case Aspect:
- float aspect = ((float) viewWidth) / viewHeight;
- u.setValue(VarType.Float, aspect);
- break;
- case FrustumNearFar:
- tempVec2.set(near, far);
- u.setValue(VarType.Vector2, tempVec2);
- break;
- case CameraPosition:
- u.setValue(VarType.Vector3, camLoc);
- break;
- case CameraDirection:
- u.setValue(VarType.Vector3, camDir);
- break;
- case CameraLeft:
- u.setValue(VarType.Vector3, camLeft);
- break;
- case CameraUp:
- u.setValue(VarType.Vector3, camUp);
- break;
- case Time:
- u.setValue(VarType.Float, timer.getTimeInSeconds());
- break;
- case Tpf:
- u.setValue(VarType.Float, timer.getTimePerFrame());
- break;
- case FrameRate:
- u.setValue(VarType.Float, timer.getFrameRate());
- break;
- }
- }
-
- vars.release();
- }
-
- /**
- * Set the material to use to render all future objects.
- * This overrides the material set on the geometry and renders
- * with the provided material instead.
- * Use null to clear the material and return renderer to normal
- * functionality.
- * @param mat The forced material to set, or null to return to normal
- */
- public void setForcedMaterial(Material mat) {
- forcedMaterial = mat;
- }
-
- /**
- * Returns the forced render state previously set with
- * {@link #setForcedRenderState(com.jme3.material.RenderState) }.
- * @return the forced render state
- */
- public RenderState getForcedRenderState() {
- return forcedRenderState;
- }
-
- /**
- * Set the render state to use for all future objects.
- * This overrides the render state set on the material and instead
- * forces this render state to be applied for all future materials
- * rendered. Set to null to return to normal functionality.
- *
- * @param forcedRenderState The forced render state to set, or null
- * to return to normal
- */
- public void setForcedRenderState(RenderState forcedRenderState) {
- this.forcedRenderState = forcedRenderState;
- }
-
- /**
- * Set the timer that should be used to query the time based
- * {@link UniformBinding}s for material world parameters.
- *
- * @param timer The timer to query time world parameters
- */
- public void setTimer(Timer timer) {
- this.timer = timer;
- }
-
- /**
- * Returns the forced technique name set.
- *
- * @return the forced technique name set.
- *
- * @see #setForcedTechnique(java.lang.String)
- */
- public String getForcedTechnique() {
- return forcedTechnique;
- }
-
- /**
- * Sets the forced technique to use when rendering geometries.
- * <p>
- * If the specified technique name is available on the geometry's
- * material, then it is used, otherwise, the
- * {@link #setForcedMaterial(com.jme3.material.Material) forced material} is used.
- * If a forced material is not set and the forced technique name cannot
- * be found on the material, the geometry will <em>not</em> be rendered.
- *
- * @param forcedTechnique The forced technique name to use, set to null
- * to return to normal functionality.
- *
- * @see #renderGeometry(com.jme3.scene.Geometry)
- */
- public void setForcedTechnique(String forcedTechnique) {
- this.forcedTechnique = forcedTechnique;
- }
-
- /**
- * Enable or disable alpha-to-coverage.
- * <p>
- * When alpha to coverage is enabled and the renderer implementation
- * supports it, then alpha blending will be replaced with alpha dissolve
- * if multi-sampling is also set on the renderer.
- * This feature allows avoiding of alpha blending artifacts due to
- * lack of triangle-level back-to-front sorting.
- *
- * @param value True to enable alpha-to-coverage, false otherwise.
- */
- public void setAlphaToCoverage(boolean value) {
- renderer.setAlphaToCoverage(value);
- }
-
- /**
- * True if the translucent bucket should automatically be rendered
- * by the RenderManager.
- *
- * @return Whether or not the translucent bucket is rendered.
- *
- * @see #setHandleTranslucentBucket(boolean)
- */
- public boolean isHandleTranslucentBucket() {
- return handleTranlucentBucket;
- }
-
- /**
- * Enable or disable rendering of the
- * {@link Bucket#Translucent translucent bucket}
- * by the RenderManager. The default is enabled.
- *
- * @param handleTranslucentBucket Whether or not the translucent bucket should
- * be rendered.
- */
- public void setHandleTranslucentBucket(boolean handleTranslucentBucket) {
- this.handleTranlucentBucket = handleTranslucentBucket;
- }
-
- /**
- * Internal use only. Sets the world matrix to use for future
- * rendering. This has no effect unless objects are rendered manually
- * using {@link Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) }.
- * Using {@link #renderGeometry(com.jme3.scene.Geometry) } will
- * override this value.
- *
- * @param mat The world matrix to set
- */
- public void setWorldMatrix(Matrix4f mat) {
- if (shader) {
- worldMatrix.set(mat);
- } else {
- renderer.setWorldMatrix(mat);
- }
- }
-
- /**
- * Renders the given geometry.
- * <p>
- * First the proper world matrix is set, if
- * the geometry's {@link Geometry#setIgnoreTransform(boolean) ignore transform}
- * feature is enabled, the identity world matrix is used, otherwise, the
- * geometry's {@link Geometry#getWorldMatrix() world transform matrix} is used.
- * <p>
- * Once the world matrix is applied, the proper material is chosen for rendering.
- * If a {@link #setForcedMaterial(com.jme3.material.Material) forced material} is
- * set on this RenderManager, then it is used for rendering the geometry,
- * otherwise, the {@link Geometry#getMaterial() geometry's material} is used.
- * <p>
- * If a {@link #setForcedTechnique(java.lang.String) forced technique} is
- * set on this RenderManager, then it is selected automatically
- * on the geometry's material and is used for rendering. Otherwise, one
- * of the {@link MaterialDef#getDefaultTechniques() default techniques} is
- * used.
- * <p>
- * If a {@link #setForcedRenderState(com.jme3.material.RenderState) forced
- * render state} is set on this RenderManager, then it is used
- * for rendering the material, and the material's own render state is ignored.
- * Otherwise, the material's render state is used as intended.
- *
- * @param g The geometry to render
- *
- * @see Technique
- * @see RenderState
- * @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
- * @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager)
- */
- public void renderGeometry(Geometry g) {
- if (g.isIgnoreTransform()) {
- setWorldMatrix(Matrix4f.IDENTITY);
- } else {
- setWorldMatrix(g.getWorldMatrix());
- }
-
- //if forcedTechnique we try to force it for render,
- //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
- //else the geom is not rendered
- if (forcedTechnique != null) {
- if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
- tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
- g.getMaterial().selectTechnique(forcedTechnique, this);
- // use geometry's material
- g.getMaterial().render(g, this);
- g.getMaterial().selectTechnique(tmpTech, this);
- //Reverted this part from revision 6197
- //If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
- } else if (forcedMaterial != null) {
- // use forced material
- forcedMaterial.render(g, this);
- }
- } else if (forcedMaterial != null) {
- // use forced material
- forcedMaterial.render(g, this);
- } else {
- g.getMaterial().render(g, this);
- }
- }
-
- /**
- * Renders the given GeometryList.
- * <p>
- * For every geometry in the list, the
- * {@link #renderGeometry(com.jme3.scene.Geometry) } method is called.
- *
- * @param gl The geometry list to render.
- *
- * @see GeometryList
- * @see #renderGeometry(com.jme3.scene.Geometry)
- */
- public void renderGeometryList(GeometryList gl) {
- for (int i = 0; i < gl.size(); i++) {
- renderGeometry(gl.get(i));
- }
- }
-
- /**
- * If a spatial is not inside the eye frustum, it
- * is still rendered in the shadow frustum (shadow casting queue)
- * through this recursive method.
- */
- private void renderShadow(Spatial s, RenderQueue rq) {
- if (s instanceof Node) {
- Node n = (Node) s;
- List<Spatial> children = n.getChildren();
- for (int i = 0; i < children.size(); i++) {
- renderShadow(children.get(i), rq);
- }
- } else if (s instanceof Geometry) {
- Geometry gm = (Geometry) s;
-
- RenderQueue.ShadowMode shadowMode = s.getShadowMode();
- if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive) {
- //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
- rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
- }
- }
- }
-
- /**
- * Preloads a scene for rendering.
- * <p>
- * After invocation of this method, the underlying
- * renderer would have uploaded any textures, shaders and meshes
- * used by the given scene to the video driver.
- * Using this method is useful when wishing to avoid the initial pause
- * when rendering a scene for the first time. Note that it is not
- * guaranteed that the underlying renderer will actually choose to upload
- * the data to the GPU so some pause is still to be expected.
- *
- * @param scene The scene to preload
- */
- public void preloadScene(Spatial scene) {
- if (scene instanceof Node) {
- // recurse for all children
- Node n = (Node) scene;
- List<Spatial> children = n.getChildren();
- for (int i = 0; i < children.size(); i++) {
- preloadScene(children.get(i));
- }
- } else if (scene instanceof Geometry) {
- // add to the render queue
- Geometry gm = (Geometry) scene;
- if (gm.getMaterial() == null) {
- throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
- }
-
- gm.getMaterial().preload(this);
- Mesh mesh = gm.getMesh();
- if (mesh != null) {
- for (Entry<VertexBuffer> entry : mesh.getBuffers()) {
- VertexBuffer buf = entry.getValue();
- if (buf.getData() != null) {
- renderer.updateBufferData(buf);
- }
- }
- }
- }
- }
-
- /**
- * Flattens the given scene graph into the ViewPort's RenderQueue,
- * checking for culling as the call goes down the graph recursively.
- * <p>
- * First, the scene is checked for culling based on the <code>Spatial</code>s
- * {@link Spatial#setCullHint(com.jme3.scene.Spatial.CullHint) cull hint},
- * if the camera frustum contains the scene, then this method is recursively
- * called on its children.
- * <p>
- * When the scene's leaves or {@link Geometry geometries} are reached,
- * they are each enqueued into the
- * {@link ViewPort#getQueue() ViewPort's render queue}.
- * <p>
- * In addition to enqueuing the visible geometries, this method
- * also scenes which cast or receive shadows, by putting them into the
- * RenderQueue's
- * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
- * shadow queue}. Each Spatial which has its
- * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
- * set to not off, will be put into the appropriate shadow queue, note that
- * this process does not check for frustum culling on any
- * {@link ShadowMode#Cast shadow casters}, as they don't have to be
- * in the eye camera frustum to cast shadows on objects that are inside it.
- *
- * @param scene The scene to flatten into the queue
- * @param vp The ViewPort provides the {@link ViewPort#getCamera() camera}
- * used for culling and the {@link ViewPort#getQueue() queue} used to
- * contain the flattened scene graph.
- */
- public void renderScene(Spatial scene, ViewPort vp) {
- if (scene.getParent() == null) {
- vp.getCamera().setPlaneState(0);
- }
- // check culling first.
- if (!scene.checkCulling(vp.getCamera())) {
- // move on to shadow-only render
- if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint()!=Spatial.CullHint.Always) {
- renderShadow(scene, vp.getQueue());
- }
- return;
- }
-
- scene.runControlRender(this, vp);
- if (scene instanceof Node) {
- // recurse for all children
- Node n = (Node) scene;
- List<Spatial> children = n.getChildren();
- //saving cam state for culling
- int camState = vp.getCamera().getPlaneState();
- for (int i = 0; i < children.size(); i++) {
- //restoring cam state before proceeding children recusively
- vp.getCamera().setPlaneState(camState);
- renderScene(children.get(i), vp);
-
- }
- } else if (scene instanceof Geometry) {
-
- // add to the render queue
- Geometry gm = (Geometry) scene;
- if (gm.getMaterial() == null) {
- throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
- }
-
- vp.getQueue().addToQueue(gm, scene.getQueueBucket());
-
- // add to shadow queue if needed
- RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
- if (shadowMode != RenderQueue.ShadowMode.Off) {
- vp.getQueue().addToShadowQueue(gm, shadowMode);
- }
- }
- }
-
- /**
- * Returns the camera currently used for rendering.
- * <p>
- * The camera can be set with {@link #setCamera(com.jme3.renderer.Camera, boolean) }.
- *
- * @return the camera currently used for rendering.
- */
- public Camera getCurrentCamera() {
- return prevCam;
- }
-
- /**
- * The renderer implementation used for rendering operations.
- *
- * @return The renderer implementation
- *
- * @see #RenderManager(com.jme3.renderer.Renderer)
- * @see Renderer
- */
- public Renderer getRenderer() {
- return renderer;
- }
-
- /**
- * Flushes the ViewPort's {@link ViewPort#getQueue() render queue}
- * by rendering each of its visible buckets.
- * By default the queues will automatically be cleared after rendering,
- * so there's no need to clear them manually.
- *
- * @param vp The ViewPort of which the queue will be flushed
- *
- * @see RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera)
- * @see #renderGeometryList(com.jme3.renderer.queue.GeometryList)
- */
- public void flushQueue(ViewPort vp) {
- renderViewPortQueues(vp, true);
- }
-
- /**
- * Clears the queue of the given ViewPort.
- * Simply calls {@link RenderQueue#clear() } on the ViewPort's
- * {@link ViewPort#getQueue() render queue}.
- *
- * @param vp The ViewPort of which the queue will be cleared.
- *
- * @see RenderQueue#clear()
- * @see ViewPort#getQueue()
- */
- public void clearQueue(ViewPort vp) {
- vp.getQueue().clear();
- }
-
- /**
- * Render the given viewport queues.
- * <p>
- * Changes the {@link Renderer#setDepthRange(float, float) depth range}
- * appropriately as expected by each queue and then calls
- * {@link RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) }
- * on the queue. Makes sure to restore the depth range to [0, 1]
- * at the end of the call.
- * Note that the {@link Bucket#Translucent translucent bucket} is NOT
- * rendered by this method. Instead the user should call
- * {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }
- * after this call.
- *
- * @param vp the viewport of which queue should be rendered
- * @param flush If true, the queues will be cleared after
- * rendering.
- *
- * @see RenderQueue
- * @see #renderTranslucentQueue(com.jme3.renderer.ViewPort)
- */
- public void renderViewPortQueues(ViewPort vp, boolean flush) {
- RenderQueue rq = vp.getQueue();
- Camera cam = vp.getCamera();
- boolean depthRangeChanged = false;
-
- // render opaque objects with default depth range
- // opaque objects are sorted front-to-back, reducing overdraw
- rq.renderQueue(Bucket.Opaque, this, cam, flush);
-
- // render the sky, with depth range set to the farthest
- if (!rq.isQueueEmpty(Bucket.Sky)) {
- renderer.setDepthRange(1, 1);
- rq.renderQueue(Bucket.Sky, this, cam, flush);
- depthRangeChanged = true;
- }
-
-
- // transparent objects are last because they require blending with the
- // rest of the scene's objects. Consequently, they are sorted
- // back-to-front.
- if (!rq.isQueueEmpty(Bucket.Transparent)) {
- if (depthRangeChanged) {
- renderer.setDepthRange(0, 1);
- depthRangeChanged = false;
- }
-
- rq.renderQueue(Bucket.Transparent, this, cam, flush);
- }
-
- if (!rq.isQueueEmpty(Bucket.Gui)) {
- renderer.setDepthRange(0, 0);
- setCamera(cam, true);
- rq.renderQueue(Bucket.Gui, this, cam, flush);
- setCamera(cam, false);
- depthRangeChanged = true;
- }
-
- // restore range to default
- if (depthRangeChanged) {
- renderer.setDepthRange(0, 1);
- }
- }
-
- /**
- * Renders the {@link Bucket#Translucent translucent queue} on the viewPort.
- * <p>
- * This call does nothing unless {@link #setHandleTranslucentBucket(boolean) }
- * is set to true. This method clears the translucent queue after rendering
- * it.
- *
- * @param vp The viewport of which the translucent queue should be rendered.
- *
- * @see #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean)
- * @see #setHandleTranslucentBucket(boolean)
- */
- public void renderTranslucentQueue(ViewPort vp) {
- RenderQueue rq = vp.getQueue();
- if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
- rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
- }
- }
-
- private void setViewPort(Camera cam) {
- // this will make sure to update viewport only if needed
- if (cam != prevCam || cam.isViewportChanged()) {
- viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
- viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
- viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
- viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
- renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
- renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
- cam.clearViewportChanged();
- prevCam = cam;
-
-// float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
-// float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
-// float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
-// float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
-//
-// orthoMatrix.loadIdentity();
-// orthoMatrix.setTranslation(translateX, translateY, 0);
-// orthoMatrix.setScale(scaleX, scaleY, 0);
-
- orthoMatrix.loadIdentity();
- orthoMatrix.setTranslation(-1f, -1f, 0f);
- orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
- }
- }
-
- private void setViewProjection(Camera cam, boolean ortho) {
- if (shader) {
- if (ortho) {
- viewMatrix.set(Matrix4f.IDENTITY);
- projMatrix.set(orthoMatrix);
- viewProjMatrix.set(orthoMatrix);
- } else {
- viewMatrix.set(cam.getViewMatrix());
- projMatrix.set(cam.getProjectionMatrix());
- viewProjMatrix.set(cam.getViewProjectionMatrix());
- }
-
- camLoc.set(cam.getLocation());
- cam.getLeft(camLeft);
- cam.getUp(camUp);
- cam.getDirection(camDir);
-
- near = cam.getFrustumNear();
- far = cam.getFrustumFar();
- } else {
- if (ortho) {
- renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
- } else {
- renderer.setViewProjectionMatrices(cam.getViewMatrix(),
- cam.getProjectionMatrix());
- }
-
- }
- }
-
- /**
- * Set the camera to use for rendering.
- * <p>
- * First, the camera's
- * {@link Camera#setViewPort(float, float, float, float) view port parameters}
- * are applied. Then, the camera's {@link Camera#getViewMatrix() view} and
- * {@link Camera#getProjectionMatrix() projection} matrices are set
- * on the renderer. If <code>ortho</code> is <code>true</code>, then
- * instead of using the camera's view and projection matrices, an ortho
- * matrix is computed and used instead of the view projection matrix.
- * The ortho matrix converts from the range (0 ~ Width, 0 ~ Height, -1 ~ +1)
- * to the clip range (-1 ~ +1, -1 ~ +1, -1 ~ +1).
- *
- * @param cam The camera to set
- * @param ortho True if to use orthographic projection (for GUI rendering),
- * false if to use the camera's view and projection matrices.
- */
- public void setCamera(Camera cam, boolean ortho) {
- setViewPort(cam);
- setViewProjection(cam, ortho);
- }
-
- /**
- * Draws the viewport but without notifying {@link SceneProcessor scene
- * processors} of any rendering events.
- *
- * @param vp The ViewPort to render
- *
- * @see #renderViewPort(com.jme3.renderer.ViewPort, float)
- */
- public void renderViewPortRaw(ViewPort vp) {
- setCamera(vp.getCamera(), false);
- List<Spatial> scenes = vp.getScenes();
- for (int i = scenes.size() - 1; i >= 0; i--) {
- renderScene(scenes.get(i), vp);
- }
- flushQueue(vp);
- }
-
- /**
- * Renders the {@link ViewPort}.
- * <p>
- * If the ViewPort is {@link ViewPort#isEnabled() disabled}, this method
- * returns immediately. Otherwise, the ViewPort is rendered by
- * the following process:<br>
- * <ul>
- * <li>All {@link SceneProcessor scene processors} that are attached
- * to the ViewPort are {@link SceneProcessor#initialize(com.jme3.renderer.RenderManager, com.jme3.renderer.ViewPort) initialized}.
- * </li>
- * <li>The SceneProcessors' {@link SceneProcessor#preFrame(float) } method
- * is called.</li>
- * <li>The ViewPort's {@link ViewPort#getOutputFrameBuffer() output framebuffer}
- * is set on the Renderer</li>
- * <li>The camera is set on the renderer, including its view port parameters.
- * (see {@link #setCamera(com.jme3.renderer.Camera, boolean) })</li>
- * <li>Any buffers that the ViewPort requests to be cleared are cleared
- * and the {@link ViewPort#getBackgroundColor() background color} is set</li>
- * <li>Every scene that is attached to the ViewPort is flattened into
- * the ViewPort's render queue
- * (see {@link #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) })
- * </li>
- * <li>The SceneProcessors' {@link SceneProcessor#postQueue(com.jme3.renderer.queue.RenderQueue) }
- * method is called.</li>
- * <li>The render queue is sorted and then flushed, sending
- * rendering commands to the underlying Renderer implementation.
- * (see {@link #flushQueue(com.jme3.renderer.ViewPort) })</li>
- * <li>The SceneProcessors' {@link SceneProcessor#postFrame(com.jme3.texture.FrameBuffer) }
- * method is called.</li>
- * <li>The translucent queue of the ViewPort is sorted and then flushed
- * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
- * <li>If any objects remained in the render queue, they are removed
- * from the queue. This is generally objects added to the
- * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
- * shadow queue}
- * which were not rendered because of a missing shadow renderer.</li>
- * </ul>
- *
- * @param vp
- * @param tpf
- */
- public void renderViewPort(ViewPort vp, float tpf) {
- if (!vp.isEnabled()) {
- return;
- }
- List<SceneProcessor> processors = vp.getProcessors();
- if (processors.isEmpty()) {
- processors = null;
- }
-
- if (processors != null) {
- for (SceneProcessor proc : processors) {
- if (!proc.isInitialized()) {
- proc.initialize(this, vp);
- }
- proc.preFrame(tpf);
- }
- }
-
- renderer.setFrameBuffer(vp.getOutputFrameBuffer());
- setCamera(vp.getCamera(), false);
- if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
- if (vp.isClearColor()) {
- renderer.setBackgroundColor(vp.getBackgroundColor());
- }
- renderer.clearBuffers(vp.isClearColor(),
- vp.isClearDepth(),
- vp.isClearStencil());
- }
-
- List<Spatial> scenes = vp.getScenes();
- for (int i = scenes.size() - 1; i >= 0; i--) {
- renderScene(scenes.get(i), vp);
- }
-
- if (processors != null) {
- for (SceneProcessor proc : processors) {
- proc.postQueue(vp.getQueue());
- }
- }
-
- flushQueue(vp);
-
- if (processors != null) {
- for (SceneProcessor proc : processors) {
- proc.postFrame(vp.getOutputFrameBuffer());
- }
- }
- //renders the translucent objects queue after processors have been rendered
- renderTranslucentQueue(vp);
- // clear any remaining spatials that were not rendered.
- clearQueue(vp);
- }
-
- /**
- * Called by the application to render any ViewPorts
- * added to this RenderManager.
- * <p>
- * Renders any viewports that were added using the following methods:
- * <ul>
- * <li>{@link #createPreView(java.lang.String, com.jme3.renderer.Camera) }</li>
- * <li>{@link #createMainView(java.lang.String, com.jme3.renderer.Camera) }</li>
- * <li>{@link #createPostView(java.lang.String, com.jme3.renderer.Camera) }</li>
- * </ul>
- *
- * @param tpf Time per frame value
- */
- public void render(float tpf, boolean mainFrameBufferActive) {
- if (renderer instanceof NullRenderer) {
- return;
- }
-
- this.shader = renderer.getCaps().contains(Caps.GLSL100);
-
- for (int i = 0; i < preViewPorts.size(); i++) {
- ViewPort vp = preViewPorts.get(i);
- if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
- renderViewPort(vp, tpf);
- }
- }
- for (int i = 0; i < viewPorts.size(); i++) {
- ViewPort vp = viewPorts.get(i);
- if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
- renderViewPort(vp, tpf);
- }
- }
- for (int i = 0; i < postViewPorts.size(); i++) {
- ViewPort vp = postViewPorts.get(i);
- if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
- renderViewPort(vp, tpf);
- }
- }
- }
-}
+/*
+ * 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.renderer;
+
+import com.jme3.material.Material;
+import com.jme3.material.MaterialDef;
+import com.jme3.material.RenderState;
+import com.jme3.material.Technique;
+import com.jme3.math.*;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.queue.GeometryList;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.renderer.queue.RenderQueue.Bucket;
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;
+import com.jme3.scene.*;
+import com.jme3.shader.Uniform;
+import com.jme3.shader.UniformBinding;
+import com.jme3.shader.VarType;
+import com.jme3.system.NullRenderer;
+import com.jme3.system.Timer;
+import com.jme3.util.IntMap.Entry;
+import com.jme3.util.TempVars;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * <code>RenderManager</code> is a high-level rendering interface that is
+ * above the Renderer implementation. RenderManager takes care
+ * of rendering the scene graphs attached to each viewport and
+ * handling SceneProcessors.
+ *
+ * @see SceneProcessor
+ * @see ViewPort
+ * @see Spatial
+ */
+public class RenderManager {
+
+ private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
+
+ private Renderer renderer;
+ private Timer timer;
+ private ArrayList<ViewPort> preViewPorts = new ArrayList<ViewPort>();
+ private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
+ private ArrayList<ViewPort> postViewPorts = new ArrayList<ViewPort>();
+ private Camera prevCam = null;
+ private Material forcedMaterial = null;
+ private String forcedTechnique = null;
+ private RenderState forcedRenderState = null;
+ private boolean shader;
+ private int viewX, viewY, viewWidth, viewHeight;
+ private float near, far;
+ private Matrix4f orthoMatrix = new Matrix4f();
+ private Matrix4f viewMatrix = new Matrix4f();
+ private Matrix4f projMatrix = new Matrix4f();
+ private Matrix4f viewProjMatrix = new Matrix4f();
+ private Matrix4f worldMatrix = new Matrix4f();
+ private Vector3f camUp = new Vector3f(),
+ camLeft = new Vector3f(),
+ camDir = new Vector3f(),
+ camLoc = new Vector3f();
+ //temp technique
+ private String tmpTech;
+ private boolean handleTranlucentBucket = true;
+
+ /**
+ * Create a high-level rendering interface over the
+ * low-level rendering interface.
+ * @param renderer
+ */
+ public RenderManager(Renderer renderer) {
+ this.renderer = renderer;
+ //this.shader = renderer.getCaps().contains(Caps.GLSL100);
+ }
+
+ /**
+ * Returns the pre ViewPort with the given name.
+ *
+ * @param viewName The name of the pre ViewPort to look up
+ * @return The ViewPort, or null if not found.
+ *
+ * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public ViewPort getPreView(String viewName) {
+ for (int i = 0; i < preViewPorts.size(); i++) {
+ if (preViewPorts.get(i).getName().equals(viewName)) {
+ return preViewPorts.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes the specified pre ViewPort.
+ *
+ * @param view The pre ViewPort to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public boolean removePreView(ViewPort view) {
+ return preViewPorts.remove(view);
+ }
+
+ /**
+ * Returns the main ViewPort with the given name.
+ *
+ * @param viewName The name of the main ViewPort to look up
+ * @return The ViewPort, or null if not found.
+ *
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public ViewPort getMainView(String viewName) {
+ for (int i = 0; i < viewPorts.size(); i++) {
+ if (viewPorts.get(i).getName().equals(viewName)) {
+ return viewPorts.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes the main ViewPort with the specified name.
+ *
+ * @param viewName The main ViewPort name to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public boolean removeMainView(String viewName) {
+ for (int i = 0; i < viewPorts.size(); i++) {
+ if (viewPorts.get(i).getName().equals(viewName)) {
+ viewPorts.remove(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the specified main ViewPort.
+ *
+ * @param view The main ViewPort to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public boolean removeMainView(ViewPort view) {
+ return viewPorts.remove(view);
+ }
+
+ /**
+ * Returns the post ViewPort with the given name.
+ *
+ * @param viewName The name of the post ViewPort to look up
+ * @return The ViewPort, or null if not found.
+ *
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public ViewPort getPostView(String viewName) {
+ for (int i = 0; i < postViewPorts.size(); i++) {
+ if (postViewPorts.get(i).getName().equals(viewName)) {
+ return postViewPorts.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes the post ViewPort with the specified name.
+ *
+ * @param viewName The post ViewPort name to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public boolean removePostView(String viewName) {
+ for (int i = 0; i < postViewPorts.size(); i++) {
+ if (postViewPorts.get(i).getName().equals(viewName)) {
+ postViewPorts.remove(i);
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the specified post ViewPort.
+ *
+ * @param view The post ViewPort to remove
+ * @return True if the ViewPort was removed successfully.
+ *
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public boolean removePostView(ViewPort view) {
+ return postViewPorts.remove(view);
+ }
+
+ /**
+ * Returns a read-only list of all pre ViewPorts
+ * @return a read-only list of all pre ViewPorts
+ * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public List<ViewPort> getPreViews() {
+ return Collections.unmodifiableList(preViewPorts);
+ }
+
+ /**
+ * Returns a read-only list of all main ViewPorts
+ * @return a read-only list of all main ViewPorts
+ * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public List<ViewPort> getMainViews() {
+ return Collections.unmodifiableList(viewPorts);
+ }
+
+ /**
+ * Returns a read-only list of all post ViewPorts
+ * @return a read-only list of all post ViewPorts
+ * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
+ */
+ public List<ViewPort> getPostViews() {
+ return Collections.unmodifiableList(postViewPorts);
+ }
+
+ /**
+ * Creates a new pre ViewPort, to display the given camera's content.
+ * <p>
+ * The view will be processed before the main and post viewports.
+ */
+ public ViewPort createPreView(String viewName, Camera cam) {
+ ViewPort vp = new ViewPort(viewName, cam);
+ preViewPorts.add(vp);
+ return vp;
+ }
+
+ /**
+ * Creates a new main ViewPort, to display the given camera's content.
+ * <p>
+ * The view will be processed before the post viewports but after
+ * the pre viewports.
+ */
+ public ViewPort createMainView(String viewName, Camera cam) {
+ ViewPort vp = new ViewPort(viewName, cam);
+ viewPorts.add(vp);
+ return vp;
+ }
+
+ /**
+ * Creates a new post ViewPort, to display the given camera's content.
+ * <p>
+ * The view will be processed after the pre and main viewports.
+ */
+ public ViewPort createPostView(String viewName, Camera cam) {
+ ViewPort vp = new ViewPort(viewName, cam);
+ postViewPorts.add(vp);
+ return vp;
+ }
+
+ private void notifyReshape(ViewPort vp, int w, int h) {
+ List<SceneProcessor> processors = vp.getProcessors();
+ for (SceneProcessor proc : processors) {
+ if (!proc.isInitialized()) {
+ proc.initialize(this, vp);
+ } else {
+ proc.reshape(vp, w, h);
+ }
+ }
+ }
+
+ /**
+ * Internal use only.
+ * Updates the resolution of all on-screen cameras to match
+ * the given width and height.
+ */
+ public void notifyReshape(int w, int h) {
+ for (ViewPort vp : preViewPorts) {
+ if (vp.getOutputFrameBuffer() == null) {
+ Camera cam = vp.getCamera();
+ cam.resize(w, h, true);
+ }
+ notifyReshape(vp, w, h);
+ }
+ for (ViewPort vp : viewPorts) {
+ if (vp.getOutputFrameBuffer() == null) {
+ Camera cam = vp.getCamera();
+ cam.resize(w, h, true);
+ }
+ notifyReshape(vp, w, h);
+ }
+ for (ViewPort vp : postViewPorts) {
+ if (vp.getOutputFrameBuffer() == null) {
+ Camera cam = vp.getCamera();
+ cam.resize(w, h, true);
+ }
+ notifyReshape(vp, w, h);
+ }
+ }
+
+ /**
+ * Internal use only.
+ * Updates the given list of uniforms with {@link UniformBinding uniform bindings}
+ * based on the current world state.
+ */
+ public void updateUniformBindings(List<Uniform> params) {
+ // assums worldMatrix is properly set.
+ TempVars vars = TempVars.get();
+
+ Matrix4f tempMat4 = vars.tempMat4;
+ Matrix3f tempMat3 = vars.tempMat3;
+ Vector2f tempVec2 = vars.vect2d;
+ Quaternion tempVec4 = vars.quat1;
+
+ for (int i = 0; i < params.size(); i++) {
+ Uniform u = params.get(i);
+ switch (u.getBinding()) {
+ case WorldMatrix:
+ u.setValue(VarType.Matrix4, worldMatrix);
+ break;
+ case ViewMatrix:
+ u.setValue(VarType.Matrix4, viewMatrix);
+ break;
+ case ProjectionMatrix:
+ u.setValue(VarType.Matrix4, projMatrix);
+ break;
+ case ViewProjectionMatrix:
+ u.setValue(VarType.Matrix4, viewProjMatrix);
+ break;
+ case WorldViewMatrix:
+ tempMat4.set(viewMatrix);
+ tempMat4.multLocal(worldMatrix);
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case NormalMatrix:
+ tempMat4.set(viewMatrix);
+ tempMat4.multLocal(worldMatrix);
+ tempMat4.toRotationMatrix(tempMat3);
+ tempMat3.invertLocal();
+ tempMat3.transposeLocal();
+ u.setValue(VarType.Matrix3, tempMat3);
+ break;
+ case WorldViewProjectionMatrix:
+ tempMat4.set(viewProjMatrix);
+ tempMat4.multLocal(worldMatrix);
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case WorldMatrixInverse:
+ tempMat4.set(worldMatrix);
+ tempMat4.invertLocal();
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case WorldMatrixInverseTranspose:
+ worldMatrix.toRotationMatrix(tempMat3);
+ tempMat3.invertLocal().transposeLocal();
+ u.setValue(VarType.Matrix3, tempMat3);
+ break;
+ case ViewMatrixInverse:
+ tempMat4.set(viewMatrix);
+ tempMat4.invertLocal();
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case ProjectionMatrixInverse:
+ tempMat4.set(projMatrix);
+ tempMat4.invertLocal();
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case ViewProjectionMatrixInverse:
+ tempMat4.set(viewProjMatrix);
+ tempMat4.invertLocal();
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case WorldViewMatrixInverse:
+ tempMat4.set(viewMatrix);
+ tempMat4.multLocal(worldMatrix);
+ tempMat4.invertLocal();
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case NormalMatrixInverse:
+ tempMat4.set(viewMatrix);
+ tempMat4.multLocal(worldMatrix);
+ tempMat4.toRotationMatrix(tempMat3);
+ tempMat3.invertLocal();
+ tempMat3.transposeLocal();
+ tempMat3.invertLocal();
+ u.setValue(VarType.Matrix3, tempMat3);
+ break;
+ case WorldViewProjectionMatrixInverse:
+ tempMat4.set(viewProjMatrix);
+ tempMat4.multLocal(worldMatrix);
+ tempMat4.invertLocal();
+ u.setValue(VarType.Matrix4, tempMat4);
+ break;
+ case ViewPort:
+ tempVec4.set(viewX, viewY, viewWidth, viewHeight);
+ u.setValue(VarType.Vector4, tempVec4);
+ break;
+ case Resolution:
+ tempVec2.set(viewWidth, viewHeight);
+ u.setValue(VarType.Vector2, tempVec2);
+ break;
+ case ResolutionInverse:
+ tempVec2.set(1f / viewWidth, 1f / viewHeight);
+ u.setValue(VarType.Vector2, tempVec2);
+ break;
+ case Aspect:
+ float aspect = ((float) viewWidth) / viewHeight;
+ u.setValue(VarType.Float, aspect);
+ break;
+ case FrustumNearFar:
+ tempVec2.set(near, far);
+ u.setValue(VarType.Vector2, tempVec2);
+ break;
+ case CameraPosition:
+ u.setValue(VarType.Vector3, camLoc);
+ break;
+ case CameraDirection:
+ u.setValue(VarType.Vector3, camDir);
+ break;
+ case CameraLeft:
+ u.setValue(VarType.Vector3, camLeft);
+ break;
+ case CameraUp:
+ u.setValue(VarType.Vector3, camUp);
+ break;
+ case Time:
+ u.setValue(VarType.Float, timer.getTimeInSeconds());
+ break;
+ case Tpf:
+ u.setValue(VarType.Float, timer.getTimePerFrame());
+ break;
+ case FrameRate:
+ u.setValue(VarType.Float, timer.getFrameRate());
+ break;
+ }
+ }
+
+ vars.release();
+ }
+
+ /**
+ * Set the material to use to render all future objects.
+ * This overrides the material set on the geometry and renders
+ * with the provided material instead.
+ * Use null to clear the material and return renderer to normal
+ * functionality.
+ * @param mat The forced material to set, or null to return to normal
+ */
+ public void setForcedMaterial(Material mat) {
+ forcedMaterial = mat;
+ }
+
+ /**
+ * Returns the forced render state previously set with
+ * {@link #setForcedRenderState(com.jme3.material.RenderState) }.
+ * @return the forced render state
+ */
+ public RenderState getForcedRenderState() {
+ return forcedRenderState;
+ }
+
+ /**
+ * Set the render state to use for all future objects.
+ * This overrides the render state set on the material and instead
+ * forces this render state to be applied for all future materials
+ * rendered. Set to null to return to normal functionality.
+ *
+ * @param forcedRenderState The forced render state to set, or null
+ * to return to normal
+ */
+ public void setForcedRenderState(RenderState forcedRenderState) {
+ this.forcedRenderState = forcedRenderState;
+ }
+
+ /**
+ * Set the timer that should be used to query the time based
+ * {@link UniformBinding}s for material world parameters.
+ *
+ * @param timer The timer to query time world parameters
+ */
+ public void setTimer(Timer timer) {
+ this.timer = timer;
+ }
+
+ /**
+ * Returns the forced technique name set.
+ *
+ * @return the forced technique name set.
+ *
+ * @see #setForcedTechnique(java.lang.String)
+ */
+ public String getForcedTechnique() {
+ return forcedTechnique;
+ }
+
+ /**
+ * Sets the forced technique to use when rendering geometries.
+ * <p>
+ * If the specified technique name is available on the geometry's
+ * material, then it is used, otherwise, the
+ * {@link #setForcedMaterial(com.jme3.material.Material) forced material} is used.
+ * If a forced material is not set and the forced technique name cannot
+ * be found on the material, the geometry will <em>not</em> be rendered.
+ *
+ * @param forcedTechnique The forced technique name to use, set to null
+ * to return to normal functionality.
+ *
+ * @see #renderGeometry(com.jme3.scene.Geometry)
+ */
+ public void setForcedTechnique(String forcedTechnique) {
+ this.forcedTechnique = forcedTechnique;
+ }
+
+ /**
+ * Enable or disable alpha-to-coverage.
+ * <p>
+ * When alpha to coverage is enabled and the renderer implementation
+ * supports it, then alpha blending will be replaced with alpha dissolve
+ * if multi-sampling is also set on the renderer.
+ * This feature allows avoiding of alpha blending artifacts due to
+ * lack of triangle-level back-to-front sorting.
+ *
+ * @param value True to enable alpha-to-coverage, false otherwise.
+ */
+ public void setAlphaToCoverage(boolean value) {
+ renderer.setAlphaToCoverage(value);
+ }
+
+ /**
+ * True if the translucent bucket should automatically be rendered
+ * by the RenderManager.
+ *
+ * @return Whether or not the translucent bucket is rendered.
+ *
+ * @see #setHandleTranslucentBucket(boolean)
+ */
+ public boolean isHandleTranslucentBucket() {
+ return handleTranlucentBucket;
+ }
+
+ /**
+ * Enable or disable rendering of the
+ * {@link Bucket#Translucent translucent bucket}
+ * by the RenderManager. The default is enabled.
+ *
+ * @param handleTranslucentBucket Whether or not the translucent bucket should
+ * be rendered.
+ */
+ public void setHandleTranslucentBucket(boolean handleTranslucentBucket) {
+ this.handleTranlucentBucket = handleTranslucentBucket;
+ }
+
+ /**
+ * Internal use only. Sets the world matrix to use for future
+ * rendering. This has no effect unless objects are rendered manually
+ * using {@link Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) }.
+ * Using {@link #renderGeometry(com.jme3.scene.Geometry) } will
+ * override this value.
+ *
+ * @param mat The world matrix to set
+ */
+ public void setWorldMatrix(Matrix4f mat) {
+ if (shader) {
+ worldMatrix.set(mat);
+ } else {
+ renderer.setWorldMatrix(mat);
+ }
+ }
+
+ /**
+ * Renders the given geometry.
+ * <p>
+ * First the proper world matrix is set, if
+ * the geometry's {@link Geometry#setIgnoreTransform(boolean) ignore transform}
+ * feature is enabled, the identity world matrix is used, otherwise, the
+ * geometry's {@link Geometry#getWorldMatrix() world transform matrix} is used.
+ * <p>
+ * Once the world matrix is applied, the proper material is chosen for rendering.
+ * If a {@link #setForcedMaterial(com.jme3.material.Material) forced material} is
+ * set on this RenderManager, then it is used for rendering the geometry,
+ * otherwise, the {@link Geometry#getMaterial() geometry's material} is used.
+ * <p>
+ * If a {@link #setForcedTechnique(java.lang.String) forced technique} is
+ * set on this RenderManager, then it is selected automatically
+ * on the geometry's material and is used for rendering. Otherwise, one
+ * of the {@link MaterialDef#getDefaultTechniques() default techniques} is
+ * used.
+ * <p>
+ * If a {@link #setForcedRenderState(com.jme3.material.RenderState) forced
+ * render state} is set on this RenderManager, then it is used
+ * for rendering the material, and the material's own render state is ignored.
+ * Otherwise, the material's render state is used as intended.
+ *
+ * @param g The geometry to render
+ *
+ * @see Technique
+ * @see RenderState
+ * @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
+ * @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager)
+ */
+ public void renderGeometry(Geometry g) {
+ if (g.isIgnoreTransform()) {
+ setWorldMatrix(Matrix4f.IDENTITY);
+ } else {
+ setWorldMatrix(g.getWorldMatrix());
+ }
+
+ //if forcedTechnique we try to force it for render,
+ //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
+ //else the geom is not rendered
+ if (forcedTechnique != null) {
+ if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
+ tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
+ g.getMaterial().selectTechnique(forcedTechnique, this);
+ // use geometry's material
+ g.getMaterial().render(g, this);
+ g.getMaterial().selectTechnique(tmpTech, this);
+ //Reverted this part from revision 6197
+ //If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
+ } else if (forcedMaterial != null) {
+ // use forced material
+ forcedMaterial.render(g, this);
+ }
+ } else if (forcedMaterial != null) {
+ // use forced material
+ forcedMaterial.render(g, this);
+ } else {
+ g.getMaterial().render(g, this);
+ }
+ }
+
+ /**
+ * Renders the given GeometryList.
+ * <p>
+ * For every geometry in the list, the
+ * {@link #renderGeometry(com.jme3.scene.Geometry) } method is called.
+ *
+ * @param gl The geometry list to render.
+ *
+ * @see GeometryList
+ * @see #renderGeometry(com.jme3.scene.Geometry)
+ */
+ public void renderGeometryList(GeometryList gl) {
+ for (int i = 0; i < gl.size(); i++) {
+ renderGeometry(gl.get(i));
+ }
+ }
+
+ /**
+ * If a spatial is not inside the eye frustum, it
+ * is still rendered in the shadow frustum (shadow casting queue)
+ * through this recursive method.
+ */
+ private void renderShadow(Spatial s, RenderQueue rq) {
+ if (s instanceof Node) {
+ Node n = (Node) s;
+ List<Spatial> children = n.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ renderShadow(children.get(i), rq);
+ }
+ } else if (s instanceof Geometry) {
+ Geometry gm = (Geometry) s;
+
+ RenderQueue.ShadowMode shadowMode = s.getShadowMode();
+ if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive) {
+ //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
+ rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
+ }
+ }
+ }
+
+ /**
+ * Preloads a scene for rendering.
+ * <p>
+ * After invocation of this method, the underlying
+ * renderer would have uploaded any textures, shaders and meshes
+ * used by the given scene to the video driver.
+ * Using this method is useful when wishing to avoid the initial pause
+ * when rendering a scene for the first time. Note that it is not
+ * guaranteed that the underlying renderer will actually choose to upload
+ * the data to the GPU so some pause is still to be expected.
+ *
+ * @param scene The scene to preload
+ */
+ public void preloadScene(Spatial scene) {
+ if (scene instanceof Node) {
+ // recurse for all children
+ Node n = (Node) scene;
+ List<Spatial> children = n.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ preloadScene(children.get(i));
+ }
+ } else if (scene instanceof Geometry) {
+ // add to the render queue
+ Geometry gm = (Geometry) scene;
+ if (gm.getMaterial() == null) {
+ throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
+ }
+
+ gm.getMaterial().preload(this);
+ Mesh mesh = gm.getMesh();
+ if (mesh != null) {
+ for (VertexBuffer vb : mesh.getBufferList().getArray()) {
+ if (vb.getData() != null) {
+ renderer.updateBufferData(vb);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Flattens the given scene graph into the ViewPort's RenderQueue,
+ * checking for culling as the call goes down the graph recursively.
+ * <p>
+ * First, the scene is checked for culling based on the <code>Spatial</code>s
+ * {@link Spatial#setCullHint(com.jme3.scene.Spatial.CullHint) cull hint},
+ * if the camera frustum contains the scene, then this method is recursively
+ * called on its children.
+ * <p>
+ * When the scene's leaves or {@link Geometry geometries} are reached,
+ * they are each enqueued into the
+ * {@link ViewPort#getQueue() ViewPort's render queue}.
+ * <p>
+ * In addition to enqueuing the visible geometries, this method
+ * also scenes which cast or receive shadows, by putting them into the
+ * RenderQueue's
+ * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
+ * shadow queue}. Each Spatial which has its
+ * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
+ * set to not off, will be put into the appropriate shadow queue, note that
+ * this process does not check for frustum culling on any
+ * {@link ShadowMode#Cast shadow casters}, as they don't have to be
+ * in the eye camera frustum to cast shadows on objects that are inside it.
+ *
+ * @param scene The scene to flatten into the queue
+ * @param vp The ViewPort provides the {@link ViewPort#getCamera() camera}
+ * used for culling and the {@link ViewPort#getQueue() queue} used to
+ * contain the flattened scene graph.
+ */
+ public void renderScene(Spatial scene, ViewPort vp) {
+ if (scene.getParent() == null) {
+ vp.getCamera().setPlaneState(0);
+ }
+ // check culling first.
+ if (!scene.checkCulling(vp.getCamera())) {
+ // move on to shadow-only render
+ if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint()!=Spatial.CullHint.Always) {
+ renderShadow(scene, vp.getQueue());
+ }
+ return;
+ }
+
+ scene.runControlRender(this, vp);
+ if (scene instanceof Node) {
+ // recurse for all children
+ Node n = (Node) scene;
+ List<Spatial> children = n.getChildren();
+ //saving cam state for culling
+ int camState = vp.getCamera().getPlaneState();
+ for (int i = 0; i < children.size(); i++) {
+ //restoring cam state before proceeding children recusively
+ vp.getCamera().setPlaneState(camState);
+ renderScene(children.get(i), vp);
+
+ }
+ } else if (scene instanceof Geometry) {
+
+ // add to the render queue
+ Geometry gm = (Geometry) scene;
+ if (gm.getMaterial() == null) {
+ throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
+ }
+
+ vp.getQueue().addToQueue(gm, scene.getQueueBucket());
+
+ // add to shadow queue if needed
+ RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
+ if (shadowMode != RenderQueue.ShadowMode.Off) {
+ vp.getQueue().addToShadowQueue(gm, shadowMode);
+ }
+ }
+ }
+
+ /**
+ * Returns the camera currently used for rendering.
+ * <p>
+ * The camera can be set with {@link #setCamera(com.jme3.renderer.Camera, boolean) }.
+ *
+ * @return the camera currently used for rendering.
+ */
+ public Camera getCurrentCamera() {
+ return prevCam;
+ }
+
+ /**
+ * The renderer implementation used for rendering operations.
+ *
+ * @return The renderer implementation
+ *
+ * @see #RenderManager(com.jme3.renderer.Renderer)
+ * @see Renderer
+ */
+ public Renderer getRenderer() {
+ return renderer;
+ }
+
+ /**
+ * Flushes the ViewPort's {@link ViewPort#getQueue() render queue}
+ * by rendering each of its visible buckets.
+ * By default the queues will automatically be cleared after rendering,
+ * so there's no need to clear them manually.
+ *
+ * @param vp The ViewPort of which the queue will be flushed
+ *
+ * @see RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera)
+ * @see #renderGeometryList(com.jme3.renderer.queue.GeometryList)
+ */
+ public void flushQueue(ViewPort vp) {
+ renderViewPortQueues(vp, true);
+ }
+
+ /**
+ * Clears the queue of the given ViewPort.
+ * Simply calls {@link RenderQueue#clear() } on the ViewPort's
+ * {@link ViewPort#getQueue() render queue}.
+ *
+ * @param vp The ViewPort of which the queue will be cleared.
+ *
+ * @see RenderQueue#clear()
+ * @see ViewPort#getQueue()
+ */
+ public void clearQueue(ViewPort vp) {
+ vp.getQueue().clear();
+ }
+
+ /**
+ * Render the given viewport queues.
+ * <p>
+ * Changes the {@link Renderer#setDepthRange(float, float) depth range}
+ * appropriately as expected by each queue and then calls
+ * {@link RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) }
+ * on the queue. Makes sure to restore the depth range to [0, 1]
+ * at the end of the call.
+ * Note that the {@link Bucket#Translucent translucent bucket} is NOT
+ * rendered by this method. Instead the user should call
+ * {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }
+ * after this call.
+ *
+ * @param vp the viewport of which queue should be rendered
+ * @param flush If true, the queues will be cleared after
+ * rendering.
+ *
+ * @see RenderQueue
+ * @see #renderTranslucentQueue(com.jme3.renderer.ViewPort)
+ */
+ public void renderViewPortQueues(ViewPort vp, boolean flush) {
+ RenderQueue rq = vp.getQueue();
+ Camera cam = vp.getCamera();
+ boolean depthRangeChanged = false;
+
+ // render opaque objects with default depth range
+ // opaque objects are sorted front-to-back, reducing overdraw
+ rq.renderQueue(Bucket.Opaque, this, cam, flush);
+
+ // render the sky, with depth range set to the farthest
+ if (!rq.isQueueEmpty(Bucket.Sky)) {
+ renderer.setDepthRange(1, 1);
+ rq.renderQueue(Bucket.Sky, this, cam, flush);
+ depthRangeChanged = true;
+ }
+
+
+ // transparent objects are last because they require blending with the
+ // rest of the scene's objects. Consequently, they are sorted
+ // back-to-front.
+ if (!rq.isQueueEmpty(Bucket.Transparent)) {
+ if (depthRangeChanged) {
+ renderer.setDepthRange(0, 1);
+ depthRangeChanged = false;
+ }
+
+ rq.renderQueue(Bucket.Transparent, this, cam, flush);
+ }
+
+ if (!rq.isQueueEmpty(Bucket.Gui)) {
+ renderer.setDepthRange(0, 0);
+ setCamera(cam, true);
+ rq.renderQueue(Bucket.Gui, this, cam, flush);
+ setCamera(cam, false);
+ depthRangeChanged = true;
+ }
+
+ // restore range to default
+ if (depthRangeChanged) {
+ renderer.setDepthRange(0, 1);
+ }
+ }
+
+ /**
+ * Renders the {@link Bucket#Translucent translucent queue} on the viewPort.
+ * <p>
+ * This call does nothing unless {@link #setHandleTranslucentBucket(boolean) }
+ * is set to true. This method clears the translucent queue after rendering
+ * it.
+ *
+ * @param vp The viewport of which the translucent queue should be rendered.
+ *
+ * @see #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean)
+ * @see #setHandleTranslucentBucket(boolean)
+ */
+ public void renderTranslucentQueue(ViewPort vp) {
+ RenderQueue rq = vp.getQueue();
+ if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
+ rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
+ }
+ }
+
+ private void setViewPort(Camera cam) {
+ // this will make sure to update viewport only if needed
+ if (cam != prevCam || cam.isViewportChanged()) {
+ viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
+ viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
+ viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
+ viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
+ renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
+ renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
+ cam.clearViewportChanged();
+ prevCam = cam;
+
+// float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
+// float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
+// float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
+// float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
+//
+// orthoMatrix.loadIdentity();
+// orthoMatrix.setTranslation(translateX, translateY, 0);
+// orthoMatrix.setScale(scaleX, scaleY, 0);
+
+ orthoMatrix.loadIdentity();
+ orthoMatrix.setTranslation(-1f, -1f, 0f);
+ orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
+ }
+ }
+
+ private void setViewProjection(Camera cam, boolean ortho) {
+ if (shader) {
+ if (ortho) {
+ viewMatrix.set(Matrix4f.IDENTITY);
+ projMatrix.set(orthoMatrix);
+ viewProjMatrix.set(orthoMatrix);
+ } else {
+ viewMatrix.set(cam.getViewMatrix());
+ projMatrix.set(cam.getProjectionMatrix());
+ viewProjMatrix.set(cam.getViewProjectionMatrix());
+ }
+
+ camLoc.set(cam.getLocation());
+ cam.getLeft(camLeft);
+ cam.getUp(camUp);
+ cam.getDirection(camDir);
+
+ near = cam.getFrustumNear();
+ far = cam.getFrustumFar();
+ } else {
+ if (ortho) {
+ renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
+ } else {
+ renderer.setViewProjectionMatrices(cam.getViewMatrix(),
+ cam.getProjectionMatrix());
+ }
+
+ }
+ }
+
+ /**
+ * Set the camera to use for rendering.
+ * <p>
+ * First, the camera's
+ * {@link Camera#setViewPort(float, float, float, float) view port parameters}
+ * are applied. Then, the camera's {@link Camera#getViewMatrix() view} and
+ * {@link Camera#getProjectionMatrix() projection} matrices are set
+ * on the renderer. If <code>ortho</code> is <code>true</code>, then
+ * instead of using the camera's view and projection matrices, an ortho
+ * matrix is computed and used instead of the view projection matrix.
+ * The ortho matrix converts from the range (0 ~ Width, 0 ~ Height, -1 ~ +1)
+ * to the clip range (-1 ~ +1, -1 ~ +1, -1 ~ +1).
+ *
+ * @param cam The camera to set
+ * @param ortho True if to use orthographic projection (for GUI rendering),
+ * false if to use the camera's view and projection matrices.
+ */
+ public void setCamera(Camera cam, boolean ortho) {
+ setViewPort(cam);
+ setViewProjection(cam, ortho);
+ }
+
+ /**
+ * Draws the viewport but without notifying {@link SceneProcessor scene
+ * processors} of any rendering events.
+ *
+ * @param vp The ViewPort to render
+ *
+ * @see #renderViewPort(com.jme3.renderer.ViewPort, float)
+ */
+ public void renderViewPortRaw(ViewPort vp) {
+ setCamera(vp.getCamera(), false);
+ List<Spatial> scenes = vp.getScenes();
+ for (int i = scenes.size() - 1; i >= 0; i--) {
+ renderScene(scenes.get(i), vp);
+ }
+ flushQueue(vp);
+ }
+
+ /**
+ * Renders the {@link ViewPort}.
+ * <p>
+ * If the ViewPort is {@link ViewPort#isEnabled() disabled}, this method
+ * returns immediately. Otherwise, the ViewPort is rendered by
+ * the following process:<br>
+ * <ul>
+ * <li>All {@link SceneProcessor scene processors} that are attached
+ * to the ViewPort are {@link SceneProcessor#initialize(com.jme3.renderer.RenderManager, com.jme3.renderer.ViewPort) initialized}.
+ * </li>
+ * <li>The SceneProcessors' {@link SceneProcessor#preFrame(float) } method
+ * is called.</li>
+ * <li>The ViewPort's {@link ViewPort#getOutputFrameBuffer() output framebuffer}
+ * is set on the Renderer</li>
+ * <li>The camera is set on the renderer, including its view port parameters.
+ * (see {@link #setCamera(com.jme3.renderer.Camera, boolean) })</li>
+ * <li>Any buffers that the ViewPort requests to be cleared are cleared
+ * and the {@link ViewPort#getBackgroundColor() background color} is set</li>
+ * <li>Every scene that is attached to the ViewPort is flattened into
+ * the ViewPort's render queue
+ * (see {@link #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) })
+ * </li>
+ * <li>The SceneProcessors' {@link SceneProcessor#postQueue(com.jme3.renderer.queue.RenderQueue) }
+ * method is called.</li>
+ * <li>The render queue is sorted and then flushed, sending
+ * rendering commands to the underlying Renderer implementation.
+ * (see {@link #flushQueue(com.jme3.renderer.ViewPort) })</li>
+ * <li>The SceneProcessors' {@link SceneProcessor#postFrame(com.jme3.texture.FrameBuffer) }
+ * method is called.</li>
+ * <li>The translucent queue of the ViewPort is sorted and then flushed
+ * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
+ * <li>If any objects remained in the render queue, they are removed
+ * from the queue. This is generally objects added to the
+ * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
+ * shadow queue}
+ * which were not rendered because of a missing shadow renderer.</li>
+ * </ul>
+ *
+ * @param vp
+ * @param tpf
+ */
+ public void renderViewPort(ViewPort vp, float tpf) {
+ if (!vp.isEnabled()) {
+ return;
+ }
+ List<SceneProcessor> processors = vp.getProcessors();
+ if (processors.isEmpty()) {
+ processors = null;
+ }
+
+ if (processors != null) {
+ for (SceneProcessor proc : processors) {
+ if (!proc.isInitialized()) {
+ proc.initialize(this, vp);
+ }
+ proc.preFrame(tpf);
+ }
+ }
+
+ renderer.setFrameBuffer(vp.getOutputFrameBuffer());
+ setCamera(vp.getCamera(), false);
+ if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
+ if (vp.isClearColor()) {
+ renderer.setBackgroundColor(vp.getBackgroundColor());
+ }
+ renderer.clearBuffers(vp.isClearColor(),
+ vp.isClearDepth(),
+ vp.isClearStencil());
+ }
+
+ List<Spatial> scenes = vp.getScenes();
+ for (int i = scenes.size() - 1; i >= 0; i--) {
+ renderScene(scenes.get(i), vp);
+ }
+
+ if (processors != null) {
+ for (SceneProcessor proc : processors) {
+ proc.postQueue(vp.getQueue());
+ }
+ }
+
+ flushQueue(vp);
+
+ if (processors != null) {
+ for (SceneProcessor proc : processors) {
+ proc.postFrame(vp.getOutputFrameBuffer());
+ }
+ }
+ //renders the translucent objects queue after processors have been rendered
+ renderTranslucentQueue(vp);
+ // clear any remaining spatials that were not rendered.
+ clearQueue(vp);
+ }
+
+ /**
+ * Called by the application to render any ViewPorts
+ * added to this RenderManager.
+ * <p>
+ * Renders any viewports that were added using the following methods:
+ * <ul>
+ * <li>{@link #createPreView(java.lang.String, com.jme3.renderer.Camera) }</li>
+ * <li>{@link #createMainView(java.lang.String, com.jme3.renderer.Camera) }</li>
+ * <li>{@link #createPostView(java.lang.String, com.jme3.renderer.Camera) }</li>
+ * </ul>
+ *
+ * @param tpf Time per frame value
+ */
+ public void render(float tpf, boolean mainFrameBufferActive) {
+ if (renderer instanceof NullRenderer) {
+ return;
+ }
+
+ this.shader = renderer.getCaps().contains(Caps.GLSL100);
+
+ for (int i = 0; i < preViewPorts.size(); i++) {
+ ViewPort vp = preViewPorts.get(i);
+ if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
+ renderViewPort(vp, tpf);
+ }
+ }
+ for (int i = 0; i < viewPorts.size(); i++) {
+ ViewPort vp = viewPorts.get(i);
+ if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
+ renderViewPort(vp, tpf);
+ }
+ }
+ for (int i = 0; i < postViewPorts.size(); i++) {
+ ViewPort vp = postViewPorts.get(i);
+ if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
+ renderViewPort(vp, tpf);
+ }
+ }
+ }
+}
diff --git a/engine/src/core/com/jme3/scene/BatchNode.java b/engine/src/core/com/jme3/scene/BatchNode.java
index bc1b2cb..303de7a 100644
--- a/engine/src/core/com/jme3/scene/BatchNode.java
+++ b/engine/src/core/com/jme3/scene/BatchNode.java
@@ -46,6 +46,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -190,10 +191,10 @@ public class BatchNode extends Node implements Savable {
}
batches.clear();
}
-
- for (Material material : matMap.keySet()) {
+ for (Map.Entry<Material, List<Geometry>> entry : matMap.entrySet()) {
Mesh m = new Mesh();
- List<Geometry> list = matMap.get(material);
+ Material material = entry.getKey();
+ List<Geometry> list = entry.getValue();
nbGeoms += list.size();
if (!needsFullRebatch) {
list.add(batches.get(material).geometry);
@@ -408,9 +409,9 @@ public class BatchNode extends Node implements Savable {
throw new UnsupportedOperationException();
}
- for (Entry<VertexBuffer> entry : geom.getMesh().getBuffers()) {
- compsForBuf[entry.getKey()] = entry.getValue().getNumComponents();
- formatForBuf[entry.getKey()] = entry.getValue().getFormat();
+ for (VertexBuffer vb : geom.getMesh().getBufferList().getArray()) {
+ compsForBuf[vb.getBufferType().ordinal()] = vb.getNumComponents();
+ formatForBuf[vb.getBufferType().ordinal()] = vb.getFormat();
}
if (mode != null && mode != listMode) {
diff --git a/engine/src/core/com/jme3/scene/Mesh.java b/engine/src/core/com/jme3/scene/Mesh.java
index 6c587f2..036e525 100644
--- a/engine/src/core/com/jme3/scene/Mesh.java
+++ b/engine/src/core/com/jme3/scene/Mesh.java
@@ -43,7 +43,6 @@ import com.jme3.math.Matrix4f;
import com.jme3.math.Triangle;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
-import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
@@ -55,8 +54,6 @@ import com.jme3.util.SafeArrayList;
import java.io.IOException;
import java.nio.*;
import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
/**
* <code>Mesh</code> is used to store rendering data.
@@ -237,9 +234,9 @@ public class Mesh implements Savable, Cloneable {
clone.buffers = new IntMap<VertexBuffer>();
clone.buffersList = new SafeArrayList<VertexBuffer>(VertexBuffer.class);
- for (Entry<VertexBuffer> ent : buffers){
- VertexBuffer bufClone = ent.getValue().clone();
- clone.buffers.put(ent.getKey(), bufClone);
+ for (VertexBuffer vb : buffersList.getArray()){
+ VertexBuffer bufClone = vb.clone();
+ clone.buffers.put(vb.getBufferType().ordinal(), bufClone);
clone.buffersList.add(bufClone);
}
@@ -540,8 +537,8 @@ public class Mesh implements Savable, Cloneable {
* for all {@link VertexBuffer vertex buffers} on this Mesh.
*/
public void setStatic() {
- for (Entry<VertexBuffer> entry : buffers){
- entry.getValue().setUsage(Usage.Static);
+ for (VertexBuffer vb : buffersList.getArray()){
+ vb.setUsage(Usage.Static);
}
}
@@ -551,8 +548,8 @@ public class Mesh implements Savable, Cloneable {
* for all {@link VertexBuffer vertex buffers} on this Mesh.
*/
public void setDynamic() {
- for (Entry<VertexBuffer> entry : buffers){
- entry.getValue().setUsage(Usage.Dynamic);
+ for (VertexBuffer vb : buffersList.getArray()){
+ vb.setUsage(Usage.Dynamic);
}
}
@@ -562,8 +559,8 @@ public class Mesh implements Savable, Cloneable {
* for all {@link VertexBuffer vertex buffers} on this Mesh.
*/
public void setStreamed(){
- for (Entry<VertexBuffer> entry : buffers){
- entry.getValue().setUsage(Usage.Stream);
+ for (VertexBuffer vb : buffersList.getArray()){
+ vb.setUsage(Usage.Stream);
}
}
@@ -572,11 +569,11 @@ public class Mesh implements Savable, Cloneable {
* Some GPUs may prefer the data in this format, however it is a good idea
* to <em>avoid</em> using this method as it disables some engine features.
*/
+ @Deprecated
public void setInterleaved(){
ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>();
- for (Entry<VertexBuffer> entry : buffers){
- vbs.add(entry.getValue());
- }
+ vbs.addAll(buffersList);
+
// ArrayList<VertexBuffer> vbs = new ArrayList<VertexBuffer>(buffers.values());
// index buffer not included when interleaving
vbs.remove(getBuffer(Type.Index));
@@ -860,6 +857,65 @@ public class Mesh implements Savable, Cloneable {
}
/**
+ * Sets the {@link VertexBuffer} on the mesh.
+ * This will update the vertex/triangle counts if needed.
+ *
+ * @param vb The buffer to set
+ * @throws IllegalArgumentException If the buffer type is already set
+ */
+ public void setBuffer(VertexBuffer vb){
+ if (buffers.containsKey(vb.getBufferType().ordinal()))
+ throw new IllegalArgumentException("Buffer type already set: "+vb.getBufferType());
+
+ buffers.put(vb.getBufferType().ordinal(), vb);
+ buffersList.add(vb);
+ updateCounts();
+ }
+
+ /**
+ * Unsets the {@link VertexBuffer} set on this mesh
+ * with the given type. Does nothing if the vertex buffer type is not set
+ * initially.
+ *
+ * @param type The buffer type to remove
+ */
+ public void clearBuffer(VertexBuffer.Type type){
+ VertexBuffer vb = buffers.remove(type.ordinal());
+ if (vb != null){
+ buffersList.remove(vb);
+ updateCounts();
+ }
+ }
+
+ /**
+ * Creates a {@link VertexBuffer} for the mesh or modifies
+ * the existing one per the parameters given.
+ *
+ * @param type The type of the buffer
+ * @param components Number of components
+ * @param format Data format
+ * @param buf The buffer data
+ *
+ * @throws UnsupportedOperationException If the buffer already set is
+ * incompatible with the parameters given.
+ */
+ public void setBuffer(Type type, int components, Format format, Buffer buf){
+ VertexBuffer vb = buffers.get(type.ordinal());
+ if (vb == null){
+ vb = new VertexBuffer(type);
+ vb.setupData(Usage.Dynamic, components, format, buf);
+ setBuffer(vb);
+ }else{
+ if (vb.getNumComponents() != components || vb.getFormat() != format){
+ throw new UnsupportedOperationException("The buffer already set "
+ + "is incompatible with the given parameters");
+ }
+ vb.updateData(buf);
+ updateCounts();
+ }
+ }
+
+ /**
* Set a floating point {@link VertexBuffer} on the mesh.
*
* @param type The type of {@link VertexBuffer},
@@ -871,21 +927,7 @@ public class Mesh implements Savable, Cloneable {
* @param buf The floating point data to contain
*/
public void setBuffer(Type type, int components, FloatBuffer buf) {
-// VertexBuffer vb = buffers.get(type);
- VertexBuffer vb = buffers.get(type.ordinal());
- if (vb == null){
- if (buf == null)
- return;
-
- vb = new VertexBuffer(type);
- vb.setupData(Usage.Dynamic, components, Format.Float, buf);
-// buffers.put(type, vb);
- buffers.put(type.ordinal(), vb);
- buffersList.add(vb);
- }else{
- vb.setupData(Usage.Dynamic, components, Format.Float, buf);
- }
- updateCounts();
+ setBuffer(type, components, Format.Float, buf);
}
public void setBuffer(Type type, int components, float[] buf){
@@ -893,14 +935,7 @@ public class Mesh implements Savable, Cloneable {
}
public void setBuffer(Type type, int components, IntBuffer buf) {
- VertexBuffer vb = buffers.get(type.ordinal());
- if (vb == null){
- vb = new VertexBuffer(type);
- vb.setupData(Usage.Dynamic, components, Format.UnsignedInt, buf);
- buffers.put(type.ordinal(), vb);
- buffersList.add(vb);
- updateCounts();
- }
+ setBuffer(type, components, Format.UnsignedInt, buf);
}
public void setBuffer(Type type, int components, int[] buf){
@@ -908,14 +943,7 @@ public class Mesh implements Savable, Cloneable {
}
public void setBuffer(Type type, int components, ShortBuffer buf) {
- VertexBuffer vb = buffers.get(type.ordinal());
- if (vb == null){
- vb = new VertexBuffer(type);
- vb.setupData(Usage.Dynamic, components, Format.UnsignedShort, buf);
- buffers.put(type.ordinal(), vb);
- buffersList.add(vb);
- updateCounts();
- }
+ setBuffer(type, components, Format.UnsignedShort, buf);
}
public void setBuffer(Type type, int components, byte[] buf){
@@ -923,38 +951,7 @@ public class Mesh implements Savable, Cloneable {
}
public void setBuffer(Type type, int components, ByteBuffer buf) {
- VertexBuffer vb = buffers.get(type.ordinal());
- if (vb == null){
- vb = new VertexBuffer(type);
- vb.setupData(Usage.Dynamic, components, Format.UnsignedByte, buf);
- buffers.put(type.ordinal(), vb);
- buffersList.add(vb);
- updateCounts();
- }
- }
-
- public void setBuffer(VertexBuffer vb){
- if (buffers.containsKey(vb.getBufferType().ordinal()))
- throw new IllegalArgumentException("Buffer type already set: "+vb.getBufferType());
-
- buffers.put(vb.getBufferType().ordinal(), vb);
- buffersList.add(vb);
- updateCounts();
- }
-
- /**
- * Clears or unsets the {@link VertexBuffer} set on this mesh
- * with the given type.
- * Does nothing if the vertex buffer type is not set initially
- *
- * @param type The type to remove
- */
- public void clearBuffer(VertexBuffer.Type type){
- VertexBuffer vb = buffers.remove(type.ordinal());
- if (vb != null){
- buffersList.remove(vb);
- updateCounts();
- }
+ setBuffer(type, components, Format.UnsignedByte, buf);
}
public void setBuffer(Type type, int components, short[] buf){
diff --git a/engine/src/core/com/jme3/shader/UniformBinding.java b/engine/src/core/com/jme3/shader/UniformBinding.java
index bdca35b..6bd4ca9 100644
--- a/engine/src/core/com/jme3/shader/UniformBinding.java
+++ b/engine/src/core/com/jme3/shader/UniformBinding.java
@@ -1,162 +1,176 @@
-/*
- * Copyright (c) 2009-2010 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.shader;
-
-public enum UniformBinding {
-
- /**
- * The world matrix. Converts Model space to World space.
- * Type: mat4
- */
- WorldMatrix,
-
- /**
- * The view matrix. Converts World space to View space.
- * Type: mat4
- */
- ViewMatrix,
-
- /**
- * The projection matrix. Converts View space to Clip/Projection space.
- * Type: mat4
- */
- ProjectionMatrix,
-
- /**
- * The world view matrix. Converts Model space to View space.
- * Type: mat4
- */
- WorldViewMatrix,
-
- /**
- * The normal matrix. The inverse transpose of the worldview matrix.
- * Converts normals from model space to view space.
- * Type: mat3
- */
- NormalMatrix,
-
- /**
- * The world view projection matrix. Converts Model space to Clip/Projection
- * space.
- * Type: mat4
- */
- WorldViewProjectionMatrix,
-
- /**
- * The view projection matrix. Converts Model space to Clip/Projection
- * space.
- * Type: mat4
- */
- ViewProjectionMatrix,
-
-
- WorldMatrixInverse,
- ViewMatrixInverse,
- ProjectionMatrixInverse,
- ViewProjectionMatrixInverse,
- WorldViewMatrixInverse,
- NormalMatrixInverse,
- WorldViewProjectionMatrixInverse,
-
- /**
- * Contains the four viewport parameters in this order:
- * X = Left,
- * Y = Top,
- * Z = Right,
- * W = Bottom.
- * Type: vec4
- */
- ViewPort,
-
- /**
- * The near and far values for the camera frustum.
- * X = Near
- * Y = Far.
- * Type: vec2
- */
- FrustumNearFar,
-
- /**
- * The width and height of the camera.
- * Type: vec2
- */
- Resolution,
-
- /**
- * Aspect ratio of the resolution currently set. Width/Height.
- * Type: float
- */
- Aspect,
-
- /**
- * Camera position in world space.
- * Type: vec3
- */
- CameraPosition,
-
- /**
- * Direction of the camera.
- * Type: vec3
- */
- CameraDirection,
-
- /**
- * Left vector of the camera.
- * Type: vec3
- */
- CameraLeft,
-
- /**
- * Up vector of the camera.
- * Type: vec3
- */
- CameraUp,
-
- /**
- * Time in seconds since the application was started.
- * Type: float
- */
- Time,
-
- /**
- * Time in seconds that the last frame took.
- * Type: float
- */
- Tpf,
-
- /**
- * Frames per second.
- * Type: float
- */
- FrameRate,
-}
+/*
+ * Copyright (c) 2009-2010 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.shader;
+
+public enum UniformBinding {
+
+ /**
+ * The world matrix. Converts Model space to World space.
+ * Type: mat4
+ */
+ WorldMatrix,
+
+ /**
+ * The view matrix. Converts World space to View space.
+ * Type: mat4
+ */
+ ViewMatrix,
+
+ /**
+ * The projection matrix. Converts View space to Clip/Projection space.
+ * Type: mat4
+ */
+ ProjectionMatrix,
+
+ /**
+ * The world view matrix. Converts Model space to View space.
+ * Type: mat4
+ */
+ WorldViewMatrix,
+
+ /**
+ * The normal matrix. The inverse transpose of the worldview matrix.
+ * Converts normals from model space to view space.
+ * Type: mat3
+ */
+ NormalMatrix,
+
+ /**
+ * The world view projection matrix. Converts Model space to Clip/Projection
+ * space.
+ * Type: mat4
+ */
+ WorldViewProjectionMatrix,
+
+ /**
+ * The view projection matrix. Converts World space to Clip/Projection
+ * space.
+ * Type: mat4
+ */
+ ViewProjectionMatrix,
+
+ /**
+ * The world matrix inverse transpose. Converts a normals from Model space
+ * to world space.
+ * Type: mat3
+ */
+ WorldMatrixInverseTranspose,
+
+
+
+ WorldMatrixInverse,
+ ViewMatrixInverse,
+ ProjectionMatrixInverse,
+ ViewProjectionMatrixInverse,
+ WorldViewMatrixInverse,
+ NormalMatrixInverse,
+ WorldViewProjectionMatrixInverse,
+
+ /**
+ * Contains the four viewport parameters in this order:
+ * X = Left,
+ * Y = Top,
+ * Z = Right,
+ * W = Bottom.
+ * Type: vec4
+ */
+ ViewPort,
+
+ /**
+ * The near and far values for the camera frustum.
+ * X = Near
+ * Y = Far.
+ * Type: vec2
+ */
+ FrustumNearFar,
+
+ /**
+ * The width and height of the camera.
+ * Type: vec2
+ */
+ Resolution,
+
+ /**
+ * The inverse of the resolution, 1/width and 1/height.
+ * Type: vec2
+ */
+ ResolutionInverse,
+
+ /**
+ * Aspect ratio of the resolution currently set. Width/Height.
+ * Type: float
+ */
+ Aspect,
+
+ /**
+ * Camera position in world space.
+ * Type: vec3
+ */
+ CameraPosition,
+
+ /**
+ * Direction of the camera.
+ * Type: vec3
+ */
+ CameraDirection,
+
+ /**
+ * Left vector of the camera.
+ * Type: vec3
+ */
+ CameraLeft,
+
+ /**
+ * Up vector of the camera.
+ * Type: vec3
+ */
+ CameraUp,
+
+ /**
+ * Time in seconds since the application was started.
+ * Type: float
+ */
+ Time,
+
+ /**
+ * Time in seconds that the last frame took.
+ * Type: float
+ */
+ Tpf,
+
+ /**
+ * Frames per second.
+ * Type: float
+ */
+ FrameRate,
+}
diff --git a/engine/src/core/com/jme3/system/JmeSystem.java b/engine/src/core/com/jme3/system/JmeSystem.java
index 1a13a42..2e2d79a 100644
--- a/engine/src/core/com/jme3/system/JmeSystem.java
+++ b/engine/src/core/com/jme3/system/JmeSystem.java
@@ -1,136 +1,147 @@
-/*
- * Copyright (c) 2009-2010 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 com.jme3.asset.AssetManager;
-import com.jme3.audio.AudioRenderer;
-import java.io.File;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class JmeSystem {
-
- private static JmeSystemDelegate systemDelegate;
-
- public static void setSystemDelegate(JmeSystemDelegate systemDelegate) {
- JmeSystem.systemDelegate = systemDelegate;
- }
-
- public static synchronized File getStorageFolder() {
- checkDelegate();
- return systemDelegate.getStorageFolder();
- }
-
- public static String getFullName() {
- checkDelegate();
- return systemDelegate.getFullName();
- }
-
- public static InputStream getResourceAsStream(String name) {
- checkDelegate();
- return systemDelegate.getResourceAsStream(name);
- }
-
- public static URL getResource(String name) {
- checkDelegate();
- return systemDelegate.getResource(name);
- }
-
- public static boolean trackDirectMemory() {
- checkDelegate();
- return systemDelegate.trackDirectMemory();
- }
-
- public static void setLowPermissions(boolean lowPerm) {
- checkDelegate();
- systemDelegate.setLowPermissions(lowPerm);
- }
-
- public static boolean isLowPermissions() {
- checkDelegate();
- return systemDelegate.isLowPermissions();
- }
-
- public static AssetManager newAssetManager(URL configFile) {
- checkDelegate();
- return systemDelegate.newAssetManager(configFile);
- }
-
- public static AssetManager newAssetManager() {
- checkDelegate();
- return systemDelegate.newAssetManager();
- }
-
- public static boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) {
- checkDelegate();
- return systemDelegate.showSettingsDialog(sourceSettings, loadFromRegistry);
- }
-
- public static Platform getPlatform() {
- checkDelegate();
- return systemDelegate.getPlatform();
- }
-
- public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) {
- checkDelegate();
- return systemDelegate.newContext(settings, contextType);
- }
-
- public static AudioRenderer newAudioRenderer(AppSettings settings) {
- checkDelegate();
- return systemDelegate.newAudioRenderer(settings);
- }
-
- public static void initialize(AppSettings settings) {
- checkDelegate();
- systemDelegate.initialize(settings);
- }
-
- @SuppressWarnings("unchecked")
- private static void checkDelegate() {
- if (systemDelegate == null) {
- Class<JmeSystemDelegate> systemDelegateClass;
- try {
- systemDelegateClass = (Class<JmeSystemDelegate>) Class.forName("com.jme3.system.JmeDesktopSystem");
- systemDelegate = systemDelegateClass.newInstance();
- } catch (InstantiationException ex) {
- Logger.getLogger(JmeSystem.class.getName()).log(Level.SEVERE, "No JmeSystemDelegate specified, cannot instantiate default JmeDesktopSystem:\n{0}", ex);
- } catch (IllegalAccessException ex) {
- Logger.getLogger(JmeSystem.class.getName()).log(Level.SEVERE, "No JmeSystemDelegate specified, cannot instantiate default JmeDesktopSystem:\n{0}", ex);
- } catch (ClassNotFoundException ex) {
- Logger.getLogger(JmeSystem.class.getName()).log(Level.SEVERE, "No JmeSystemDelegate specified, cannot instantiate default JmeDesktopSystem:\n{0}", ex);
- }
- }
- }
-}
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.asset.AssetManager;
+import com.jme3.audio.AudioRenderer;
+import com.jme3.input.SoftTextDialogInput;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class JmeSystem {
+
+ private static JmeSystemDelegate systemDelegate;
+
+ public static void setSystemDelegate(JmeSystemDelegate systemDelegate) {
+ JmeSystem.systemDelegate = systemDelegate;
+ }
+
+ public static synchronized File getStorageFolder() {
+ checkDelegate();
+ return systemDelegate.getStorageFolder();
+ }
+
+ public static String getFullName() {
+ checkDelegate();
+ return systemDelegate.getFullName();
+ }
+
+ public static InputStream getResourceAsStream(String name) {
+ checkDelegate();
+ return systemDelegate.getResourceAsStream(name);
+ }
+
+ public static URL getResource(String name) {
+ checkDelegate();
+ return systemDelegate.getResource(name);
+ }
+
+ public static boolean trackDirectMemory() {
+ checkDelegate();
+ return systemDelegate.trackDirectMemory();
+ }
+
+ public static void setLowPermissions(boolean lowPerm) {
+ checkDelegate();
+ systemDelegate.setLowPermissions(lowPerm);
+ }
+
+ public static boolean isLowPermissions() {
+ checkDelegate();
+ return systemDelegate.isLowPermissions();
+ }
+
+ public static void setSoftTextDialogInput(SoftTextDialogInput input) {
+ checkDelegate();
+ systemDelegate.setSoftTextDialogInput(input);
+ }
+
+ public static SoftTextDialogInput getSoftTextDialogInput() {
+ checkDelegate();
+ return systemDelegate.getSoftTextDialogInput();
+ }
+
+ public static AssetManager newAssetManager(URL configFile) {
+ checkDelegate();
+ return systemDelegate.newAssetManager(configFile);
+ }
+
+ public static AssetManager newAssetManager() {
+ checkDelegate();
+ return systemDelegate.newAssetManager();
+ }
+
+ public static boolean showSettingsDialog(AppSettings sourceSettings, final boolean loadFromRegistry) {
+ checkDelegate();
+ return systemDelegate.showSettingsDialog(sourceSettings, loadFromRegistry);
+ }
+
+ public static Platform getPlatform() {
+ checkDelegate();
+ return systemDelegate.getPlatform();
+ }
+
+ public static JmeContext newContext(AppSettings settings, JmeContext.Type contextType) {
+ checkDelegate();
+ return systemDelegate.newContext(settings, contextType);
+ }
+
+ public static AudioRenderer newAudioRenderer(AppSettings settings) {
+ checkDelegate();
+ return systemDelegate.newAudioRenderer(settings);
+ }
+
+ public static void initialize(AppSettings settings) {
+ checkDelegate();
+ systemDelegate.initialize(settings);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void checkDelegate() {
+ if (systemDelegate == null) {
+ Class<JmeSystemDelegate> systemDelegateClass;
+ try {
+ systemDelegateClass = (Class<JmeSystemDelegate>) Class.forName("com.jme3.system.JmeDesktopSystem");
+ systemDelegate = systemDelegateClass.newInstance();
+ } catch (InstantiationException ex) {
+ Logger.getLogger(JmeSystem.class.getName()).log(Level.SEVERE, "No JmeSystemDelegate specified, cannot instantiate default JmeDesktopSystem:\n{0}", ex);
+ } catch (IllegalAccessException ex) {
+ Logger.getLogger(JmeSystem.class.getName()).log(Level.SEVERE, "No JmeSystemDelegate specified, cannot instantiate default JmeDesktopSystem:\n{0}", ex);
+ } catch (ClassNotFoundException ex) {
+ Logger.getLogger(JmeSystem.class.getName()).log(Level.SEVERE, "No JmeSystemDelegate specified, cannot instantiate default JmeDesktopSystem:\n{0}", ex);
+ }
+ }
+ }
+}
diff --git a/engine/src/core/com/jme3/system/JmeSystemDelegate.java b/engine/src/core/com/jme3/system/JmeSystemDelegate.java
index 60265ae..e0f6fa5 100644
--- a/engine/src/core/com/jme3/system/JmeSystemDelegate.java
+++ b/engine/src/core/com/jme3/system/JmeSystemDelegate.java
@@ -1,140 +1,149 @@
-/*
- * Copyright (c) 2009-2010 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 com.jme3.asset.AssetManager;
-import com.jme3.audio.AudioRenderer;
-import java.io.File;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.logging.Logger;
-
-/**
- *
- * @author Kirill Vainer, normenhansen
- */
-public abstract class JmeSystemDelegate {
-
- protected final Logger logger = Logger.getLogger(JmeSystem.class.getName());
- protected boolean initialized = false;
- protected boolean lowPermissions = false;
- protected File storageFolder = null;
-
- public synchronized File getStorageFolder() {
- if (lowPermissions) {
- throw new UnsupportedOperationException("File system access restricted");
- }
- if (storageFolder == null) {
- // Initialize storage folder
- storageFolder = new File(System.getProperty("user.home"), ".jme3");
- if (!storageFolder.exists()) {
- storageFolder.mkdir();
- }
- }
- return storageFolder;
- }
-
- public String getFullName() {
- return JmeVersion.FULL_NAME;
- }
-
- public InputStream getResourceAsStream(String name) {
- return this.getClass().getResourceAsStream(name);
- }
-
- public URL getResource(String name) {
- return this.getClass().getResource(name);
- }
-
- public boolean trackDirectMemory() {
- return false;
- }
-
- public void setLowPermissions(boolean lowPerm) {
- lowPermissions = lowPerm;
- }
-
- public boolean isLowPermissions() {
- return lowPermissions;
- }
-
- public abstract AssetManager newAssetManager(URL configFile);
-
- public abstract AssetManager newAssetManager();
-
- public abstract boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry);
-
- private boolean is64Bit(String arch) {
- if (arch.equals("x86")) {
- return false;
- } else if (arch.equals("amd64")) {
- return true;
- } else if (arch.equals("x86_64")) {
- return true;
- } else if (arch.equals("ppc") || arch.equals("PowerPC")) {
- return false;
- } else if (arch.equals("ppc64")) {
- return true;
- } else if (arch.equals("i386") || arch.equals("i686")) {
- return false;
- } else if (arch.equals("universal")) {
- return false;
- } else {
- throw new UnsupportedOperationException("Unsupported architecture: " + arch);
- }
- }
-
- public Platform getPlatform() {
- String os = System.getProperty("os.name").toLowerCase();
- String arch = System.getProperty("os.arch").toLowerCase();
- boolean is64 = is64Bit(arch);
- if (os.contains("windows")) {
- return is64 ? Platform.Windows64 : Platform.Windows32;
- } else if (os.contains("linux") || os.contains("freebsd") || os.contains("sunos")) {
- return is64 ? Platform.Linux64 : Platform.Linux32;
- } else if (os.contains("mac os x") || os.contains("darwin")) {
- if (arch.startsWith("ppc")) {
- return is64 ? Platform.MacOSX_PPC64 : Platform.MacOSX_PPC32;
- } else {
- return is64 ? Platform.MacOSX64 : Platform.MacOSX32;
- }
- } else {
- throw new UnsupportedOperationException("The specified platform: " + os + " is not supported.");
- }
- }
-
- public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType);
-
- public abstract AudioRenderer newAudioRenderer(AppSettings settings);
-
- public abstract void initialize(AppSettings settings);
-}
+/*
+ * Copyright (c) 2009-2010 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 com.jme3.asset.AssetManager;
+import com.jme3.audio.AudioRenderer;
+import com.jme3.input.SoftTextDialogInput;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Kirill Vainer, normenhansen
+ */
+public abstract class JmeSystemDelegate {
+
+ protected final Logger logger = Logger.getLogger(JmeSystem.class.getName());
+ protected boolean initialized = false;
+ protected boolean lowPermissions = false;
+ protected File storageFolder = null;
+ protected SoftTextDialogInput softTextDialogInput = null;
+
+ public synchronized File getStorageFolder() {
+ if (lowPermissions) {
+ throw new UnsupportedOperationException("File system access restricted");
+ }
+ if (storageFolder == null) {
+ // Initialize storage folder
+ storageFolder = new File(System.getProperty("user.home"), ".jme3");
+ if (!storageFolder.exists()) {
+ storageFolder.mkdir();
+ }
+ }
+ return storageFolder;
+ }
+
+ public String getFullName() {
+ return JmeVersion.FULL_NAME;
+ }
+
+ public InputStream getResourceAsStream(String name) {
+ return this.getClass().getResourceAsStream(name);
+ }
+
+ public URL getResource(String name) {
+ return this.getClass().getResource(name);
+ }
+
+ public boolean trackDirectMemory() {
+ return false;
+ }
+
+ public void setLowPermissions(boolean lowPerm) {
+ lowPermissions = lowPerm;
+ }
+
+ public boolean isLowPermissions() {
+ return lowPermissions;
+ }
+
+ public void setSoftTextDialogInput(SoftTextDialogInput input) {
+ softTextDialogInput = input;
+ }
+ public SoftTextDialogInput getSoftTextDialogInput() {
+ return softTextDialogInput;
+ }
+
+ public abstract AssetManager newAssetManager(URL configFile);
+
+ public abstract AssetManager newAssetManager();
+
+ public abstract boolean showSettingsDialog(AppSettings sourceSettings, boolean loadFromRegistry);
+
+ private boolean is64Bit(String arch) {
+ if (arch.equals("x86")) {
+ return false;
+ } else if (arch.equals("amd64")) {
+ return true;
+ } else if (arch.equals("x86_64")) {
+ return true;
+ } else if (arch.equals("ppc") || arch.equals("PowerPC")) {
+ return false;
+ } else if (arch.equals("ppc64")) {
+ return true;
+ } else if (arch.equals("i386") || arch.equals("i686")) {
+ return false;
+ } else if (arch.equals("universal")) {
+ return false;
+ } else {
+ throw new UnsupportedOperationException("Unsupported architecture: " + arch);
+ }
+ }
+
+ public Platform getPlatform() {
+ String os = System.getProperty("os.name").toLowerCase();
+ String arch = System.getProperty("os.arch").toLowerCase();
+ boolean is64 = is64Bit(arch);
+ if (os.contains("windows")) {
+ return is64 ? Platform.Windows64 : Platform.Windows32;
+ } else if (os.contains("linux") || os.contains("freebsd") || os.contains("sunos")) {
+ return is64 ? Platform.Linux64 : Platform.Linux32;
+ } else if (os.contains("mac os x") || os.contains("darwin")) {
+ if (arch.startsWith("ppc")) {
+ return is64 ? Platform.MacOSX_PPC64 : Platform.MacOSX_PPC32;
+ } else {
+ return is64 ? Platform.MacOSX64 : Platform.MacOSX32;
+ }
+ } else {
+ throw new UnsupportedOperationException("The specified platform: " + os + " is not supported.");
+ }
+ }
+
+ public abstract JmeContext newContext(AppSettings settings, JmeContext.Type contextType);
+
+ public abstract AudioRenderer newAudioRenderer(AppSettings settings);
+
+ public abstract void initialize(AppSettings settings);
+}
diff --git a/engine/src/core/com/jme3/util/BufferUtils.java b/engine/src/core/com/jme3/util/BufferUtils.java
index f0cc698..2e59e97 100644
--- a/engine/src/core/com/jme3/util/BufferUtils.java
+++ b/engine/src/core/com/jme3/util/BufferUtils.java
@@ -42,6 +42,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -1144,6 +1145,47 @@ public final class BufferUtils {
}
}
+ private static final AtomicBoolean loadedMethods = new AtomicBoolean(false);
+ private static Method cleanerMethod = null;
+ private static Method cleanMethod = null;
+ private static Method viewedBufferMethod = null;
+ private static Method freeMethod = null;
+
+ private static Method loadMethod(String className, String methodName){
+ try {
+ Method method = Class.forName(className).getMethod(methodName);
+ method.setAccessible(true);
+ return method;
+ } catch (NoSuchMethodException ex) {
+ return null; // the method was not found
+ } catch (SecurityException ex) {
+ return null; // setAccessible not allowed by security policy
+ } catch (ClassNotFoundException ex) {
+ return null; // the direct buffer implementation was not found
+ }
+ }
+
+ private static void loadCleanerMethods() {
+ // If its already true, exit, if not, set it to true.
+ if (loadedMethods.getAndSet(true)) {
+ return;
+ }
+ // This could potentially be called many times if used from multiple
+ // threads
+ synchronized (loadedMethods) {
+ // Oracle JRE / OpenJDK
+ cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
+ cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
+ viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
+
+ // Apache Harmony
+ freeMethod = loadMethod("org.apache.harmony.nio.internal.DirectBuffer", "free");
+
+ // GUN Classpath (not likely)
+ //finalizeMethod = loadMethod("java.nio.DirectByteBufferImpl", "finalize");
+ }
+ }
+
/**
* Direct buffers are garbage collected by using a phantom reference and a
* reference queue. Every once a while, the JVM checks the reference queue and
@@ -1157,27 +1199,27 @@ public final class BufferUtils {
*
*/
public static void destroyDirectBuffer(Buffer toBeDestroyed) {
-
if (!toBeDestroyed.isDirect()) {
return;
}
+
+ loadCleanerMethods();
+
try {
- Method cleanerMethod = toBeDestroyed.getClass().getMethod("cleaner");
- cleanerMethod.setAccessible(true);
- Object cleaner = cleanerMethod.invoke(toBeDestroyed);
- if (cleaner != null) {
- Method cleanMethod = cleaner.getClass().getMethod("clean");
- cleanMethod.setAccessible(true);
- cleanMethod.invoke(cleaner);
+ if (freeMethod != null) {
+ freeMethod.invoke(toBeDestroyed);
} else {
- // Try the alternate approach of getting the viewed buffer
- Method viewedBufferMethod = toBeDestroyed.getClass().getMethod("viewedBuffer");
- viewedBufferMethod.setAccessible(true);
- Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
- if (viewedBuffer != null) {
- destroyDirectBuffer( (Buffer)viewedBuffer );
+ Object cleaner = cleanerMethod.invoke(toBeDestroyed);
+ if (cleaner != null) {
+ cleanMethod.invoke(cleaner);
} else {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
+ // Try the alternate approach of getting the viewed buffer first
+ Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
+ if (viewedBuffer != null) {
+ destroyDirectBuffer((Buffer) viewedBuffer);
+ } else {
+ Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
+ }
}
}
} catch (IllegalAccessException ex) {
@@ -1186,11 +1228,8 @@ public final class BufferUtils {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
- } catch (NoSuchMethodException ex) {
- Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
} catch (SecurityException ex) {
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
}
}
-
}
diff --git a/engine/src/core/com/jme3/util/IntMap.java b/engine/src/core/com/jme3/util/IntMap.java
index edf659b..1b91119 100644
--- a/engine/src/core/com/jme3/util/IntMap.java
+++ b/engine/src/core/com/jme3/util/IntMap.java
@@ -44,8 +44,6 @@ import java.util.Map;
* @author Nate
*/
public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable {
-
- private final IntMapIterator iterator = new IntMapIterator();
private Entry[] table;
private final float loadFactor;
@@ -200,8 +198,9 @@ public final class IntMap<T> implements Iterable<Entry<T>>, Cloneable {
}
public Iterator<Entry<T>> iterator() {
- iterator.beginUse();
- return iterator;
+ IntMapIterator it = new IntMapIterator();
+ it.beginUse();
+ return it;
}
final class IntMapIterator implements Iterator<Entry<T>> {
diff --git a/engine/src/core/com/jme3/util/TangentBinormalGenerator.java b/engine/src/core/com/jme3/util/TangentBinormalGenerator.java
index 88f6822..8816b91 100644
--- a/engine/src/core/com/jme3/util/TangentBinormalGenerator.java
+++ b/engine/src/core/com/jme3/util/TangentBinormalGenerator.java
@@ -117,7 +117,13 @@ public class TangentBinormalGenerator {
}
} else {
Geometry geom = (Geometry) scene;
- generate(geom.getMesh());
+ Mesh mesh = geom.getMesh();
+
+ // Check to ensure mesh has texcoords and normals before generating
+ if (mesh.getBuffer(Type.TexCoord) != null
+ && mesh.getBuffer(Type.Normal) != null){
+ generate(geom.getMesh());
+ }
}
}
@@ -640,7 +646,7 @@ public class TangentBinormalGenerator {
lineMesh.setBuffer(Type.Color, 4, lineColor);
lineMesh.setStatic();
- lineMesh.setInterleaved();
+ //lineMesh.setInterleaved();
return lineMesh;
}
@@ -733,7 +739,7 @@ public class TangentBinormalGenerator {
lineMesh.setBuffer(Type.Color, 4, lineColor);
lineMesh.setStatic();
- lineMesh.setInterleaved();
+ //lineMesh.setInterleaved();
return lineMesh;
}
}
diff --git a/engine/src/desktop/com/jme3/texture/plugins/AWTLoader.java b/engine/src/desktop/com/jme3/texture/plugins/AWTLoader.java
index 3f471f7..9513bcf 100644
--- a/engine/src/desktop/com/jme3/texture/plugins/AWTLoader.java
+++ b/engine/src/desktop/com/jme3/texture/plugins/AWTLoader.java
@@ -33,6 +33,7 @@
package com.jme3.texture.plugins;
import com.jme3.asset.AssetInfo;
+import com.jme3.asset.AssetLoadException;
import com.jme3.asset.AssetLoader;
import com.jme3.asset.TextureKey;
import com.jme3.texture.Image;
@@ -185,27 +186,30 @@ public class AWTLoader implements AssetLoader {
public Image load(InputStream in, boolean flipY) throws IOException{
ImageIO.setUseCache(false);
BufferedImage img = ImageIO.read(in);
- if (img == null)
+ if (img == null){
return null;
-
+ }
return load(img, flipY);
}
public Object load(AssetInfo info) throws IOException {
- if (ImageIO.getImageWritersBySuffix(info.getKey().getExtension()) != null){
-
+ if (ImageIO.getImageReadersBySuffix(info.getKey().getExtension()) != null){
boolean flip = ((TextureKey) info.getKey()).isFlipY();
InputStream in = null;
try {
in = info.openStream();
Image img = load(in, flip);
+ if (img == null){
+ throw new AssetLoadException("The given image cannot be loaded " + info.getKey());
+ }
return img;
} finally {
if (in != null){
in.close();
}
}
+ }else{
+ throw new AssetLoadException("The extension " + info.getKey().getExtension() + " is not supported");
}
- return null;
}
}
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag
deleted file mode 100644
index 5e77548..0000000
--- a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag
+++ /dev/null
@@ -1,13 +0,0 @@
-uniform bool m_UseTex;
-uniform sampler2D m_Texture;
-uniform vec4 m_Color;
-
-varying vec2 texCoord;
-varying vec4 color;
-
-void main() {
- vec4 texVal = texture2D(m_Texture, texCoord);
- texVal = m_UseTex ? texVal : vec4(1.0);
- gl_FragColor = texVal * color * m_Color;
-}
-
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.frag b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.frag
new file mode 100644
index 0000000..31f49d6
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.frag
@@ -0,0 +1,6 @@
+uniform vec4 m_Color;
+
+void main() {
+ gl_FragColor = m_Color;
+}
+
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.j3md b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.j3md
new file mode 100644
index 0000000..d0213e9
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.j3md
@@ -0,0 +1,19 @@
+MaterialDef Default GUI {
+
+ MaterialParameters {
+ Vector4 Color (Color)
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Nifty/NiftyQuad.vert
+ FragmentShader GLSL100: Common/MatDefs/Nifty/NiftyQuad.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.vert b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.vert
new file mode 100644
index 0000000..1eb1616
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuad.vert
@@ -0,0 +1,9 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+attribute vec4 inPosition;
+
+
+void main() {
+ vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+ gl_Position = vec4(pos, 0.0, 1.0);
+} \ No newline at end of file
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.frag b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.frag
new file mode 100644
index 0000000..1f0a645
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.frag
@@ -0,0 +1,6 @@
+varying vec4 color;
+
+void main() {
+ gl_FragColor = color;
+}
+
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.j3md b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.j3md
new file mode 100644
index 0000000..4b3b22d
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.j3md
@@ -0,0 +1,18 @@
+MaterialDef Default GUI {
+
+ MaterialParameters {
+ }
+
+ Technique {
+ VertexShader GLSL100: Common/MatDefs/Nifty/NiftyQuadGrad.vert
+ FragmentShader GLSL100: Common/MatDefs/Nifty/NiftyQuadGrad.frag
+
+ WorldParameters {
+ WorldViewProjectionMatrix
+ }
+ }
+
+ Technique FixedFunc {
+ }
+
+} \ No newline at end of file
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.vert b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.vert
new file mode 100644
index 0000000..0ecaee4
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyQuadGrad.vert
@@ -0,0 +1,14 @@
+uniform mat4 g_WorldViewProjectionMatrix;
+
+attribute vec4 inPosition;
+attribute vec4 inColor;
+attribute vec4 inIndex;
+
+varying vec4 color;
+
+void main() {
+ vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
+ gl_Position = vec4(pos, 0.0, 1.0);
+
+ color = inIndex;
+} \ No newline at end of file
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.frag b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.frag
new file mode 100644
index 0000000..b2b4b95
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.frag
@@ -0,0 +1,10 @@
+uniform sampler2D m_Texture;
+uniform vec4 m_Color;
+
+varying vec2 texCoord;
+
+void main() {
+ vec4 texVal = texture2D(m_Texture, texCoord);
+ gl_FragColor = texVal * m_Color ;
+}
+
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.j3md b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.j3md
index 9ba39b1..07f5e92 100644
--- a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.j3md
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.j3md
@@ -2,13 +2,12 @@ MaterialDef Default GUI {
MaterialParameters {
Texture2D Texture
- Boolean UseTex
Vector4 Color (Color)
}
Technique {
- VertexShader GLSL100: Common/MatDefs/Nifty/Nifty.vert
- FragmentShader GLSL100: Common/MatDefs/Nifty/Nifty.frag
+ VertexShader GLSL100: Common/MatDefs/Nifty/NiftyTex.vert
+ FragmentShader GLSL100: Common/MatDefs/Nifty/NiftyTex.frag
WorldParameters {
WorldViewProjectionMatrix
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.vert
index 67c864d..c5c3dc1 100644
--- a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/NiftyTex.vert
@@ -1,16 +1,13 @@
uniform mat4 g_WorldViewProjectionMatrix;
attribute vec4 inPosition;
-attribute vec4 inColor;
attribute vec2 inTexCoord;
varying vec2 texCoord;
-varying vec4 color;
void main() {
vec2 pos = (g_WorldViewProjectionMatrix * inPosition).xy;
gl_Position = vec4(pos, 0.0, 1.0);
- texCoord = inTexCoord;
- color = inColor;
+ texCoord = inTexCoord;
} \ No newline at end of file
diff --git a/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java b/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java
index 0b80131..01c2ac7 100644
--- a/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java
+++ b/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java
@@ -1,233 +1,274 @@
-/*
- * Copyright (c) 2009-2010 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.niftygui;
-
-import com.jme3.input.InputManager;
-import com.jme3.input.KeyInput;
-import com.jme3.input.RawInputListener;
-import com.jme3.input.event.*;
-import de.lessvoid.nifty.Nifty;
-import de.lessvoid.nifty.NiftyInputConsumer;
-import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
-import de.lessvoid.nifty.input.keyboard.KeyboardInputEvent;
-import de.lessvoid.nifty.spi.input.InputSystem;
-import java.util.ArrayList;
-
-public class InputSystemJme implements InputSystem, RawInputListener {
-
- private final ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
-
- private InputManager inputManager;
-
- private boolean isDragging = false, niftyOwnsDragging = false;
- private boolean pressed = false;
- private int buttonIndex;
- private int x, y;
- private int height;
-
- private boolean shiftDown = false;
- private boolean ctrlDown = false;
-
- private Nifty nifty;
-
- public InputSystemJme(InputManager inputManager){
- this.inputManager = inputManager;
- }
-
- public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
- }
-
- public void setNifty(Nifty nifty) {
- this.nifty = nifty;
- }
-
- /**
- * @param height The height of the viewport. Used to convert
- * buttom-left origin to upper-left origin.
- */
- public void setHeight(int height){
- this.height = height;
- }
-
- public void setMousePosition(int x, int y){
- }
-
- public void beginInput(){
- }
-
- public void endInput(){
- boolean result = nifty.update();
- }
-
- private void onTouchEventQueued(TouchEvent evt, NiftyInputConsumer nic) {
- boolean consumed = false;
-
- x = (int) evt.getX();
- y = (int) (height - evt.getY());
-
- switch (evt.getType()) {
- case DOWN:
- consumed = nic.processMouseEvent(x, y, 0, 0, false);
- isDragging = true;
- niftyOwnsDragging = consumed;
- if (consumed){
- evt.setConsumed();
- }
-
- break;
-
- case UP:
- if (niftyOwnsDragging){
- consumed = nic.processMouseEvent(x, y, 0, buttonIndex, pressed);
- if (consumed){
- evt.setConsumed();
- }
- }
-
- isDragging = false;
- niftyOwnsDragging = false;
- break;
- }
- }
-
- private void onMouseMotionEventQueued(MouseMotionEvent evt, NiftyInputConsumer nic) {
- x = evt.getX();
- y = height - evt.getY();
- nic.processMouseEvent(x, y, evt.getDeltaWheel(), buttonIndex, pressed);
-// if (nic.processMouseEvent(niftyEvt) /*|| nifty.getCurrentScreen().isMouseOverElement()*/){
- // Do not consume motion events
- //evt.setConsumed();
-// }
- }
-
- private void onMouseButtonEventQueued(MouseButtonEvent evt, NiftyInputConsumer nic) {
- boolean wasPressed = pressed;
- boolean forwardToNifty = true;
-
- buttonIndex = evt.getButtonIndex();
- pressed = evt.isPressed();
-
- // Mouse button raised. End dragging
- if (wasPressed && !pressed){
- if (!niftyOwnsDragging){
- forwardToNifty = false;
- }
- isDragging = false;
- niftyOwnsDragging = false;
- }
-
- boolean consumed = false;
- if (forwardToNifty){
- consumed = nic.processMouseEvent(x, y, 0, buttonIndex, pressed);
- if (consumed){
- evt.setConsumed();
- }
- }
-
- // Mouse button pressed. Begin dragging
- if (!wasPressed && pressed){
- isDragging = true;
- niftyOwnsDragging = consumed;
- }
- }
-
- private void onKeyEventQueued(KeyInputEvent evt, NiftyInputConsumer nic) {
- int code = evt.getKeyCode();
-
- if (code == KeyInput.KEY_LSHIFT || code == KeyInput.KEY_RSHIFT) {
- shiftDown = evt.isPressed();
- } else if (code == KeyInput.KEY_LCONTROL || code == KeyInput.KEY_RCONTROL) {
- ctrlDown = evt.isPressed();
- }
-
- KeyboardInputEvent keyEvt = new KeyboardInputEvent(code,
- evt.getKeyChar(),
- evt.isPressed(),
- shiftDown,
- ctrlDown);
-
- if (nic.processKeyboardEvent(keyEvt)){
- evt.setConsumed();
- }
- }
-
- public void onMouseMotionEvent(MouseMotionEvent evt) {
- // Only forward the event if there's actual motion involved.
- if (inputManager.isCursorVisible() && (evt.getDX() != 0 ||
- evt.getDY() != 0 ||
- evt.getDeltaWheel() != 0)){
- inputQueue.add(evt);
- }
- }
-
- public void onMouseButtonEvent(MouseButtonEvent evt) {
- if (inputManager.isCursorVisible() && evt.getButtonIndex() >= 0 && evt.getButtonIndex() <= 2){
- inputQueue.add(evt);
- }
- }
-
- public void onJoyAxisEvent(JoyAxisEvent evt) {
- }
-
- public void onJoyButtonEvent(JoyButtonEvent evt) {
- }
-
- public void onKeyEvent(KeyInputEvent evt) {
- inputQueue.add(evt);
- }
-
- public void onTouchEvent(TouchEvent evt) {
- inputQueue.add(evt);
- }
-
- public void forwardEvents(NiftyInputConsumer nic) {
- int queueSize = inputQueue.size();
-
- for (int i = 0; i < queueSize; i++){
- InputEvent evt = inputQueue.get(i);
- if (evt instanceof MouseMotionEvent){
- onMouseMotionEventQueued( (MouseMotionEvent)evt, nic);
- }else if (evt instanceof MouseButtonEvent){
- onMouseButtonEventQueued( (MouseButtonEvent)evt, nic);
- }else if (evt instanceof KeyInputEvent){
- onKeyEventQueued( (KeyInputEvent)evt, nic);
- }else if (evt instanceof TouchEvent){
- onTouchEventQueued( (TouchEvent)evt, nic);
- }
- }
-
- inputQueue.clear();
- }
-
-
-}
+/*
+ * Copyright (c) 2009-2010 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.niftygui;
+
+import com.jme3.input.InputManager;
+import com.jme3.input.KeyInput;
+import com.jme3.input.RawInputListener;
+import com.jme3.input.SoftTextDialogInput;
+import com.jme3.input.controls.SoftTextDialogInputListener;
+import com.jme3.input.event.*;
+import com.jme3.system.JmeSystem;
+import de.lessvoid.nifty.Nifty;
+import de.lessvoid.nifty.NiftyInputConsumer;
+import de.lessvoid.nifty.controls.TextField;
+import de.lessvoid.nifty.controls.nullobjects.TextFieldNull;
+import de.lessvoid.nifty.elements.Element;
+import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
+import de.lessvoid.nifty.input.keyboard.KeyboardInputEvent;
+import de.lessvoid.nifty.spi.input.InputSystem;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class InputSystemJme implements InputSystem, RawInputListener {
+
+ private final ArrayList<InputEvent> inputQueue = new ArrayList<InputEvent>();
+ private InputManager inputManager;
+ private boolean isDragging = false, niftyOwnsDragging = false;
+ private boolean pressed = false;
+ private int buttonIndex;
+ private int x, y;
+ private int height;
+ private boolean shiftDown = false;
+ private boolean ctrlDown = false;
+ private Nifty nifty;
+
+ public InputSystemJme(InputManager inputManager) {
+ this.inputManager = inputManager;
+ }
+
+ public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
+ }
+
+ public void setNifty(Nifty nifty) {
+ this.nifty = nifty;
+ }
+
+ /**
+ * @param height The height of the viewport. Used to convert
+ * buttom-left origin to upper-left origin.
+ */
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void setMousePosition(int x, int y) {
+ }
+
+ public void beginInput() {
+ }
+
+ public void endInput() {
+ boolean result = nifty.update();
+ }
+
+ private void onTouchEventQueued(TouchEvent evt, NiftyInputConsumer nic) {
+ boolean consumed = false;
+
+ x = (int) evt.getX();
+ y = (int) (height - evt.getY());
+
+ if (!inputManager.getSimulateMouse()) {
+ switch (evt.getType()) {
+ case DOWN:
+ consumed = nic.processMouseEvent(x, y, 0, 0, true);
+ isDragging = true;
+ niftyOwnsDragging = consumed;
+ if (consumed) {
+ evt.setConsumed();
+ }
+
+ break;
+
+ case UP:
+ if (niftyOwnsDragging) {
+ consumed = nic.processMouseEvent(x, y, 0, 0, false);
+ if (consumed) {
+ evt.setConsumed();
+ }
+ }
+
+ isDragging = false;
+ niftyOwnsDragging = false;
+
+ if (consumed) {
+ processSoftKeyboard();
+ }
+
+ break;
+ }
+ }
+ }
+
+ private void onMouseMotionEventQueued(MouseMotionEvent evt, NiftyInputConsumer nic) {
+ x = evt.getX();
+ y = height - evt.getY();
+ nic.processMouseEvent(x, y, evt.getDeltaWheel(), buttonIndex, pressed);
+// if (nic.processMouseEvent(niftyEvt) /*|| nifty.getCurrentScreen().isMouseOverElement()*/){
+ // Do not consume motion events
+ //evt.setConsumed();
+// }
+ }
+
+ private void onMouseButtonEventQueued(MouseButtonEvent evt, NiftyInputConsumer nic) {
+ boolean wasPressed = pressed;
+ boolean forwardToNifty = true;
+
+ buttonIndex = evt.getButtonIndex();
+ pressed = evt.isPressed();
+
+ // Mouse button raised. End dragging
+ if (wasPressed && !pressed) {
+ if (!niftyOwnsDragging) {
+ forwardToNifty = false;
+ }
+ isDragging = false;
+ niftyOwnsDragging = false;
+ }
+
+ boolean consumed = false;
+ if (forwardToNifty) {
+ consumed = nic.processMouseEvent(x, y, 0, buttonIndex, pressed);
+ if (consumed) {
+ evt.setConsumed();
+ }
+ }
+
+ // Mouse button pressed. Begin dragging
+ if (!wasPressed && pressed) {
+ isDragging = true;
+ niftyOwnsDragging = consumed;
+ }
+
+ if (consumed && pressed) {
+ processSoftKeyboard();
+ }
+
+ }
+
+ private void onKeyEventQueued(KeyInputEvent evt, NiftyInputConsumer nic) {
+ int code = evt.getKeyCode();
+
+ if (code == KeyInput.KEY_LSHIFT || code == KeyInput.KEY_RSHIFT) {
+ shiftDown = evt.isPressed();
+ } else if (code == KeyInput.KEY_LCONTROL || code == KeyInput.KEY_RCONTROL) {
+ ctrlDown = evt.isPressed();
+ }
+
+ KeyboardInputEvent keyEvt = new KeyboardInputEvent(code,
+ evt.getKeyChar(),
+ evt.isPressed(),
+ shiftDown,
+ ctrlDown);
+
+ if (nic.processKeyboardEvent(keyEvt)) {
+ evt.setConsumed();
+ }
+ }
+
+ public void onMouseMotionEvent(MouseMotionEvent evt) {
+ // Only forward the event if there's actual motion involved.
+ if (inputManager.isCursorVisible() && (evt.getDX() != 0
+ || evt.getDY() != 0
+ || evt.getDeltaWheel() != 0)) {
+ inputQueue.add(evt);
+ }
+ }
+
+ public void onMouseButtonEvent(MouseButtonEvent evt) {
+ if (inputManager.isCursorVisible() && evt.getButtonIndex() >= 0 && evt.getButtonIndex() <= 2) {
+ inputQueue.add(evt);
+ }
+ }
+
+ public void onJoyAxisEvent(JoyAxisEvent evt) {
+ }
+
+ public void onJoyButtonEvent(JoyButtonEvent evt) {
+ }
+
+ public void onKeyEvent(KeyInputEvent evt) {
+ inputQueue.add(evt);
+ }
+
+ public void onTouchEvent(TouchEvent evt) {
+ inputQueue.add(evt);
+ }
+
+ public void forwardEvents(NiftyInputConsumer nic) {
+ int queueSize = inputQueue.size();
+
+ for (int i = 0; i < queueSize; i++) {
+ InputEvent evt = inputQueue.get(i);
+ if (evt instanceof MouseMotionEvent) {
+ onMouseMotionEventQueued((MouseMotionEvent) evt, nic);
+ } else if (evt instanceof MouseButtonEvent) {
+ onMouseButtonEventQueued((MouseButtonEvent) evt, nic);
+ } else if (evt instanceof KeyInputEvent) {
+ onKeyEventQueued((KeyInputEvent) evt, nic);
+ } else if (evt instanceof TouchEvent) {
+ onTouchEventQueued((TouchEvent) evt, nic);
+ }
+ }
+
+ inputQueue.clear();
+ }
+
+ private void processSoftKeyboard() {
+ SoftTextDialogInput softTextDialogInput = JmeSystem.getSoftTextDialogInput();
+ if (softTextDialogInput != null) {
+
+ Element element = nifty.getCurrentScreen().getFocusHandler().getKeyboardFocusElement();
+ if (element != null) {
+ final TextField textField = element.getNiftyControl(TextField.class);
+ if (textField != null && !(textField instanceof TextFieldNull)) {
+ Logger.getLogger(InputSystemJme.class.getName()).log(Level.INFO, "Current TextField: {0}", textField.getId());
+ String initialValue = textField.getText();
+ if (initialValue == null) {
+ initialValue = "";
+ }
+
+ softTextDialogInput.requestDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG, "Enter Text", initialValue, new SoftTextDialogInputListener() {
+
+ public void onSoftText(int action, String text) {
+ if (action == SoftTextDialogInputListener.COMPLETE) {
+ textField.setText(text);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ }
+}
diff --git a/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java b/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java
index 8977ed6..1f36a97 100644
--- a/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java
+++ b/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java
@@ -29,7 +29,6 @@
* 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.niftygui;
import com.jme3.font.BitmapText;
@@ -60,140 +59,148 @@ import java.nio.FloatBuffer;
import java.util.HashMap;
public class RenderDeviceJme implements RenderDevice {
-
+
private NiftyJmeDisplay display;
private RenderManager rm;
private Renderer r;
-
private HashMap<String, BitmapText> textCacheLastFrame = new HashMap<String, BitmapText>();
private HashMap<String, BitmapText> textCacheCurrentFrame = new HashMap<String, BitmapText>();
-
private final Quad quad = new Quad(1, -1, true);
private final Geometry quadGeom = new Geometry("nifty-quad", quad);
private final Material niftyMat;
-
+ private final Material niftyQuadMat;
+ private final Material niftyQuadGradMat;
private boolean clipWasSet = false;
private BlendMode blendMode = null;
-
private VertexBuffer quadDefaultTC = quad.getBuffer(Type.TexCoord);
private VertexBuffer quadModTC = quadDefaultTC.clone();
private VertexBuffer quadColor;
-
private Matrix4f tempMat = new Matrix4f();
private ColorRGBA tempColor = new ColorRGBA();
-
- public RenderDeviceJme(NiftyJmeDisplay display){
+
+ public RenderDeviceJme(NiftyJmeDisplay display) {
this.display = display;
-
+
quadColor = new VertexBuffer(Type.Color);
quadColor.setNormalized(true);
ByteBuffer bb = BufferUtils.createByteBuffer(4 * 4);
quadColor.setupData(Usage.Stream, 4, Format.UnsignedByte, bb);
quad.setBuffer(quadColor);
-
+
quadModTC.setUsage(Usage.Stream);
-
- niftyMat = new Material(display.getAssetManager(), "Common/MatDefs/Nifty/Nifty.j3md");
+
+ //Color + texture color material for text and images
+ niftyMat = new Material(display.getAssetManager(), "Common/MatDefs/Nifty/NiftyTex.j3md");
niftyMat.getAdditionalRenderState().setDepthTest(false);
+ //Color material for uniform colored quads
+ niftyQuadMat = new Material(display.getAssetManager(), "Common/MatDefs/Nifty/NiftyQuad.j3md");
+ niftyQuadMat.getAdditionalRenderState().setDepthTest(false);
+
+ //vertex color only for gradient quads (although i didn't find a way in nifty to make a gradient using vertex color)
+ niftyQuadGradMat = new Material(display.getAssetManager(), "Common/MatDefs/Nifty/NiftyQuadGrad.j3md");
+ niftyQuadGradMat.getAdditionalRenderState().setDepthTest(false);
+
}
-
+
public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
}
-
- public void setRenderManager(RenderManager rm){
+
+ public void setRenderManager(RenderManager rm) {
this.rm = rm;
this.r = rm.getRenderer();
}
// TODO: Cursor support
- public MouseCursor createMouseCursor(String str, int x, int y){
+ public MouseCursor createMouseCursor(String str, int x, int y) {
return new MouseCursor() {
+
public void dispose() {
}
};
}
-
- public void enableMouseCursor(MouseCursor cursor){
+
+ public void enableMouseCursor(MouseCursor cursor) {
}
-
- public void disableMouseCursor(){
+
+ public void disableMouseCursor() {
}
-
+
public RenderImage createImage(String filename, boolean linear) {
return new RenderImageJme(filename, linear, display);
}
-
+
public RenderFont createFont(String filename) {
return new RenderFontJme(filename, display);
}
-
+
public void beginFrame() {
}
-
+
public void endFrame() {
HashMap<String, BitmapText> temp = textCacheLastFrame;
textCacheLastFrame = textCacheCurrentFrame;
textCacheCurrentFrame = temp;
textCacheCurrentFrame.clear();
-
+
// System.exit(1);
}
-
+
public int getWidth() {
return display.getWidth();
}
-
+
public int getHeight() {
return display.getHeight();
}
-
+
public void clear() {
}
-
+
public void setBlendMode(BlendMode blendMode) {
- if (this.blendMode != blendMode){
+ if (this.blendMode != blendMode) {
this.blendMode = blendMode;
}
}
-
- private RenderState.BlendMode convertBlend(){
- if (blendMode == null)
+
+ private RenderState.BlendMode convertBlend() {
+ if (blendMode == null) {
return RenderState.BlendMode.Off;
- else if (blendMode == BlendMode.BLEND)
+ } else if (blendMode == BlendMode.BLEND) {
return RenderState.BlendMode.Alpha;
- else if (blendMode == BlendMode.MULIPLY)
+ } else if (blendMode == BlendMode.MULIPLY) {
return RenderState.BlendMode.Modulate;
- else
+ } else {
throw new UnsupportedOperationException();
+ }
}
-
- private int convertColor(Color color){
+
+ private int convertColor(Color color) {
int color2 = 0;
- color2 |= ((int)(255.0 * color.getAlpha())) << 24;
- color2 |= ((int)(255.0 * color.getBlue())) << 16;
- color2 |= ((int)(255.0 * color.getGreen())) << 8;
- color2 |= ((int)(255.0 * color.getRed()));
+ color2 |= ((int) (255.0 * color.getAlpha())) << 24;
+ color2 |= ((int) (255.0 * color.getBlue())) << 16;
+ color2 |= ((int) (255.0 * color.getGreen())) << 8;
+ color2 |= ((int) (255.0 * color.getRed()));
return color2;
}
-
- private ColorRGBA convertColor(Color inColor, ColorRGBA outColor){
+
+ private ColorRGBA convertColor(Color inColor, ColorRGBA outColor) {
return outColor.set(inColor.getRed(), inColor.getGreen(), inColor.getBlue(), inColor.getAlpha());
}
-
- private void setColor(Color color){
- ByteBuffer buf = (ByteBuffer) quadColor.getData();
- buf.rewind();
-
- int color2 = convertColor(color);
- buf.putInt(color2);
- buf.putInt(color2);
- buf.putInt(color2);
- buf.putInt(color2);
-
- buf.flip();
- quadColor.updateData(buf);
- }
+// private void setColor(Color color) {
+// ByteBuffer buf = (ByteBuffer) quadColor.getData();
+// buf.rewind();
+//
+// int color2 = convertColor(color);
+// buf.putInt(color2);
+// buf.putInt(color2);
+// buf.putInt(color2);
+// buf.putInt(color2);
+//
+// buf.flip();
+// quadColor.updateData(buf);
+// }
+
/**
*
* @param font
@@ -205,22 +212,23 @@ public class RenderDeviceJme implements RenderDevice {
* @deprecated use renderFont(RenderFont font, String str, int x, int y, Color color, float sizeX, float sizeY) instead
*/
@Deprecated
- public void renderFont(RenderFont font, String str, int x, int y, Color color, float size){
+ public void renderFont(RenderFont font, String str, int x, int y, Color color, float size) {
renderFont(font, str, x, y, color, size, size);
}
-
+
@Override
- public void renderFont(RenderFont font, String str, int x, int y, Color color, float sizeX, float sizeY){
- //TODO find out what the f1 param is for
- if (str.length() == 0)
+ public void renderFont(RenderFont font, String str, int x, int y, Color color, float sizeX, float sizeY) {
+ if (str.length() == 0) {
return;
-
- if (font instanceof RenderFontNull)
+ }
+
+ if (font instanceof RenderFontNull) {
return;
-
+ }
+
RenderFontJme jmeFont = (RenderFontJme) font;
- String key = font+str+color.getColorString();
+ String key = font + str + color.getColorString();
BitmapText text = textCacheLastFrame.get(key);
if (text == null) {
text = jmeFont.createText();
@@ -228,166 +236,149 @@ public class RenderDeviceJme implements RenderDevice {
text.updateLogicalState(0);
}
textCacheCurrentFrame.put(key, text);
-
- niftyMat.setColor("Color", convertColor(color, tempColor));
- niftyMat.setBoolean("UseTex", true);
+
+ niftyMat.setColor("Color", convertColor(color, tempColor));
niftyMat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
// niftyMat.getAdditionalRenderState().setBlendMode(convertBlend());
text.setMaterial(niftyMat);
-
- float width = text.getLineWidth();
- float height = text.getLineHeight();
-
- float x0 = x + 0.5f * width * (1f - sizeX);
- float y0 = y + 0.5f * height * (1f - sizeY);
-
+
tempMat.loadIdentity();
- tempMat.setTranslation(x0, getHeight() - y0, 0);
+ tempMat.setTranslation(x, getHeight() - y, 0);
tempMat.setScale(sizeX, sizeY, 0);
-
+
rm.setWorldMatrix(tempMat);
text.render(rm);
-
+
// System.out.println("renderFont");
}
-
+
public void renderImage(RenderImage image, int x, int y, int w, int h,
- int srcX, int srcY, int srcW, int srcH,
- Color color, float scale,
- int centerX, int centerY){
+ int srcX, int srcY, int srcW, int srcH,
+ Color color, float scale,
+ int centerX, int centerY) {
RenderImageJme jmeImage = (RenderImageJme) image;
Texture2D texture = jmeImage.getTexture();
-
+
niftyMat.getAdditionalRenderState().setBlendMode(convertBlend());
- niftyMat.setColor("Color", ColorRGBA.White);
- niftyMat.setTexture("Texture", texture);
- niftyMat.setBoolean("UseTex", true);
- setColor(color);
-
- float imageWidth = jmeImage.getWidth();
+ niftyMat.setColor("Color", convertColor(color, tempColor));
+ niftyMat.setTexture("Texture", texture);
+ //setColor(color);
+
+ float imageWidth = jmeImage.getWidth();
float imageHeight = jmeImage.getHeight();
FloatBuffer texCoords = (FloatBuffer) quadModTC.getData();
-
+
float startX = srcX / imageWidth;
float startY = srcY / imageHeight;
- float endX = startX + (srcW / imageWidth);
- float endY = startY + (srcH / imageHeight);
-
+ float endX = startX + (srcW / imageWidth);
+ float endY = startY + (srcH / imageHeight);
+
startY = 1f - startY;
- endY = 1f - endY;
-
+ endY = 1f - endY;
+
texCoords.rewind();
texCoords.put(startX).put(startY);
- texCoords.put(endX) .put(startY);
- texCoords.put(endX) .put(endY);
+ texCoords.put(endX).put(startY);
+ texCoords.put(endX).put(endY);
texCoords.put(startX).put(endY);
texCoords.flip();
quadModTC.updateData(texCoords);
-
+
quad.clearBuffer(Type.TexCoord);
quad.setBuffer(quadModTC);
-
+
float x0 = centerX + (x - centerX) * scale;
float y0 = centerY + (y - centerY) * scale;
-
+
tempMat.loadIdentity();
tempMat.setTranslation(x0, getHeight() - y0, 0);
tempMat.setScale(w * scale, h * scale, 0);
-
+
rm.setWorldMatrix(tempMat);
niftyMat.render(quadGeom, rm);
//
// System.out.println("renderImage (Sub)");
}
-
+
public void renderImage(RenderImage image, int x, int y, int width, int height,
- Color color, float imageScale){
-
+ Color color, float imageScale) {
+
RenderImageJme jmeImage = (RenderImageJme) image;
-
+
niftyMat.getAdditionalRenderState().setBlendMode(convertBlend());
- niftyMat.setColor("Color", ColorRGBA.White);
- niftyMat.setTexture("Texture", jmeImage.getTexture());
- niftyMat.setBoolean("UseTex", true);
- setColor(color);
-
+ niftyMat.setColor("Color", convertColor(color, tempColor));
+ niftyMat.setTexture("Texture", jmeImage.getTexture());
+ //setColor(color);
+
quad.clearBuffer(Type.TexCoord);
quad.setBuffer(quadDefaultTC);
-
- float x0 = x + 0.5f * width * (1f - imageScale);
+
+ float x0 = x + 0.5f * width * (1f - imageScale);
float y0 = y + 0.5f * height * (1f - imageScale);
-
+
tempMat.loadIdentity();
tempMat.setTranslation(x0, getHeight() - y0, 0);
tempMat.setScale(width * imageScale, height * imageScale, 0);
-
+
rm.setWorldMatrix(tempMat);
niftyMat.render(quadGeom, rm);
//
// System.out.println("renderImage");
}
-
- public void renderQuad(int x, int y, int width, int height, Color color){
- niftyMat.getAdditionalRenderState().setBlendMode(convertBlend());
- niftyMat.setColor("Color", ColorRGBA.White);
- niftyMat.clearParam("Texture");
- niftyMat.setBoolean("UseTex", false);
- setColor(color);
-
- tempMat.loadIdentity();
- tempMat.setTranslation(x, getHeight() - y, 0);
- tempMat.setScale(width, height, 0);
-
- rm.setWorldMatrix(tempMat);
- niftyMat.render(quadGeom, rm);
-
+
+ public void renderQuad(int x, int y, int width, int height, Color color) {
+ if (color.getAlpha() > 0) {
+ niftyQuadMat.getAdditionalRenderState().setBlendMode(convertBlend());
+ niftyQuadMat.setColor("Color", convertColor(color, tempColor));
+
+ tempMat.loadIdentity();
+ tempMat.setTranslation(x, getHeight() - y, 0);
+ tempMat.setScale(width, height, 0);
+
+ rm.setWorldMatrix(tempMat);
+ niftyQuadMat.render(quadGeom, rm);
+ }
// System.out.println("renderQuad (Solid)");
}
-
+
public void renderQuad(int x, int y, int width, int height,
- Color topLeft, Color topRight, Color bottomRight, Color bottomLeft) {
+ Color topLeft, Color topRight, Color bottomRight, Color bottomLeft) {
ByteBuffer buf = (ByteBuffer) quadColor.getData();
buf.rewind();
buf.putInt(convertColor(topRight));
buf.putInt(convertColor(topLeft));
-
+
buf.putInt(convertColor(bottomLeft));
buf.putInt(convertColor(bottomRight));
buf.flip();
quadColor.updateData(buf);
- niftyMat.getAdditionalRenderState().setBlendMode(convertBlend());
- niftyMat.setColor("Color", ColorRGBA.White);
- niftyMat.clearParam("Texture");
- niftyMat.setBoolean("UseTex", false);
-
+ niftyQuadGradMat.getAdditionalRenderState().setBlendMode(convertBlend());
+
tempMat.loadIdentity();
tempMat.setTranslation(x, getHeight() - y, 0);
tempMat.setScale(width, height, 0);
-
+
rm.setWorldMatrix(tempMat);
- niftyMat.render(quadGeom, rm);
+ niftyQuadGradMat.render(quadGeom, rm);
//
// System.out.println("renderQuad (Grad)");
}
-
- public void enableClip(int x0, int y0, int x1, int y1){
+
+ public void enableClip(int x0, int y0, int x1, int y1) {
// System.out.println("enableClip");
clipWasSet = true;
r.setClipRect(x0, getHeight() - y1, x1 - x0, y1 - y0);
}
-
+
public void disableClip() {
// System.out.println("disableClip");
- if (clipWasSet){
+ if (clipWasSet) {
r.clearClipRect();
clipWasSet = false;
}
}
-
-
-
}
diff --git a/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java b/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java
index e7f4b10..fc8cc6b 100644
--- a/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java
+++ b/engine/src/ogre/com/jme3/scene/plugins/ogre/MeshLoader.java
@@ -712,9 +712,8 @@ public class MeshLoader extends DefaultHandler implements AssetLoader {
} else if (qName.equals("geometry")
|| qName.equals("sharedgeometry")) {
// finish writing to buffers
- IntMap<VertexBuffer> bufs = mesh.getBuffers();
- for (Entry<VertexBuffer> entry : bufs) {
- Buffer data = entry.getValue().getData();
+ for (VertexBuffer buf : mesh.getBufferList().getArray()) {
+ Buffer data = buf.getData();
if (data.position() != 0) {
data.flip();
}
diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java b/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java
index 3944b98..3348b48 100644
--- a/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java
+++ b/engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java
@@ -34,6 +34,7 @@ package com.jme3.terrain.geomipmap;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.math.FastMath;
+import com.jme3.math.Plane;
import com.jme3.math.Triangle;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
@@ -87,7 +88,7 @@ public class LODGeomap extends GeoMap {
IntBuffer ib = writeIndexArrayLodDiff(null, lod, rightLod, topLod, leftLod, bottomLod);
FloatBuffer bb = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
FloatBuffer tanb = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
- writeTangentArray(tanb, bb, texb, scale);
+ writeTangentArray(nb, tanb, bb, texb, scale);
Mesh m = new Mesh();
m.setMode(Mode.TriangleStrip);
m.setBuffer(Type.Position, 3, pb);
@@ -627,7 +628,7 @@ public class LODGeomap extends GeoMap {
return num;
}
- public FloatBuffer[] writeTangentArray(FloatBuffer tangentStore, FloatBuffer binormalStore, FloatBuffer textureBuffer, Vector3f scale) {
+ public FloatBuffer[] writeTangentArray(FloatBuffer normalBuffer, FloatBuffer tangentStore, FloatBuffer binormalStore, FloatBuffer textureBuffer, Vector3f scale) {
if (!isLoaded()) {
throw new NullPointerException();
}
@@ -650,19 +651,31 @@ public class LODGeomap extends GeoMap {
}
binormalStore.rewind();
+ Vector3f normal = new Vector3f();
Vector3f tangent = new Vector3f();
Vector3f binormal = new Vector3f();
- Vector3f v1 = new Vector3f();
+ /*Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f();
Vector3f v3 = new Vector3f();
Vector2f t1 = new Vector2f();
Vector2f t2 = new Vector2f();
- Vector2f t3 = new Vector2f();
-
- //scale = Vector3f.UNIT_XYZ;
+ Vector2f t3 = new Vector2f();*/
for (int r = 0; r < getHeight(); r++) {
for (int c = 0; c < getWidth(); c++) {
+
+ int idx = (r * getWidth() + c) * 3;
+ normal.set(normalBuffer.get(idx), normalBuffer.get(idx+1), normalBuffer.get(idx+2));
+ tangent.set(normal.cross(new Vector3f(0,0,1)));
+ binormal.set(new Vector3f(1,0,0).cross(normal));
+
+ BufferUtils.setInBuffer(tangent.normalizeLocal(), tangentStore, (r * getWidth() + c)); // save the tangent
+ BufferUtils.setInBuffer(binormal.normalizeLocal(), binormalStore, (r * getWidth() + c)); // save the binormal
+ }
+ }
+
+/* for (int r = 0; r < getHeight(); r++) {
+ for (int c = 0; c < getWidth(); c++) {
int texIdx = ((getHeight() - 1 - r) * getWidth() + c) * 2; // pull from the end
int texIdxAbove = ((getHeight() - 1 - (r - 1)) * getWidth() + c) * 2; // pull from the end
@@ -702,7 +715,7 @@ public class LODGeomap extends GeoMap {
BufferUtils.setInBuffer(binormal, binormalStore, (r * getWidth() + c)); // save the binormal
}
}
-
+ */
return new FloatBuffer[]{tangentStore, binormalStore};
}
diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java
index 40cf190..83537af 100644
--- a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java
+++ b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java
@@ -314,13 +314,25 @@ public class TerrainPatch extends Geometry {
getMesh().getBuffer(Type.Normal).updateData(newNormalBuffer);
FloatBuffer newTangentBuffer = null;
FloatBuffer newBinormalBuffer = null;
- FloatBuffer[] tb = geomap.writeTangentArray(newTangentBuffer, newBinormalBuffer, (FloatBuffer)getMesh().getBuffer(Type.TexCoord).getData(), getWorldScale());
+ FloatBuffer[] tb = geomap.writeTangentArray(newNormalBuffer, newTangentBuffer, newBinormalBuffer, (FloatBuffer)getMesh().getBuffer(Type.TexCoord).getData(), getWorldScale());
newTangentBuffer = tb[0];
newBinormalBuffer = tb[1];
getMesh().getBuffer(Type.Tangent).updateData(newTangentBuffer);
getMesh().getBuffer(Type.Binormal).updateData(newBinormalBuffer);
}
+ private void setInBuffer(Mesh mesh, int index, Vector3f normal, Vector3f tangent, Vector3f binormal) {
+ VertexBuffer NB = mesh.getBuffer(Type.Normal);
+ VertexBuffer TB = mesh.getBuffer(Type.Tangent);
+ VertexBuffer BB = mesh.getBuffer(Type.Binormal);
+ BufferUtils.setInBuffer(normal, (FloatBuffer)NB.getData(), index);
+ BufferUtils.setInBuffer(tangent, (FloatBuffer)TB.getData(), index);
+ BufferUtils.setInBuffer(binormal, (FloatBuffer)BB.getData(), index);
+ NB.setUpdateNeeded();
+ TB.setUpdateNeeded();
+ BB.setUpdateNeeded();
+ }
+
/**
* Matches the normals along the edge of the patch with the neighbours.
* Computes the normals for the right, bottom, left, and top edges of the
@@ -357,158 +369,122 @@ public class TerrainPatch extends Geometry {
Vector3f binormal = new Vector3f();
Vector3f normal = new Vector3f();
+
int s = this.getSize()-1;
if (right != null) { // right side, works its way down
for (int i=0; i<s+1; i++) {
- rootPoint.set(s, this.getHeightmapHeight(s,i), i);
- leftPoint.set(s-1, this.getHeightmapHeight(s-1,i), i);
- rightPoint.set(s+1, right.getHeightmapHeight(1,i), i);
+ rootPoint.set(0, this.getHeightmapHeight(s,i), 0);
+ leftPoint.set(-1, this.getHeightmapHeight(s-1,i), 0);
+ rightPoint.set(1, right.getHeightmapHeight(1,i), 0);
if (i == 0) { // top point
+ bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1);
+
if (top == null) {
- bottomPoint.set(s, this.getHeightmapHeight(s,i+1), i+1);
-
- averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer rightNB = right.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), s);
- BufferUtils.setInBuffer(normal, (FloatBuffer)rightNB.getData(), 0);
+ averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), s, normal, tangent, binormal);
+ setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
} else {
- topPoint.set(s, top.getHeightmapHeight(s,s-1), i-1);
- bottomPoint.set(s, this.getHeightmapHeight(s,i+1), i+1);
+ topPoint.set(0, top.getHeightmapHeight(s,s-1), -1);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer rightNB = right.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), s);
- BufferUtils.setInBuffer(normal, (FloatBuffer)rightNB.getData(), 0);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint,normal, tangent, binormal);
+ setInBuffer(this.getMesh(), s, normal, tangent, binormal);
+ setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
+ setInBuffer(top.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
if (topRight != null) {
- VertexBuffer topRightNB = topRight.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)topRightNB.getData(), (s+1)*s);
- topRightNB.setUpdateNeeded();
+ // setInBuffer(topRight.getMesh(), (s+1)*s, normal, tangent, binormal);
}
}
} else if (i == s) { // bottom point
+ topPoint.set(0, this.getHeightmapHeight(s,s-1), -1);
+
if (bottom == null) {
- topPoint.set(s, this.getHeightmapHeight(s,i-1), i-1);
-
- averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer rightNB = right.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(i+1)-1);
- BufferUtils.setInBuffer(normal, (FloatBuffer)rightNB.getData(), (s+1)*(s));
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
+ setInBuffer(right.getMesh(), (s+1)*(s), normal, tangent, binormal);
} else {
- topPoint.set(s, this.getHeightmapHeight(s,i-1), i-1);
- bottomPoint.set(s, bottom.getHeightmapHeight(s,1), i+1);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer rightNB = right.getMesh().getBuffer(Type.Normal);
- VertexBuffer downNB = bottom.getMesh().getBuffer(Type.Normal);
-
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(s+1)-1);
- BufferUtils.setInBuffer(normal, (FloatBuffer)rightNB.getData(), (s+1)*s);
- BufferUtils.setInBuffer(normal, (FloatBuffer)downNB.getData(), s);
+ bottomPoint.set(0, bottom.getHeightmapHeight(s,1), 1);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
+ setInBuffer(right.getMesh(), (s+1)*s, normal, tangent, binormal);
+ setInBuffer(bottom.getMesh(), s, normal, tangent, binormal);
if (bottomRight != null) {
- VertexBuffer bottomRightNB = bottomRight.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)bottomRightNB.getData(), 0);
- bottomRightNB.setUpdateNeeded();
+ // setInBuffer(bottomRight.getMesh(), 0, normal, tangent, binormal);
}
- downNB.setUpdateNeeded();
}
} else { // all in the middle
- topPoint.set(s, this.getHeightmapHeight(s,i-1), i-1);
- bottomPoint.set(s, this.getHeightmapHeight(s,i+1), i+1);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer rightNB = right.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(i+1)-1);
- BufferUtils.setInBuffer(normal, (FloatBuffer)rightNB.getData(), (s+1)*(i));
+ topPoint.set(0, this.getHeightmapHeight(s,i-1), -1);
+ bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
+ setInBuffer(right.getMesh(), (s+1)*(i), normal, tangent, binormal);
}
}
- right.getMesh().getBuffer(Type.Normal).setUpdateNeeded();
}
if (left != null) { // left side, works its way down
for (int i=0; i<s+1; i++) {
- rootPoint.set(0, this.getHeightmapHeight(0,i), i);
- leftPoint.set(-1, left.getHeightmapHeight(s-1,i), i);
- rightPoint.set(1, this.getHeightmapHeight(1,i), i);
+ rootPoint.set(0, this.getHeightmapHeight(0,i), 0);
+ leftPoint.set(-1, left.getHeightmapHeight(s-1,i), 0);
+ rightPoint.set(1, this.getHeightmapHeight(1,i), 0);
if (i == 0) { // top point
+ bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
+
if (top == null) {
- bottomPoint.set(0, this.getHeightmapHeight(0,i+1), i+1);
- averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer leftNB = left.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), 0);
- BufferUtils.setInBuffer(normal, (FloatBuffer)leftNB.getData(), s);
+ averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
+ setInBuffer(left.getMesh(), s, normal, tangent, binormal);
} else {
- topPoint.set(0, top.getHeightmapHeight(0,s-1), i-1);
- bottomPoint.set(0, this.getHeightmapHeight(0,i+1), i+1);
+ topPoint.set(0, top.getHeightmapHeight(0,s-1), -1);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer leftNB = left.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), 0);
- BufferUtils.setInBuffer(normal, (FloatBuffer)leftNB.getData(), s);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
+ setInBuffer(left.getMesh(), s, normal, tangent, binormal);
+ setInBuffer(top.getMesh(), (s+1)*s, normal, tangent, binormal);
if (topLeft != null) {
- VertexBuffer topLeftNB = topLeft.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)topLeftNB.getData(), (s+1)*(s+1)-1);
- topLeftNB.setUpdateNeeded();
+ // setInBuffer(topLeft.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
}
}
} else if (i == s) { // bottom point
+ topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
+
if (bottom == null) {
- topPoint.set(0, this.getHeightmapHeight(0,i-1), i-1);
-
- averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer leftNB = left.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(s));
- BufferUtils.setInBuffer(normal, (FloatBuffer)leftNB.getData(), (s+1)*(i+1)-1);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
+ setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
} else {
- topPoint.set(0, this.getHeightmapHeight(0,i-1), i-1);
- bottomPoint.set(0, bottom.getHeightmapHeight(0,1), i+1);
+ bottomPoint.set(0, bottom.getHeightmapHeight(0,1), 1);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer leftNB = left.getMesh().getBuffer(Type.Normal);
- VertexBuffer downNB = bottom.getMesh().getBuffer(Type.Normal);
-
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(s));
- BufferUtils.setInBuffer(normal, (FloatBuffer)leftNB.getData(), (s+1)*(i+1)-1);
- BufferUtils.setInBuffer(normal, (FloatBuffer)downNB.getData(), 0);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
+ setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
+ setInBuffer(bottom.getMesh(), 0, normal, tangent, binormal);
if (bottomLeft != null) {
- VertexBuffer bottomLeftNB = bottomLeft.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)bottomLeftNB.getData(), s);
- bottomLeftNB.setUpdateNeeded();
+ // setInBuffer(bottomLeft.getMesh(), s, normal, tangent, binormal);
}
- downNB.setUpdateNeeded();
}
} else { // all in the middle
- topPoint.set(0, this.getHeightmapHeight(0,i-1), i-1);
- bottomPoint.set(0, this.getHeightmapHeight(0,i+1), i+1);
+ topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
+ bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- VertexBuffer leftNB = left.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(i));
- BufferUtils.setInBuffer(normal, (FloatBuffer)leftNB.getData(), (s+1)*(i+1)-1);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(i), normal, tangent, binormal);
+ setInBuffer(left.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
}
}
- left.getMesh().getBuffer(Type.Normal).setUpdateNeeded();
}
-
+
if (top != null) { // top side, works its way right
for (int i=0; i<s+1; i++) {
- rootPoint.set(i, this.getHeightmapHeight(i,0), 0);
- topPoint.set(i, top.getHeightmapHeight(i,s-1), -1);
- bottomPoint.set(i, this.getHeightmapHeight(i,1), 1);
+ rootPoint.set(0, this.getHeightmapHeight(i,0), 0);
+ topPoint.set(0, top.getHeightmapHeight(i,s-1), -1);
+ bottomPoint.set(0, this.getHeightmapHeight(i,1), 1);
if (i == 0) { // left corner
// handled by left side pass
@@ -518,49 +494,39 @@ public class TerrainPatch extends Geometry {
// handled by this patch when it does its right side
} else { // all in the middle
- leftPoint.set(i-1, this.getHeightmapHeight(i-1,0), 0);
- rightPoint.set(i+1, this.getHeightmapHeight(i+1,0), 0);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), i);
- VertexBuffer topNB = top.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)topNB.getData(), (s+1)*(s)+i);
+ leftPoint.set(-1, this.getHeightmapHeight(i-1,0), 0);
+ rightPoint.set(1, this.getHeightmapHeight(i+1,0), 0);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), i, normal, tangent, binormal);
+ setInBuffer(top.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
}
}
- top.getMesh().getBuffer(Type.Normal).setUpdateNeeded();
}
if (bottom != null) { // bottom side, works its way right
for (int i=0; i<s+1; i++) {
- rootPoint.set(i, this.getHeightmapHeight(i,s), s);
- topPoint.set(i, this.getHeightmapHeight(i,s-1), s-1);
- bottomPoint.set(i, bottom.getHeightmapHeight(i,1), s+1);
+ rootPoint.set(0, this.getHeightmapHeight(i,s), 0);
+ topPoint.set(0, this.getHeightmapHeight(i,s-1), -1);
+ bottomPoint.set(0, bottom.getHeightmapHeight(i,1), 1);
if (i == 0) { // left
// handled by the left side pass
} else if (i == s) { // right
- // handled by this patch when it does its right side
+ // handled by the right side pass
} else { // all in the middle
- leftPoint.set(i-1, this.getHeightmapHeight(i-1,s), s);
- rightPoint.set(i+1, this.getHeightmapHeight(i+1,s), s);
- averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, null, null, null, null, null, normal, tangent, binormal);
- VertexBuffer tpNB = this.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)tpNB.getData(), (s+1)*(s)+i);
- VertexBuffer downNB = bottom.getMesh().getBuffer(Type.Normal);
- BufferUtils.setInBuffer(normal, (FloatBuffer)downNB.getData(), i);
+ leftPoint.set(-1, this.getHeightmapHeight(i-1,s), 0);
+ rightPoint.set(1, this.getHeightmapHeight(i+1,s), 0);
+ averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
+ setInBuffer(this.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
+ setInBuffer(bottom.getMesh(), i, normal, tangent, binormal);
}
}
- bottom.getMesh().getBuffer(Type.Normal).setUpdateNeeded();
}
-
- this.getMesh().getBuffer(Type.Normal).setUpdateNeeded();
- this.getMesh().getBuffer(Type.Tangent).setUpdateNeeded();
- this.getMesh().getBuffer(Type.Binormal).setUpdateNeeded();
}
protected void averageNormalsTangents(
@@ -569,38 +535,36 @@ public class TerrainPatch extends Geometry {
Vector3f leftPoint,
Vector3f bottomPoint,
Vector3f rightPoint,
- Vector2f topTex,
- Vector2f rootTex,
- Vector2f leftTex,
- Vector2f bottomTex,
- Vector2f rightTex,
Vector3f normal,
Vector3f tangent,
Vector3f binormal)
{
Vector3f scale = getWorldScale();
- Vector3f n1 = Vector3f.ZERO;
+ Vector3f n1 = new Vector3f(0,0,0);
if (topPoint != null && leftPoint != null) {
- n1 = calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale));
+ n1.set(calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale)));
}
- Vector3f n2 = Vector3f.ZERO;
+ Vector3f n2 = new Vector3f(0,0,0);
if (leftPoint != null && bottomPoint != null) {
- n2 = calculateNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale));
+ n2.set(calculateNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale)));
}
- Vector3f n3 = Vector3f.ZERO;
+ Vector3f n3 = new Vector3f(0,0,0);
if (rightPoint != null && bottomPoint != null) {
- n3 = calculateNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale));
+ n3.set(calculateNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale)));
}
- Vector3f n4 = Vector3f.ZERO;
+ Vector3f n4 = new Vector3f(0,0,0);
if (rightPoint != null && topPoint != null) {
- n4 = calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale));
+ n4.set(calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale)));
}
- if (bottomPoint != null && rightPoint != null && rootTex != null && rightTex != null && bottomTex != null)
- LODGeomap.calculateTangent(new Vector3f[]{rootPoint.mult(scale),rightPoint.mult(scale),bottomPoint.mult(scale)}, new Vector2f[]{rootTex,rightTex,bottomTex}, tangent, binormal);
+ //if (bottomPoint != null && rightPoint != null && rootTex != null && rightTex != null && bottomTex != null)
+ // LODGeomap.calculateTangent(new Vector3f[]{rootPoint.mult(scale),rightPoint.mult(scale),bottomPoint.mult(scale)}, new Vector2f[]{rootTex,rightTex,bottomTex}, tangent, binormal);
- normal.set(n1.add(n2).add(n3).add(n4).normalizeLocal());
+ normal.set(n1.add(n2).add(n3).add(n4).normalize());
+
+ tangent.set(normal.cross(new Vector3f(0,0,1)).normalize());
+ binormal.set(new Vector3f(1,0,0).cross(normal).normalize());
}
private Vector3f calculateNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {
diff --git a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java
index 0b9b218..1086c71 100644
--- a/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java
+++ b/engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java
@@ -1675,8 +1675,9 @@ public class TerrainQuad extends Node implements Terrain {
}
}
}
- else
+ else if (children.get(i) instanceof TerrainQuad) {
((TerrainQuad) children.get(i)).findPick(toTest, results);
+ }
}
}
}
diff --git a/engine/src/test/jme3test/app/TestAppStateLifeCycle.java b/engine/src/test/jme3test/app/TestAppStateLifeCycle.java
new file mode 100644
index 0000000..f224242
--- /dev/null
+++ b/engine/src/test/jme3test/app/TestAppStateLifeCycle.java
@@ -0,0 +1,126 @@
+/*
+ * 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 jme3test.app;
+
+import com.jme3.app.Application;
+import com.jme3.app.SimpleApplication;
+import com.jme3.app.state.AbstractAppState;
+import com.jme3.app.state.AppStateManager;
+import com.jme3.material.Material;
+import com.jme3.math.Vector3f;
+import com.jme3.renderer.RenderManager;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+
+/**
+ * Tests the app state lifecycles.
+ *
+ * @author Paul Speed
+ */
+public class TestAppStateLifeCycle extends SimpleApplication {
+
+ public static void main(String[] args){
+ TestAppStateLifeCycle app = new TestAppStateLifeCycle();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ Box b = new Box(Vector3f.ZERO, 1, 1, 1);
+ Geometry geom = new Geometry("Box", b);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ geom.setMaterial(mat);
+ rootNode.attachChild(geom);
+
+ System.out.println("Attaching test state.");
+ stateManager.attach(new TestState());
+ }
+
+ @Override
+ public void simpleUpdate(float tpf) {
+
+ if(stateManager.getState(TestState.class) != null) {
+ System.out.println("Detaching test state.");
+ stateManager.detach(stateManager.getState(TestState.class));
+ System.out.println("Done");
+ }
+ }
+
+ public class TestState extends AbstractAppState {
+
+ @Override
+ public void initialize(AppStateManager stateManager, Application app) {
+ super.initialize(stateManager, app);
+ System.out.println("Initialized");
+ }
+
+ @Override
+ public void stateAttached(AppStateManager stateManager) {
+ super.stateAttached(stateManager);
+ System.out.println("Attached");
+ }
+
+ @Override
+ public void update(float tpf) {
+ super.update(tpf);
+ System.out.println("update");
+ }
+
+ @Override
+ public void render(RenderManager rm) {
+ super.render(rm);
+ System.out.println("render");
+ }
+
+ @Override
+ public void postRender() {
+ super.postRender();
+ System.out.println("postRender");
+ }
+
+ @Override
+ public void stateDetached(AppStateManager stateManager) {
+ super.stateDetached(stateManager);
+ System.out.println("Detached");
+ }
+
+ @Override
+ public void cleanup() {
+ super.cleanup();
+ System.out.println("Cleanup");
+ }
+
+ }
+}
diff --git a/engine/src/test/jme3test/effect/TestSoftParticles.java b/engine/src/test/jme3test/effect/TestSoftParticles.java
new file mode 100644
index 0000000..d779a6f
--- /dev/null
+++ b/engine/src/test/jme3test/effect/TestSoftParticles.java
@@ -0,0 +1,130 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package jme3test.effect;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.ParticleMesh;
+import com.jme3.effect.shapes.EmitterSphereShape;
+import com.jme3.input.KeyInput;
+import com.jme3.input.controls.ActionListener;
+import com.jme3.input.controls.KeyTrigger;
+import com.jme3.material.Material;
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector3f;
+import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.TranslucentBucketFilter;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Box;
+
+/**
+ *
+ * @author Nehon
+ */
+public class TestSoftParticles extends SimpleApplication {
+
+ private boolean softParticles = true;
+ private FilterPostProcessor fpp;
+ private TranslucentBucketFilter tbf;
+
+ public static void main(String[] args) {
+ TestSoftParticles app = new TestSoftParticles();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+
+ cam.setLocation(new Vector3f(-7.2221026f, 4.1183004f, 7.759811f));
+ cam.setRotation(new Quaternion(0.06152846f, 0.91236454f, -0.1492115f, 0.37621948f));
+
+ flyCam.setMoveSpeed(10);
+
+
+ // -------- floor
+ Box b = new Box(Vector3f.ZERO, 10, 0.1f, 10);
+ Geometry geom = new Geometry("Box", b);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat.setColor("Color", ColorRGBA.Gray);
+ mat.setTexture("ColorMap", assetManager.loadTexture("Interface/Logo/Monkey.jpg"));
+ geom.setMaterial(mat);
+ rootNode.attachChild(geom);
+
+ Box b2 = new Box(Vector3f.ZERO, 1, 1, 1);
+ Geometry geom2 = new Geometry("Box", b2);
+ Material mat2 = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ mat2.setColor("Color", ColorRGBA.DarkGray);
+ geom2.setMaterial(mat2);
+ rootNode.attachChild(geom2);
+ geom2.setLocalScale(0.1f, 0.2f, 1);
+
+ fpp = new FilterPostProcessor(assetManager);
+ tbf = new TranslucentBucketFilter(true);
+ fpp.addFilter(tbf);
+ viewPort.addProcessor(fpp);
+
+
+ Material material = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
+ material.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
+
+ material.setFloat("Softness", 3f); //
+
+
+ //Fire
+ ParticleEmitter fire = new ParticleEmitter("Fire", ParticleMesh.Type.Triangle, 30);
+ fire.setMaterial(material);
+ fire.setShape(new EmitterSphereShape(Vector3f.ZERO, 0.1f));
+ fire.setImagesX(2);
+ fire.setImagesY(2); // 2x2 texture animation
+ fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red
+ fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
+ fire.setStartSize(0.6f);
+ fire.setEndSize(0.01f);
+ fire.setGravity(0, -0.3f, 0);
+ fire.setLowLife(0.5f);
+ fire.setHighLife(3f);
+ fire.setLocalTranslation(0, 0.2f, 0);
+
+ rootNode.attachChild(fire);
+
+
+ ParticleEmitter smoke = new ParticleEmitter("Smoke", ParticleMesh.Type.Triangle, 30);
+ smoke.setMaterial(material);
+ smoke.setShape(new EmitterSphereShape(Vector3f.ZERO, 5));
+ smoke.setImagesX(1);
+ smoke.setImagesY(1); // 2x2 texture animation
+ smoke.setStartColor(new ColorRGBA(0.1f, 0.1f, 0.1f,1f)); // dark gray
+ smoke.setEndColor(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.3f)); // gray
+ smoke.setStartSize(3f);
+ smoke.setEndSize(5f);
+ smoke.setGravity(0, -0.001f, 0);
+ smoke.setLowLife(100f);
+ smoke.setHighLife(100f);
+ smoke.setLocalTranslation(0, 0.1f, 0);
+ smoke.emitAllParticles();
+
+ rootNode.attachChild(smoke);
+
+
+ inputManager.addListener(new ActionListener() {
+
+ public void onAction(String name, boolean isPressed, float tpf) {
+ if(isPressed && name.equals("toggle")){
+ // tbf.setEnabled(!tbf.isEnabled());
+ softParticles = !softParticles;
+ if(softParticles){
+ viewPort.addProcessor(fpp);
+ }else{
+ viewPort.removeProcessor(fpp);
+ }
+ }
+ }
+ }, "toggle");
+ inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
+ }
+
+
+}
diff --git a/engine/src/test/jme3test/helloworld/HelloMaterial.java b/engine/src/test/jme3test/helloworld/HelloMaterial.java
index e930c91..8ef6f56 100644
--- a/engine/src/test/jme3test/helloworld/HelloMaterial.java
+++ b/engine/src/test/jme3test/helloworld/HelloMaterial.java
@@ -80,7 +80,7 @@ public class HelloMaterial extends SimpleApplication {
/** A cube with its base color "leaking" through a partially transparent texture */
Box boxshape4 = new Box(new Vector3f(3f,-1f,0f), 1f,1f,1f);
Geometry cube_leak = new Geometry("Leak-through color cube", boxshape4);
- Material mat_tl = new Material(assetManager, "Common/MatDefs/Misc/ColoredTextured.j3md");
+ Material mat_tl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat_tl.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));
mat_tl.setColor("Color", new ColorRGBA(1f,0f,1f, 1f)); // purple
cube_leak.setMaterial(mat_tl);
@@ -103,6 +103,7 @@ public class HelloMaterial extends SimpleApplication {
shiny_rock.setLocalTranslation(0,2,-2); // Move it a bit
shiny_rock.rotate(1.6f, 0, 0); // Rotate it a bit
rootNode.attachChild(shiny_rock);
+
/** Must add a light to make the lit object visible! */
DirectionalLight sun = new DirectionalLight();
sun.setDirection(new Vector3f(1,0,-2).normalizeLocal());
diff --git a/engine/src/test/jme3test/model/shape/TestExpandingTorus.java b/engine/src/test/jme3test/model/shape/TestExpandingTorus.java
new file mode 100644
index 0000000..9e76b3f
--- /dev/null
+++ b/engine/src/test/jme3test/model/shape/TestExpandingTorus.java
@@ -0,0 +1,45 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package jme3test.model.shape;
+
+import com.jme3.app.SimpleApplication;
+import com.jme3.material.Material;
+import com.jme3.scene.Geometry;
+import com.jme3.scene.shape.Torus;
+
+public class TestExpandingTorus extends SimpleApplication {
+
+ private float outerRadius = 1.5f;
+ private float rate = 1;
+ private Torus torus;
+ private Geometry geom;
+
+ public static void main(String[] args) {
+ TestExpandingTorus app = new TestExpandingTorus();
+ app.start();
+ }
+
+ @Override
+ public void simpleInitApp() {
+ torus = new Torus(30, 10, .5f, 1f);
+ geom = new Geometry("Torus", torus);
+ Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
+ geom.setMaterial(mat);
+ rootNode.attachChild(geom);
+ }
+
+ @Override
+ public void simpleUpdate(float tpf){
+ if (outerRadius > 2.5f){
+ outerRadius = 2.5f;
+ rate = -rate;
+ }else if (outerRadius < 1f){
+ outerRadius = 1f;
+ rate = -rate;
+ }
+ outerRadius += rate * tpf;
+ torus.updateGeometry(30, 10, .5f, outerRadius);
+ }
+} \ No newline at end of file
diff --git a/engine/src/tools/jme3tools/converters/model/ModelConverter.java b/engine/src/tools/jme3tools/converters/model/ModelConverter.java
index 2539574..6383d43 100644
--- a/engine/src/tools/jme3tools/converters/model/ModelConverter.java
+++ b/engine/src/tools/jme3tools/converters/model/ModelConverter.java
@@ -69,7 +69,7 @@ public class ModelConverter {
ts.setListsOnly(listOnly);
ts.setMinStripSize(minStripSize);
- IndexBuffer ib = mesh.getIndexBuffer();
+ IndexBuffer ib = mesh.getIndicesAsList();
int[] indices = new int[ib.size()];
for (int i = 0; i < indices.length; i++)
indices[i] = ib.get(i);
@@ -157,7 +157,7 @@ public class ModelConverter {
mesh.setBuffer(vb);
}
}
- mesh.setInterleaved();
+ //mesh.setInterleaved();
}
private static void optimizeScene(Spatial source, boolean toFixed){
diff --git a/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java b/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java
index ae6ad8c..121d75c 100644
--- a/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java
+++ b/engine/src/tools/jme3tools/optimize/GeometryBatchFactory.java
@@ -62,26 +62,27 @@ public class GeometryBatchFactory {
}
}
- private static void doTransformTangents(FloatBuffer inBuf, int offset, FloatBuffer outBuf, Matrix4f transform) {
+ private static void doTransformTangents(FloatBuffer inBuf, int offset, int components, FloatBuffer outBuf, Matrix4f transform) {
Vector3f tan = new Vector3f();
- float handedness = 0;
+
// offset is given in element units
// convert to be in component units
- offset *= 4;
+ offset *= components;
- for (int i = 0; i < inBuf.capacity() / 4; i++) {
- tan.x = inBuf.get(i * 4 + 0);
- tan.y = inBuf.get(i * 4 + 1);
- tan.z = inBuf.get(i * 4 + 2);
- handedness = inBuf.get(i * 4 + 3);
+ for (int i = 0; i < inBuf.capacity() / components; i++) {
+ tan.x = inBuf.get(i * components + 0);
+ tan.y = inBuf.get(i * components + 1);
+ tan.z = inBuf.get(i * components + 2);
transform.multNormal(tan, tan);
- outBuf.put(offset + i * 4 + 0, tan.x);
- outBuf.put(offset + i * 4 + 1, tan.y);
- outBuf.put(offset + i * 4 + 2, tan.z);
- outBuf.put(offset + i * 4 + 3, handedness);
-
+ outBuf.put(offset + i * components + 0, tan.x);
+ outBuf.put(offset + i * components + 1, tan.y);
+ outBuf.put(offset + i * components + 2, tan.z);
+
+ if (components == 4){
+ outBuf.put(offset + i * components + 3, inBuf.get(i * components + 3));
+ }
}
}
@@ -129,9 +130,9 @@ public class GeometryBatchFactory {
throw new UnsupportedOperationException();
}
- for (Entry<VertexBuffer> entry : geom.getMesh().getBuffers()) {
- compsForBuf[entry.getKey()] = entry.getValue().getNumComponents();
- formatForBuf[entry.getKey()] = entry.getValue().getFormat();
+ for (VertexBuffer vb : geom.getMesh().getBufferList().getArray()){
+ compsForBuf[vb.getBufferType().ordinal()] = vb.getNumComponents();
+ formatForBuf[vb.getBufferType().ordinal()] = vb.getFormat();
}
if (mode != null && mode != listMode) {
@@ -208,10 +209,11 @@ public class GeometryBatchFactory {
FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
doTransformNorms(inPos, globalVertIndex, outPos, worldMatrix);
- }else if(Type.Tangent.ordinal() == bufType){
+ }else if(Type.Tangent.ordinal() == bufType){
FloatBuffer inPos = (FloatBuffer) inBuf.getDataReadOnly();
FloatBuffer outPos = (FloatBuffer) outBuf.getData();
- doTransformTangents(inPos, globalVertIndex, outPos, worldMatrix);
+ int components = inBuf.getNumComponents();
+ doTransformTangents(inPos, globalVertIndex, components, outPos, worldMatrix);
} else {
inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount);
}