Adds the jMonkeyEngine library to the build.

Adds the jMonkeyEngine open source 3D game engine to the build. This
is built as a static library and is only used by the Finsky client.

Change-Id: I06a3f054df7b8a67757267d884854f70c5a16ca0
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag
new file mode 100644
index 0000000..5e77548
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.frag
@@ -0,0 +1,13 @@
+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/Nifty.j3md b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.j3md
new file mode 100644
index 0000000..9ba39b1
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.j3md
@@ -0,0 +1,21 @@
+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

+

+        WorldParameters {

+            WorldViewProjectionMatrix

+        }

+    }

+

+    Technique FixedFunc {

+    }

+

+}
\ No newline at end of file
diff --git a/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert
new file mode 100644
index 0000000..67c864d
--- /dev/null
+++ b/engine/src/niftygui/Common/MatDefs/Nifty/Nifty.vert
@@ -0,0 +1,16 @@
+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;

+}
\ No newline at end of file
diff --git a/engine/src/niftygui/com/jme3/cinematic/events/GuiTrack.java b/engine/src/niftygui/com/jme3/cinematic/events/GuiTrack.java
new file mode 100644
index 0000000..281c450
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/cinematic/events/GuiTrack.java
@@ -0,0 +1,119 @@
+/*
+ * 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.cinematic.events;
+
+import com.jme3.animation.LoopMode;
+import com.jme3.app.Application;
+import com.jme3.cinematic.Cinematic;
+import com.jme3.export.InputCapsule;
+import com.jme3.export.JmeExporter;
+import com.jme3.export.JmeImporter;
+import com.jme3.export.OutputCapsule;
+import de.lessvoid.nifty.Nifty;
+import java.io.IOException;
+
+/**
+ *
+ * @author Nehon
+ */
+public class GuiTrack extends AbstractCinematicEvent {
+
+    protected String screen;
+    protected Nifty nifty;
+
+    public GuiTrack() {
+    }
+
+    public GuiTrack(Nifty nifty, String screen) {
+        this.screen = screen;
+        this.nifty = nifty;
+    }
+
+    public GuiTrack(Nifty nifty, String screen, float initialDuration) {
+        super(initialDuration);
+        this.screen = screen;
+        this.nifty = nifty;
+    }
+
+    public GuiTrack(Nifty nifty, String screen, LoopMode loopMode) {
+        super(loopMode);
+        this.screen = screen;
+        this.nifty = nifty;
+    }
+
+    public GuiTrack(Nifty nifty, String screen, float initialDuration, LoopMode loopMode) {
+        super(initialDuration, loopMode);
+        this.screen = screen;
+        this.nifty = nifty;
+    }
+
+    @Override
+    public void onPlay() {
+        System.out.println("screen should be "+screen);
+        nifty.gotoScreen(screen);
+    }
+
+    @Override
+    public void onStop() {
+        nifty.gotoScreen("");
+    }
+
+    @Override
+    public void onPause() {
+    }
+
+    public void setNifty(Nifty nifty) {
+        this.nifty = nifty;
+    }
+
+    public void setScreen(String screen) {
+        this.screen = screen;
+    }
+
+    @Override
+    public void onUpdate(float tpf) {
+    }
+
+    @Override
+    public void write(JmeExporter ex) throws IOException {
+        super.write(ex);
+        OutputCapsule oc = ex.getCapsule(this);
+        oc.write(screen, "screen", "");
+    }
+
+    @Override
+    public void read(JmeImporter im) throws IOException {
+        super.read(im);
+        InputCapsule ic = im.getCapsule(this);
+        screen = ic.readString("screen", "");
+    }
+}
diff --git a/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java b/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java
new file mode 100644
index 0000000..0b80131
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/InputSystemJme.java
@@ -0,0 +1,233 @@
+/*
+ * 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();
+    }
+    
+    
+}
diff --git a/engine/src/niftygui/com/jme3/niftygui/NiftyJmeDisplay.java b/engine/src/niftygui/com/jme3/niftygui/NiftyJmeDisplay.java
new file mode 100644
index 0000000..97ddf9d
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/NiftyJmeDisplay.java
@@ -0,0 +1,181 @@
+/*
+ * 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.asset.AssetInfo;
+import com.jme3.asset.AssetKey;
+import com.jme3.asset.AssetManager;
+import com.jme3.asset.AssetNotFoundException;
+import com.jme3.audio.AudioRenderer;
+import com.jme3.input.InputManager;
+import com.jme3.post.SceneProcessor;
+import com.jme3.renderer.RenderManager;
+import com.jme3.renderer.Renderer;
+import com.jme3.renderer.ViewPort;
+import com.jme3.renderer.queue.RenderQueue;
+import com.jme3.texture.FrameBuffer;
+import de.lessvoid.nifty.Nifty;
+import de.lessvoid.nifty.tools.TimeProvider;
+import de.lessvoid.nifty.tools.resourceloader.ResourceLocation;
+import java.io.InputStream;
+import java.net.URL;
+
+public class NiftyJmeDisplay implements SceneProcessor {
+
+    protected boolean inited = false;
+    protected Nifty nifty;
+    protected AssetManager assetManager;
+    protected RenderManager renderManager;
+    protected RenderDeviceJme renderDev;
+    protected InputSystemJme inputSys;
+    protected SoundDeviceJme soundDev;
+    protected Renderer renderer;
+    protected ViewPort vp;
+    
+    protected ResourceLocationJme resourceLocation;
+
+    protected int w, h;
+
+    protected class ResourceLocationJme implements ResourceLocation {
+
+        public InputStream getResourceAsStream(String path) {
+            AssetKey<Object> key = new AssetKey<Object>(path);
+            AssetInfo info = assetManager.locateAsset(key);
+            if (info != null){
+                return info.openStream();
+            }else{
+                throw new AssetNotFoundException(path);
+            }
+        }
+
+        public URL getResource(String path) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    //Empty constructor needed for jMP to create replacement input system
+    public NiftyJmeDisplay() {
+    }
+    
+    public NiftyJmeDisplay(AssetManager assetManager, 
+                           InputManager inputManager,
+                           AudioRenderer audioRenderer,
+                           ViewPort vp){
+        this.assetManager = assetManager;
+
+        w = vp.getCamera().getWidth();
+        h = vp.getCamera().getHeight();
+
+        soundDev = new SoundDeviceJme(assetManager, audioRenderer);
+        renderDev = new RenderDeviceJme(this);
+        inputSys = new InputSystemJme(inputManager);
+        if (inputManager != null)
+            inputManager.addRawInputListener(inputSys);
+        
+        nifty = new Nifty(renderDev, soundDev, inputSys, new TimeProvider());
+        inputSys.setNifty(nifty);
+
+        resourceLocation = new ResourceLocationJme();
+        nifty.getResourceLoader().removeAllResourceLocations();
+        nifty.getResourceLoader().addResourceLocation(resourceLocation);
+    }
+
+    public void initialize(RenderManager rm, ViewPort vp) {
+        this.renderManager = rm;
+        renderDev.setRenderManager(rm);
+        inited = true;
+        this.vp = vp;
+        this.renderer = rm.getRenderer();
+        
+        inputSys.setHeight(vp.getCamera().getHeight());
+    }
+
+    public Nifty getNifty() {
+        return nifty;
+    }
+
+    RenderDeviceJme getRenderDevice() {
+        return renderDev;
+    }
+
+    AssetManager getAssetManager() {
+        return assetManager;
+    }
+
+    RenderManager getRenderManager() {
+        return renderManager;
+    }
+
+    int getHeight() {
+        return h;
+    }
+
+    int getWidth() {
+        return w;
+    }
+
+    Renderer getRenderer(){
+        return renderer;
+    }
+
+    public void reshape(ViewPort vp, int w, int h) {
+        this.w = w;
+        this.h = h;
+        inputSys.setHeight(h);
+        nifty.resolutionChanged();
+    }
+
+    public boolean isInitialized() {
+        return inited;
+    }
+
+    public void preFrame(float tpf) {
+    }
+
+    public void postQueue(RenderQueue rq) {
+        // render nifty before anything else
+        renderManager.setCamera(vp.getCamera(), true);
+        //nifty.update();
+        nifty.render(false);
+        renderManager.setCamera(vp.getCamera(), false);
+    }
+
+    public void postFrame(FrameBuffer out) {
+    }
+
+    public void cleanup() {
+        inited = false;
+//        nifty.exit();
+    }
+
+}
diff --git a/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java b/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java
new file mode 100644
index 0000000..8977ed6
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/RenderDeviceJme.java
@@ -0,0 +1,393 @@
+/*

+ * 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.font.BitmapText;

+import com.jme3.material.Material;

+import com.jme3.material.RenderState;

+import com.jme3.math.ColorRGBA;

+import com.jme3.math.Matrix4f;

+import com.jme3.renderer.RenderManager;

+import com.jme3.renderer.Renderer;

+import com.jme3.scene.Geometry;

+import com.jme3.scene.VertexBuffer;

+import com.jme3.scene.VertexBuffer.Format;

+import com.jme3.scene.VertexBuffer.Type;

+import com.jme3.scene.VertexBuffer.Usage;

+import com.jme3.scene.shape.Quad;

+import com.jme3.texture.Texture2D;

+import com.jme3.util.BufferUtils;

+import de.lessvoid.nifty.elements.render.TextRenderer.RenderFontNull;

+import de.lessvoid.nifty.render.BlendMode;

+import de.lessvoid.nifty.spi.render.MouseCursor;

+import de.lessvoid.nifty.spi.render.RenderDevice;

+import de.lessvoid.nifty.spi.render.RenderFont;

+import de.lessvoid.nifty.spi.render.RenderImage;

+import de.lessvoid.nifty.tools.Color;

+import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;

+import java.nio.ByteBuffer;

+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 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){

+        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");

+        niftyMat.getAdditionalRenderState().setDepthTest(false);

+    }

+

+    public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {

+    }

+

+    public void setRenderManager(RenderManager rm){

+        this.rm = rm;

+        this.r = rm.getRenderer();

+    }

+

+    // TODO: Cursor support

+    public MouseCursor createMouseCursor(String str, int x, int y){

+        return new MouseCursor() {

+            public void dispose() {

+            }

+        };

+    }

+

+    public void enableMouseCursor(MouseCursor cursor){

+    }

+

+    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){

+            this.blendMode = blendMode;

+        }

+    }

+

+    private RenderState.BlendMode convertBlend(){

+        if (blendMode == null)

+            return RenderState.BlendMode.Off;

+        else if (blendMode == BlendMode.BLEND)

+            return RenderState.BlendMode.Alpha;

+        else if (blendMode == BlendMode.MULIPLY)

+            return RenderState.BlendMode.Modulate;

+        else

+            throw new UnsupportedOperationException();

+    }

+

+    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()));

+        return color2;

+    }

+

+    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);

+    }

+    

+    /**

+     * 

+     * @param font

+     * @param str

+     * @param x

+     * @param y

+     * @param color

+     * @param size 

+     * @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){        

+        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)

+            return;

+

+        if (font instanceof RenderFontNull)

+            return;

+

+        RenderFontJme jmeFont = (RenderFontJme) font;

+        

+        String key = font+str+color.getColorString();

+        BitmapText text = textCacheLastFrame.get(key);

+        if (text == null) {

+            text = jmeFont.createText();

+            text.setText(str);

+            text.updateLogicalState(0);

+        }

+        textCacheCurrentFrame.put(key, text);

+

+        niftyMat.setColor("Color", convertColor(color, tempColor));

+        niftyMat.setBoolean("UseTex", true);

+        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.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){

+        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();

+        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);

+

+        startY = 1f - startY;

+        endY   = 1f - endY;

+

+        texCoords.rewind();

+        texCoords.put(startX).put(startY);

+        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){

+

+        RenderImageJme jmeImage = (RenderImageJme) image;

+

+        niftyMat.getAdditionalRenderState().setBlendMode(convertBlend());

+        niftyMat.setColor("Color", ColorRGBA.White);

+        niftyMat.setTexture("Texture", jmeImage.getTexture());

+        niftyMat.setBoolean("UseTex", true);

+        setColor(color);

+

+        quad.clearBuffer(Type.TexCoord);

+        quad.setBuffer(quadDefaultTC);

+

+        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);

+        

+//        System.out.println("renderQuad (Solid)");

+    }

+

+    public void renderQuad(int x, int y, int width, int height,

+                           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);

+

+        tempMat.loadIdentity();

+        tempMat.setTranslation(x, getHeight() - y, 0);

+        tempMat.setScale(width, height, 0);

+

+        rm.setWorldMatrix(tempMat);

+        niftyMat.render(quadGeom, rm);

+//        

+//        System.out.println("renderQuad (Grad)");

+    }

+

+    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){

+            r.clearClipRect();

+            clipWasSet = false;

+        }

+    }

+

+    

+

+}

diff --git a/engine/src/niftygui/com/jme3/niftygui/RenderFontJme.java b/engine/src/niftygui/com/jme3/niftygui/RenderFontJme.java
new file mode 100644
index 0000000..dccef34
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/RenderFontJme.java
@@ -0,0 +1,121 @@
+/*

+ * 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.niftygui;

+

+import com.jme3.font.BitmapFont;

+import com.jme3.font.BitmapText;

+import de.lessvoid.nifty.spi.render.RenderFont;

+

+public class RenderFontJme implements RenderFont {

+

+    private NiftyJmeDisplay display;

+    private BitmapFont font;

+    private BitmapText text;

+    private float actualSize;

+

+    /**

+     * Initialize the font.

+     * @param name font filename

+     */

+    public RenderFontJme(String name, NiftyJmeDisplay display) {

+        this.display = display;

+        font = display.getAssetManager().loadFont(name);

+        if (font == null) {

+            throw new RuntimeException( "Font not loaded:" + name );

+        }

+        text = new BitmapText(font);

+        actualSize = font.getPreferredSize();

+        text.setSize(actualSize);

+    }

+

+    public BitmapText createText() {

+      return new BitmapText(font);

+    }

+

+    public BitmapText getText(){

+        return text;

+    }

+

+    /**

+     * get font height.

+     * @return height

+     */

+    public int getHeight() {

+        return (int) text.getLineHeight();

+    }

+

+    /**

+     * get font width of the given string.

+     * @param str text

+     * @return width of the given text for the current font

+     */

+    public int getWidth(final String str) {

+        if (str.length() == 0)

+            return 0;

+ 

+        // Note: BitmapFont is now fixed to return the proper line width

+        //       at least for now.  The older commented out (by someone else, not me)

+        //       code below is arguably 'more accurate' if BitmapFont gets

+        //       buggy again.  The issue is that the BitmapText and BitmapFont

+        //       use a different algorithm for calculating size and both must

+        //       be modified in sync.       

+        int result = (int) font.getLineWidth(str);

+//        text.setText(str);

+//        text.updateLogicalState(0);

+//        int result = (int) text.getLineWidth();

+

+        return result;

+    }

+

+    public int getWidth(final String str, final float size) {

+      // Note: This is supposed to return the width of the String when scaled

+      //       with the size factor. Since I don't know how to do that with

+      //       the font rendering in jme this will only work correctly with

+      //       a size value of 1.f and will return inaccurate values otherwise.

+      return getWidth(str);

+    }

+

+    /**

+     * Return the width of the given character including kerning information.

+     * @param currentCharacter current character

+     * @param nextCharacter next character

+     * @param size font size

+     * @return width of the character or null when no information for the character is available

+     */

+    public int getCharacterAdvance(final char currentCharacter, final char nextCharacter, final float size) {

+        return Math.round(font.getCharacterAdvance(currentCharacter, nextCharacter, size));

+    }

+

+    public void dispose() {

+    }

+}

diff --git a/engine/src/niftygui/com/jme3/niftygui/RenderImageJme.java b/engine/src/niftygui/com/jme3/niftygui/RenderImageJme.java
new file mode 100644
index 0000000..e871e8a
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/RenderImageJme.java
@@ -0,0 +1,89 @@
+/*
+ * 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.asset.TextureKey;
+import com.jme3.texture.Image;
+import com.jme3.texture.Texture.MagFilter;
+import com.jme3.texture.Texture.MinFilter;
+import com.jme3.texture.Texture2D;
+import de.lessvoid.nifty.spi.render.RenderImage;
+
+public class RenderImageJme implements RenderImage {
+
+    private Texture2D texture;
+    private Image image;
+    private int width;
+    private int height;
+
+    public RenderImageJme(String filename, boolean linear, NiftyJmeDisplay display){
+        TextureKey key = new TextureKey(filename, true);
+
+        key.setAnisotropy(0);
+        key.setAsCube(false);
+        key.setGenerateMips(false);
+        
+        texture = (Texture2D) display.getAssetManager().loadTexture(key);
+        texture.setMagFilter(linear ? MagFilter.Bilinear : MagFilter.Nearest);
+        texture.setMinFilter(linear ? MinFilter.BilinearNoMipMaps : MinFilter.NearestNoMipMaps);
+        image = texture.getImage();
+
+        width = image.getWidth();
+        height = image.getHeight();
+    }
+
+    public RenderImageJme(Texture2D texture){
+        if (texture.getImage() == null)
+            throw new IllegalArgumentException("texture.getImage() cannot be null");
+        
+        this.texture = texture;
+        this.image = texture.getImage();
+        width = image.getWidth();
+        height = image.getHeight();
+    }
+
+    public Texture2D getTexture(){
+        return texture;
+    }
+
+    public int getWidth() {
+        return width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public void dispose() {
+    }
+}
diff --git a/engine/src/niftygui/com/jme3/niftygui/SoundDeviceJme.java b/engine/src/niftygui/com/jme3/niftygui/SoundDeviceJme.java
new file mode 100644
index 0000000..a936e03
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/SoundDeviceJme.java
@@ -0,0 +1,69 @@
+/*
+ * 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.asset.AssetManager;
+import com.jme3.audio.AudioNode;
+import com.jme3.audio.AudioRenderer;
+import de.lessvoid.nifty.sound.SoundSystem;
+import de.lessvoid.nifty.spi.sound.SoundDevice;
+import de.lessvoid.nifty.spi.sound.SoundHandle;
+import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
+
+public class SoundDeviceJme implements SoundDevice {
+
+    protected AssetManager assetManager;
+    protected AudioRenderer ar;
+
+    public SoundDeviceJme(AssetManager assetManager, AudioRenderer ar){
+        this.assetManager = assetManager;
+        this.ar = ar;
+    }
+
+    public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
+    }
+
+    public SoundHandle loadSound(SoundSystem soundSystem, String filename) {
+        AudioNode an = new AudioNode(assetManager, filename, false);
+        an.setPositional(false);
+        return new SoundHandleJme(ar, an);
+    }
+
+    public SoundHandle loadMusic(SoundSystem soundSystem, String filename) {
+        return new SoundHandleJme(ar, assetManager, filename);
+    }
+
+    public void update(int delta) {
+    }
+    
+}
diff --git a/engine/src/niftygui/com/jme3/niftygui/SoundHandleJme.java b/engine/src/niftygui/com/jme3/niftygui/SoundHandleJme.java
new file mode 100644
index 0000000..04ce42a
--- /dev/null
+++ b/engine/src/niftygui/com/jme3/niftygui/SoundHandleJme.java
@@ -0,0 +1,111 @@
+/*
+ * 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.asset.AssetManager;
+import com.jme3.audio.AudioNode;
+import com.jme3.audio.AudioNode.Status;
+import com.jme3.audio.AudioRenderer;
+import de.lessvoid.nifty.spi.sound.SoundHandle;
+
+public class SoundHandleJme implements SoundHandle {
+
+    private AudioNode node;
+    private AssetManager am;
+    private String fileName;
+    private float volume = 1;
+
+    public SoundHandleJme(AudioRenderer ar, AudioNode node){
+        if (ar == null || node == null)
+            throw new NullPointerException();
+
+        this.node = node;
+    }
+
+    /**
+     * For streaming music only. (May need to loop..)
+     * @param ar
+     * @param am
+     * @param fileName
+     */
+    public SoundHandleJme(AudioRenderer ar, AssetManager am, String fileName){
+        if (ar == null || am == null)
+            throw new NullPointerException();
+
+        this.am = am;
+        if (fileName == null)
+            throw new NullPointerException();
+        
+        this.fileName = fileName;
+    }
+
+    public void play() {
+        if (fileName != null){
+            if (node != null){
+                node.stop();
+            }
+
+            node = new AudioNode(am, fileName, true);
+            node.setPositional(false);
+            node.setVolume(volume);
+            node.play();
+        }else{
+            node.playInstance();
+        }
+    }
+
+    public void stop() {
+        if (node != null){
+            node.stop();
+            node = null;
+        }
+    }
+
+    public void setVolume(float f) {
+        if (node != null) {
+            node.setVolume(f);
+        }
+        volume = f;
+    }
+
+    public float getVolume() {
+        return volume;
+    }
+
+    public boolean isPlaying() {
+        return node != null && node.getStatus() == Status.Playing;
+    }
+
+    public void dispose() {
+    }
+}