Browse Source

Added Override annotations, finals, some cleanup and better null checks (#1271)

* Added Override annotations, finals, some cleanup and better null checks

* More general null check

* Follow naming conventions
Toni Helenius 5 years ago
parent
commit
427ae0a28b

+ 5 - 3
jme3-niftygui/src/main/java/com/jme3/cinematic/events/GuiEvent.java

@@ -37,6 +37,7 @@ import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import de.lessvoid.nifty.Nifty;
+import de.lessvoid.nifty.screen.Screen;
 import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -51,7 +52,7 @@ public class GuiEvent extends AbstractCinematicEvent {
     /**
      * message logger for this class
      */
-    static final Logger log = Logger.getLogger(GuiEvent.class.getName());
+    private static final Logger log = Logger.getLogger(GuiEvent.class.getName());
 
     /**
      * name of the associated Nifty screen(not null)
@@ -135,8 +136,9 @@ public class GuiEvent extends AbstractCinematicEvent {
      */
     @Override
     public void onStop() {
-        if (nifty.getCurrentScreen() != null) {
-            nifty.getCurrentScreen().endScreen(null);
+        Screen currentScreen = nifty.getCurrentScreen();
+        if (currentScreen != null) {
+            currentScreen.endScreen(null);
         }
     }
 

+ 4 - 2
jme3-niftygui/src/main/java/com/jme3/cinematic/events/GuiTrack.java

@@ -37,6 +37,7 @@ import com.jme3.export.JmeExporter;
 import com.jme3.export.JmeImporter;
 import com.jme3.export.OutputCapsule;
 import de.lessvoid.nifty.Nifty;
+import de.lessvoid.nifty.screen.Screen;
 import java.io.IOException;
 
 /**
@@ -84,8 +85,9 @@ public class GuiTrack extends AbstractCinematicEvent {
 
     @Override
     public void onStop() {
-        if (nifty.getCurrentScreen() != null) {
-            nifty.getCurrentScreen().endScreen(null);
+        Screen currentScreen = nifty.getCurrentScreen();
+        if (currentScreen != null) {
+            currentScreen.endScreen(null);
         }
     }
 

+ 18 - 4
jme3-niftygui/src/main/java/com/jme3/niftygui/InputSystemJme.java

@@ -46,14 +46,15 @@ import de.lessvoid.nifty.input.keyboard.KeyboardInputEvent;
 import de.lessvoid.nifty.spi.input.InputSystem;
 import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
 import java.util.ArrayList;
+import java.util.List;
 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[] niftyOwnsDragging = new boolean[3];
+    private final List<InputEvent> inputQueue = new ArrayList<>();
+    private final InputManager inputManager;
+    private final boolean[] niftyOwnsDragging = new boolean[3];
     private int inputPointerId = -1;
     private int x, y;
     private int height;
@@ -65,6 +66,7 @@ public class InputSystemJme implements InputSystem, RawInputListener {
         this.inputManager = inputManager;
     }
 
+    @Override
     public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
     }
 
@@ -101,15 +103,18 @@ public class InputSystemJme implements InputSystem, RawInputListener {
         this.height = height;
     }
 
+    @Override
     public void setMousePosition(int x, int y) {
         // TODO: When does nifty use this?
     }
 
+    @Override
     public void beginInput() {
     }
 
+    @Override
     public void endInput() {
-        boolean result = nifty.update();
+        nifty.update();
     }
 
     private void handleMouseEvent(int button, boolean value, NiftyInputConsumer nic, InputEvent evt) {
@@ -251,6 +256,7 @@ public class InputSystemJme implements InputSystem, RawInputListener {
         }
     }
 
+    @Override
     public void onMouseMotionEvent(MouseMotionEvent evt) {
         // Only forward the event if there's actual motion involved.
         if (inputManager.isCursorVisible() && (evt.getDX() != 0
@@ -260,6 +266,7 @@ public class InputSystemJme implements InputSystem, RawInputListener {
         }
     }
 
+    @Override
     public void onMouseButtonEvent(MouseButtonEvent evt) {
         if (evt.getButtonIndex() >= 0 && evt.getButtonIndex() <= 2) {
             if (evt.isReleased() || inputManager.isCursorVisible()) {
@@ -270,20 +277,25 @@ public class InputSystemJme implements InputSystem, RawInputListener {
         }
     }
 
+    @Override
     public void onJoyAxisEvent(JoyAxisEvent evt) {
     }
 
+    @Override
     public void onJoyButtonEvent(JoyButtonEvent evt) {
     }
 
+    @Override
     public void onKeyEvent(KeyInputEvent evt) {
         inputQueue.add(evt);
     }
 
+    @Override
     public void onTouchEvent(TouchEvent evt) {
         inputQueue.add(evt);
     }
 
+    @Override
     public void forwardEvents(NiftyInputConsumer nic) {
         int queueSize = inputQueue.size();
 
@@ -317,6 +329,8 @@ public class InputSystemJme implements InputSystem, RawInputListener {
                     }
 
                     softTextDialogInput.requestDialog(SoftTextDialogInput.TEXT_ENTRY_DIALOG, "Enter Text", initialValue, new SoftTextDialogInputListener() {
+
+                        @Override
                         public void onSoftText(int action, String text) {
                             if (action == SoftTextDialogInputListener.COMPLETE) {
                                 textField.setText(text);

+ 558 - 541
jme3-niftygui/src/main/java/com/jme3/niftygui/JmeBatchRenderBackend.java

@@ -31,15 +31,6 @@
  */
 package com.jme3.niftygui;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.nio.ShortBuffer;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
 import com.jme3.asset.TextureKey;
 import com.jme3.material.Material;
 import com.jme3.material.RenderState;
@@ -54,570 +45,596 @@ import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Usage;
 import com.jme3.texture.Image.Format;
-import com.jme3.texture.image.ImageRaster;
 import com.jme3.texture.Texture.MagFilter;
 import com.jme3.texture.Texture.MinFilter;
 import com.jme3.texture.Texture2D;
 import com.jme3.texture.image.ColorSpace;
+import com.jme3.texture.image.ImageRaster;
 import com.jme3.util.BufferUtils;
-
-import de.lessvoid.nifty.render.batch.spi.BatchRenderBackend;
 import de.lessvoid.nifty.render.BlendMode;
+import de.lessvoid.nifty.render.batch.spi.BatchRenderBackend;
 import de.lessvoid.nifty.spi.render.MouseCursor;
 import de.lessvoid.nifty.tools.Color;
 import de.lessvoid.nifty.tools.Factory;
 import de.lessvoid.nifty.tools.ObjectPool;
 import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * Nifty GUI BatchRenderBackend Implementation for jMonkeyEngine.
+ *
  * @author void
  */
 public class JmeBatchRenderBackend implements BatchRenderBackend {
-  private static Logger log = Logger.getLogger(JmeBatchRenderBackend.class.getName());
-
-  private final ObjectPool<Batch> batchPool;
-  private final List<Batch> batches = new ArrayList<Batch>();
-
-  // a modify texture call needs a jme Renderer to execute. if we're called to modify a texture but don't
-  // have a Renderer yet - since it was not initialized on the jme side - we'll cache the modify texture calls
-  // in here and execute them later (at the next beginFrame() call).
-  private final List<ModifyTexture> modifyTextureCalls = new ArrayList<ModifyTexture>();
-
-  private RenderManager renderManager;
-  private NiftyJmeDisplay display;
-  private Map<Integer, Texture2D> textures = new HashMap<Integer, Texture2D>();
-  private int textureAtlasId = 1;
-  private Batch currentBatch;
-  private Matrix4f tempMat = new Matrix4f();
-  private ByteBuffer initialData;
-
-  // this is only used for debugging purpose and will make the removed textures filled with a color
-  // please note: the old way to init this via a system property has been
-  // removed since it's now possible to configure it using the
-  // BatchRenderConfiguration class when you create the NiftyJmeDisplay instance
-  private boolean fillRemovedTexture = false;
-
-  public JmeBatchRenderBackend(final NiftyJmeDisplay display) {
-    this.display = display;
-    this.batchPool = new ObjectPool<Batch>(new Factory<Batch>() {
-      @Override
-      public Batch createNew() {
-        return new Batch();
-      }
-    });
-  }
-
-  public void setRenderManager(final RenderManager rm) {
-    this.renderManager = rm;
-  }
-
-  @Override
-  public void setResourceLoader(final NiftyResourceLoader resourceLoader) {
-  }
-
-  @Override
-  public int getWidth() {
-    return display.getWidth();
-  }
-
-  @Override
-  public int getHeight() {
-    return display.getHeight();
-  }
-
-  @Override
-  public void beginFrame() {
-    log.fine("beginFrame()");
-
-    for (int i=0; i<batches.size(); i++) {
-      batchPool.free(batches.get(i));
-    }
-    batches.clear();
-
-    // in case we have pending modifyTexture calls we'll need to execute them now
-    if (!modifyTextureCalls.isEmpty()) {
-      Renderer renderer = display.getRenderer();
-      for (int i=0; i<modifyTextureCalls.size(); i++) {
-        modifyTextureCalls.get(i).execute(renderer);
-      }
-      modifyTextureCalls.clear();
-    }
-  }
-
-  @Override
-  public void endFrame() {
-    log.fine("endFrame");
-  }
-
-  @Override
-  public void clear() {
-  }
-
-  // TODO: Cursor support
-
-  @Override
-  public MouseCursor createMouseCursor(final String filename, final int hotspotX, final int hotspotY) throws IOException {
-    return new MouseCursor() {
-        @Override
-        public void dispose() {
+
+    private static final Logger log = Logger.getLogger(JmeBatchRenderBackend.class.getName());
+
+    private final ObjectPool<Batch> batchPool;
+    private final List<Batch> batches = new ArrayList<>();
+
+    // a modify texture call needs a jme Renderer to execute. if we're called to modify a texture but don't
+    // have a Renderer yet - since it was not initialized on the jme side - we'll cache the modify texture calls
+    // in here and execute them later (at the next beginFrame() call).
+    private final List<ModifyTexture> modifyTextureCalls = new ArrayList<>();
+
+    private RenderManager renderManager;
+    private NiftyJmeDisplay display;
+    private Map<Integer, Texture2D> textures = new HashMap<>();
+    private int textureAtlasId = 1;
+    private Batch currentBatch;
+    private Matrix4f tempMat = new Matrix4f();
+    private ByteBuffer initialData;
+
+    // this is only used for debugging purpose and will make the removed textures filled with a color
+    // please note: the old way to init this via a system property has been
+    // removed since it's now possible to configure it using the
+    // BatchRenderConfiguration class when you create the NiftyJmeDisplay instance
+    private boolean fillRemovedTexture = false;
+
+    public JmeBatchRenderBackend(final NiftyJmeDisplay display) {
+        this.display = display;
+        this.batchPool = new ObjectPool<>(new Factory<Batch>() {
+
+            @Override
+            public Batch createNew() {
+                return new Batch();
+            }
+        });
+    }
+
+    public void setRenderManager(final RenderManager rm) {
+        this.renderManager = rm;
+    }
+
+    @Override
+    public void setResourceLoader(final NiftyResourceLoader resourceLoader) {
+    }
+
+    @Override
+    public int getWidth() {
+        return display.getWidth();
+    }
+
+    @Override
+    public int getHeight() {
+        return display.getHeight();
+    }
+
+    @Override
+    public void beginFrame() {
+        log.fine("beginFrame()");
+
+        for (int i = 0; i < batches.size(); i++) {
+            batchPool.free(batches.get(i));
         }
+        batches.clear();
 
-        @Override
-        public void enable() {
+        // in case we have pending modifyTexture calls we'll need to execute them now
+        if (!modifyTextureCalls.isEmpty()) {
+            Renderer renderer = display.getRenderer();
+            for (int i = 0; i < modifyTextureCalls.size(); i++) {
+                modifyTextureCalls.get(i).execute(renderer);
+            }
+            modifyTextureCalls.clear();
         }
+    }
 
-        @Override
-        public void disable() {
+    @Override
+    public void endFrame() {
+        log.fine("endFrame");
+    }
+
+    @Override
+    public void clear() {
+    }
+
+    // TODO: Cursor support
+    @Override
+    public MouseCursor createMouseCursor(final String filename, final int hotspotX, final int hotspotY) throws IOException {
+        return new MouseCursor() {
+            @Override
+            public void dispose() {
+            }
+
+            @Override
+            public void enable() {
+            }
+
+            @Override
+            public void disable() {
+            }
+        };
+    }
+
+    @Override
+    public void enableMouseCursor(final MouseCursor mouseCursor) {
+    }
+
+    @Override
+    public void disableMouseCursor() {
+    }
+
+    @Override
+    public int createTextureAtlas(final int width, final int height) {
+        try {
+            int atlasId = addTexture(createAtlasTextureInternal(width, height));
+
+            // we just initialize a second buffer here that will replace the texture atlas image
+            initialData = BufferUtils.createByteBuffer(width * height * 4);
+            for (int i = 0; i < width * height; i++) {
+                initialData.put((byte) 0x00);
+                initialData.put((byte) 0xff);
+                initialData.put((byte) 0x00);
+                initialData.put((byte) 0xff);
+            }
+            return atlasId;
+        } catch (Exception e) {
+            log.log(Level.WARNING, e.getMessage(), e);
+            return 0; // TODO Nifty always expects this call to be successfull
+            // there currently is no way to return failure or something :/
         }
-    };
-  }
-
-  @Override
-  public void enableMouseCursor(final MouseCursor mouseCursor) {
-  }
-
-  @Override
-  public void disableMouseCursor() {
-  }
-
-  @Override
-  public int createTextureAtlas(final int width, final int height) {
-    try {
-      int atlasId = addTexture(createAtlasTextureInternal(width, height));
-
-      // we just initialize a second buffer here that will replace the texture atlas image
-      initialData = BufferUtils.createByteBuffer(width*height*4);
-      for (int i=0; i<width*height; i++) {
-        initialData.put((byte) 0x00);
-        initialData.put((byte) 0xff);
-        initialData.put((byte) 0x00);
-        initialData.put((byte) 0xff);
-      }
-      return atlasId;
-    } catch (Exception e) {
-      log.log(Level.WARNING, e.getMessage(), e);
-      return 0; // TODO Nifty always expects this call to be successfull
-                // there currently is no way to return failure or something :/
-    }
-  }
-
-  @Override
-  public void clearTextureAtlas(final int atlasId) {
-      initialData.rewind();
-      getTextureAtlas(atlasId).getImage().setData(initialData);
-  }
-
-  @Override
-  public Image loadImage(final String filename) {
-    TextureKey key = new TextureKey(filename, false);
-    key.setAnisotropy(0);
-    key.setGenerateMips(false);
-
-    Texture2D texture = (Texture2D) display.getAssetManager().loadTexture(key);
-    // Fix GLES format incompatibility issue with glTexSubImage 
-    Renderer renderer = display.getRenderer();
-    if(renderer==null || renderer.getCaps().contains(Caps.OpenGLES20)) {
-        if(texture.getImage().getFormat()!=Format.RGBA8) {
-            com.jme3.texture.Image sourceImage = texture.getImage();
-            int size = sourceImage.getWidth() * sourceImage.getHeight() * 4;
-            ByteBuffer buffer = BufferUtils.createByteBuffer(size);
-            com.jme3.texture.Image rgba8Image = new com.jme3.texture.Image(Format.RGBA8,
-                                         sourceImage.getWidth(),
-                                         sourceImage.getHeight(),
-                                         buffer,
-                                         sourceImage.getColorSpace());
-            
-            ImageRaster input = ImageRaster.create(sourceImage, 0, 0, false);
-            ImageRaster output = ImageRaster.create(rgba8Image, 0, 0, false);
-            ColorRGBA color = new ColorRGBA();
-
-            for (int y = 0; y < sourceImage.getHeight(); y++) {
-                for (int x = 0; x < sourceImage.getWidth(); x++) {
-                    output.setPixel(x, y, input.getPixel(x, y, color));
+    }
+
+    @Override
+    public void clearTextureAtlas(final int atlasId) {
+        initialData.rewind();
+        getTextureAtlas(atlasId).getImage().setData(initialData);
+    }
+
+    @Override
+    public Image loadImage(final String filename) {
+        TextureKey key = new TextureKey(filename, false);
+        key.setAnisotropy(0);
+        key.setGenerateMips(false);
+
+        Texture2D texture = (Texture2D) display.getAssetManager().loadTexture(key);
+        // Fix GLES format incompatibility issue with glTexSubImage
+        Renderer renderer = display.getRenderer();
+        if (renderer == null || renderer.getCaps().contains(Caps.OpenGLES20)) {
+            if (texture.getImage().getFormat() != Format.RGBA8) {
+                com.jme3.texture.Image sourceImage = texture.getImage();
+                int size = sourceImage.getWidth() * sourceImage.getHeight() * 4;
+                ByteBuffer buffer = BufferUtils.createByteBuffer(size);
+                com.jme3.texture.Image rgba8Image = new com.jme3.texture.Image(Format.RGBA8,
+                        sourceImage.getWidth(),
+                        sourceImage.getHeight(),
+                        buffer,
+                        sourceImage.getColorSpace());
+
+                ImageRaster input = ImageRaster.create(sourceImage, 0, 0, false);
+                ImageRaster output = ImageRaster.create(rgba8Image, 0, 0, false);
+                ColorRGBA color = new ColorRGBA();
+
+                for (int y = 0; y < sourceImage.getHeight(); y++) {
+                    for (int x = 0; x < sourceImage.getWidth(); x++) {
+                        output.setPixel(x, y, input.getPixel(x, y, color));
+                    }
                 }
+                return new ImageImpl(rgba8Image);
             }
-            return new ImageImpl(rgba8Image);
         }
+        return new ImageImpl(texture.getImage());
     }
-    return new ImageImpl(texture.getImage());
-  }
-
-  @Override
-  public Image loadImage(final ByteBuffer imageData, final int imageWidth, final int imageHeight) {
-    return new ImageImpl(new com.jme3.texture.Image(Format.RGBA8, imageWidth, imageHeight, imageData, ColorSpace.Linear));
-  }
-  
-  @Override
-  public void addImageToAtlas(final Image image, final int x, final int y, final int atlasTextureId) {
-    ImageImpl imageImpl = (ImageImpl) image;
-    imageImpl.modifyTexture(this, getTextureAtlas(atlasTextureId), x, y);
-  }
-
-  @Override
-  public int createNonAtlasTexture(final Image image) {
-    ImageImpl imageImpl = (ImageImpl) image;
-
-    Texture2D texture = new Texture2D(imageImpl.image);
-    texture.setMinFilter(MinFilter.NearestNoMipMaps);
-    texture.setMagFilter(MagFilter.Nearest);
-    return addTexture(texture);
-  }
-
-  @Override
-  public void deleteNonAtlasTexture(final int textureId) {
-    textures.remove(textureId);
-  }
-
-  @Override
-  public boolean existsNonAtlasTexture(final int textureId) {
-    return textures.containsKey(textureId);
-  }
-
-  @Override
-  public void beginBatch(final BlendMode blendMode, final int textureId) {
-    batches.add(batchPool.allocate());
-    currentBatch = batches.get(batches.size() - 1);
-    currentBatch.begin(blendMode, getTextureAtlas(textureId));
-  }
-
-  @Override
-  public void addQuad(
-      final float x,
-      final float y,
-      final float width,
-      final float height,
-      final Color color1,
-      final Color color2,
-      final Color color3,
-      final Color color4,
-      final float textureX,
-      final float textureY,
-      final float textureWidth,
-      final float textureHeight,
-      final int textureId) {
-    if (!currentBatch.canAddQuad()) {
-      beginBatch(currentBatch.getBlendMode(), textureId);
-    }
-    currentBatch.addQuadInternal(x, y, width, height, color1, color2, color3, color4, textureX, textureY, textureWidth, textureHeight);
-  }
-
-  @Override
-  public int render() {
-    for (int i=0; i<batches.size(); i++) {
-      Batch batch = batches.get(i);
-      batch.render();
-    }
-    return batches.size();
-  }
-
-  @Override
-  public void removeImageFromAtlas(final Image image, final int x, final int y, final int w, final int h, final int atlasTextureId) {
-    // Since we clear the whole texture when we switch screens it's not really necessary to remove data from the
-    // texture atlas when individual textures are removed. If necessary this can be enabled with a system property.
-    if (!fillRemovedTexture) {
-      return;
-    }
-
-    ByteBuffer initialData = BufferUtils.createByteBuffer(image.getWidth()*image.getHeight()*4);
-    for (int i=0; i<image.getWidth()*image.getHeight(); i++) {
-      initialData.put((byte) 0xff);
-      initialData.put((byte) 0x00);
-      initialData.put((byte) 0x00);
-      initialData.put((byte) 0xff);
-    }
-    initialData.rewind();
-    modifyTexture(
-        getTextureAtlas(atlasTextureId),
-        new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData, ColorSpace.sRGB),
-        x,
-        y);
-  }
-
-  /**
-   * Whether or not to render textures with high quality settings. Usually, setting to true will result in slower
-   * performance, but nicer looking textures, and vice versa. How high quality textures are rendered versus low quality
-   * textures will vary depending on the {@link de.lessvoid.nifty.render.batch.spi.BatchRenderBackend} implementation.
-   */
-  @Override
-  public void useHighQualityTextures(final boolean shouldUseHighQualityTextures) {
-      // TODO when true this should use something like linear filtering
-      // not sure right now how to tell jme about that ... might not be
-      // necessary to be set?
-  }
-
-  /**
-   * Whether or not to overwrite previously used atlas space with blank data. Setting to true will result in slower
-   * performance, but may be useful in debugging when visually inspecting the atlas, since there will not be portions
-   * of old images visible in currently unused atlas space.
-   */
-  @Override
-  public void fillRemovedImagesInAtlas(final boolean shouldFill) {
-    fillRemovedTexture = shouldFill;
-  }
-
-  // internal implementations
-
-  private Texture2D createAtlasTextureInternal(final int width, final int height) throws Exception {
-    ByteBuffer initialData = BufferUtils.createByteBuffer(width*height*4);
-    for (int i=0; i<width*height*4; i++) {
-      initialData.put((byte) 0x00);
-    }
-    initialData.rewind();
-
-    Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData, ColorSpace.sRGB));
-    texture.setMinFilter(MinFilter.NearestNoMipMaps);
-    texture.setMagFilter(MagFilter.Nearest);
-    return texture;
-  }
-
-  private void modifyTexture(
-      final Texture2D textureAtlas,
-      final com.jme3.texture.Image image,
-      final int x,
-      final int y) {
-    Renderer renderer = display.getRenderer();
-    if (renderer == null) {
-      // we have no renderer (yet) so we'll need to cache this call to the next beginFrame() call
-      modifyTextureCalls.add(new ModifyTexture(textureAtlas, image, x, y));
-      return;
-    }
-
-    // all is well, we can execute the modify right away
-    renderer.modifyTexture(textureAtlas, image, x, y);
-  }
-
-  private Texture2D getTextureAtlas(final int atlasId) {
-    return textures.get(atlasId);
-  }
-
-  private int addTexture(final Texture2D texture) {
-    final int atlasId = textureAtlasId++;
-    textures.put(atlasId, texture);
-    return atlasId;
-  }
-
-  /**
-   * Simple BatchRenderBackend.Image implementation that will transport the dimensions of an image as well as the
-   * actual bytes from the loadImage() to the addImageToTexture() method.
-   *
-   * @author void
-   */
-  private static class ImageImpl implements BatchRenderBackend.Image {
-    private final com.jme3.texture.Image image;
-
-    public ImageImpl(final com.jme3.texture.Image image) {
-      this.image = image;
-    }
-
-    public void modifyTexture(
-        final JmeBatchRenderBackend backend,
-        final Texture2D textureAtlas,
-        final int x,
-        final int y) {
-      backend.modifyTexture(textureAtlas, image, x, y);
+
+    @Override
+    public Image loadImage(final ByteBuffer imageData, final int imageWidth, final int imageHeight) {
+        return new ImageImpl(new com.jme3.texture.Image(Format.RGBA8, imageWidth, imageHeight, imageData, ColorSpace.Linear));
     }
 
     @Override
-    public int getWidth() {
-      return image.getWidth();
+    public void addImageToAtlas(final Image image, final int x, final int y, final int atlasTextureId) {
+        ImageImpl imageImpl = (ImageImpl) image;
+        imageImpl.modifyTexture(this, getTextureAtlas(atlasTextureId), x, y);
     }
 
     @Override
-    public int getHeight() {
-      return image.getHeight();
-    }
-  }
-
-  /**
-   * Used to delay ModifyTexture calls in case we don't have a JME3 Renderer yet.
-   * @author void
-   */
-  private static class ModifyTexture {
-    private Texture2D atlas;
-    private com.jme3.texture.Image image;
-    private int x;
-    private int y;
-
-    private ModifyTexture(final Texture2D atlas, final com.jme3.texture.Image image, final int x, final int y) {
-      this.atlas = atlas;
-      this.image = image;
-      this.x = x;
-      this.y = y;
-    }
-
-    public void execute(final Renderer renderer) {
-      renderer.modifyTexture(atlas, image, x, y);
-    }
-  }
-
-  /**
-   * This class helps us to manage the batch data. We'll keep a bunch of instances of this class around that will be
-   * reused when needed. Each Batch instance provides room for a certain amount of vertices and we'll use a new Batch
-   * when we exceed this amount of data.
-   *
-   * @author void
-   */
-  private class Batch {
-    // 4 vertices per quad and 8 vertex attributes for each vertex:
-    // - 2 x pos
-    // - 2 x texture
-    // - 4 x color
-    //
-    // stored into 3 different buffers: position, texture coords, vertex color
-    // and an additional buffer for indexes
-    //
-    // there is a fixed amount of primitives per batch. if we run out of vertices we'll start a new batch.
-    private final static int BATCH_MAX_QUADS = 2000;
-    private final static int BATCH_MAX_VERTICES = BATCH_MAX_QUADS * 4;
-
-    // individual buffers for all the vertex attributes
-    private final VertexBuffer vertexPos = new VertexBuffer(Type.Position);
-    private final VertexBuffer vertexTexCoord = new VertexBuffer(Type.TexCoord);
-    private final VertexBuffer vertexColor = new VertexBuffer(Type.Color);
-    private final VertexBuffer indexBuffer = new VertexBuffer(Type.Index);
-
-    private final Mesh mesh = new Mesh();
-    private final Geometry meshGeometry = new Geometry("nifty-quad", mesh);
-    private final RenderState renderState = new RenderState();
-
-    private FloatBuffer vertexPosBuffer;
-    private FloatBuffer vertexTexCoordBuffer;
-    private FloatBuffer vertexColorBuffer;
-    private ShortBuffer indexBufferBuffer;
-
-    // number of quads already added to this batch.
-    private int quadCount;
-    private short globalVertexIndex;
-
-    // current blend mode
-    private BlendMode blendMode = BlendMode.BLEND;
-    private Texture2D texture;
-    private Material material;
-
-    public Batch() {
-      // setup mesh
-      vertexPos.setupData(Usage.Stream, 2, VertexBuffer.Format.Float, BufferUtils.createFloatBuffer(BATCH_MAX_VERTICES * 2));
-      vertexPosBuffer = (FloatBuffer) vertexPos.getData();
-      mesh.setBuffer(vertexPos);
-
-      vertexTexCoord.setupData(Usage.Stream, 2, VertexBuffer.Format.Float, BufferUtils.createFloatBuffer(BATCH_MAX_VERTICES * 2));
-      vertexTexCoordBuffer = (FloatBuffer) vertexTexCoord.getData();
-      mesh.setBuffer(vertexTexCoord);
-
-      vertexColor.setupData(Usage.Stream, 4, VertexBuffer.Format.Float, BufferUtils.createFloatBuffer(BATCH_MAX_VERTICES * 4));
-      vertexColorBuffer = (FloatBuffer) vertexColor.getData();
-      mesh.setBuffer(vertexColor);
-
-      indexBuffer.setupData(Usage.Stream, 3, VertexBuffer.Format.UnsignedShort, BufferUtils.createShortBuffer(BATCH_MAX_QUADS * 2 * 3));
-      indexBufferBuffer = (ShortBuffer) indexBuffer.getData();
-      mesh.setBuffer(indexBuffer);
-
-      material = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
-      material.setBoolean("VertexColor", true);
-
-      renderState.setDepthTest(false);
-      renderState.setDepthWrite(false);
-    }
-
-    public void begin(final BlendMode blendMode, final Texture2D texture) {
-      this.blendMode = blendMode;
-      this.texture = texture;
-
-      quadCount = 0;
-      globalVertexIndex = 0;
-      vertexPosBuffer.clear();
-      vertexTexCoordBuffer.clear();
-      vertexColorBuffer.clear();
-      indexBufferBuffer.clear();
-    }
-
-    public BlendMode getBlendMode() {
-      return blendMode;
-    }
-
-    public void render() {
-      renderState.setBlendMode(convertBlend(blendMode));
-
-      vertexPosBuffer.flip();
-      vertexPos.updateData(vertexPosBuffer);
-
-      vertexTexCoordBuffer.flip();
-      vertexTexCoord.updateData(vertexTexCoordBuffer);
-
-      vertexColorBuffer.flip();
-      vertexColor.updateData(vertexColorBuffer);
-
-      indexBufferBuffer.flip();
-      indexBuffer.updateData(indexBufferBuffer);
-
-      tempMat.loadIdentity();
-      renderManager.setWorldMatrix(tempMat);
-      renderManager.setForcedRenderState(renderState);
-
-      material.setTexture("ColorMap", texture);
-      mesh.updateCounts();
-      material.render(meshGeometry, renderManager);
-      renderManager.setForcedRenderState(null);
-    }
-
-    private RenderState.BlendMode convertBlend(final BlendMode blendMode) {
-      if (blendMode == null) {
-          return RenderState.BlendMode.Off;
-      } else if (blendMode == BlendMode.BLEND) {
-          return RenderState.BlendMode.Alpha;
-      } else if (blendMode == BlendMode.MULIPLY) {
-          return RenderState.BlendMode.Alpha;
-      } else {
-          throw new UnsupportedOperationException();
-      }
-  }
-
-    public boolean canAddQuad() {
-      return (quadCount + 1) < BATCH_MAX_QUADS;
-    }
-
-    private void addQuadInternal(
-        final float x,
-        final float y,
-        final float width,
-        final float height,
-        final Color color1,
-        final Color color2,
-        final Color color3,
-        final Color color4,
-        final float textureX,
-        final float textureY,
-        final float textureWidth,
-        final float textureHeight) {
-      indexBufferBuffer.put((short)(globalVertexIndex + 0));
-      indexBufferBuffer.put((short)(globalVertexIndex + 3));
-      indexBufferBuffer.put((short)(globalVertexIndex + 2));
-
-      indexBufferBuffer.put((short)(globalVertexIndex + 0));
-      indexBufferBuffer.put((short)(globalVertexIndex + 2));
-      indexBufferBuffer.put((short)(globalVertexIndex + 1));
-
-      addVertex(x,         y,          textureX,                textureY,                 color1);
-      addVertex(x + width, y,          textureX + textureWidth, textureY,                 color2);
-      addVertex(x + width, y + height, textureX + textureWidth, textureY + textureHeight, color4);
-      addVertex(x,         y + height, textureX,                textureY + textureHeight, color3);
-
-      quadCount++;
-      globalVertexIndex += 4;
-    }
-
-    private void addVertex(final float x, final float y, final float tx, final float ty, final Color c) {
-      vertexPosBuffer.put(x);
-      vertexPosBuffer.put(getHeight() - y);
-      vertexTexCoordBuffer.put(tx);
-      vertexTexCoordBuffer.put(ty);
-      vertexColorBuffer.put(c.getRed());
-      vertexColorBuffer.put(c.getGreen());
-      vertexColorBuffer.put(c.getBlue());
-      vertexColorBuffer.put(c.getAlpha());
-    }
-  }
+    public int createNonAtlasTexture(final Image image) {
+        ImageImpl imageImpl = (ImageImpl) image;
+
+        Texture2D texture = new Texture2D(imageImpl.image);
+        texture.setMinFilter(MinFilter.NearestNoMipMaps);
+        texture.setMagFilter(MagFilter.Nearest);
+        return addTexture(texture);
+    }
+
+    @Override
+    public void deleteNonAtlasTexture(final int textureId) {
+        textures.remove(textureId);
+    }
+
+    @Override
+    public boolean existsNonAtlasTexture(final int textureId) {
+        return textures.containsKey(textureId);
+    }
+
+    @Override
+    public void beginBatch(final BlendMode blendMode, final int textureId) {
+        batches.add(batchPool.allocate());
+        currentBatch = batches.get(batches.size() - 1);
+        currentBatch.begin(blendMode, getTextureAtlas(textureId));
+    }
+
+    @Override
+    public void addQuad(
+            final float x,
+            final float y,
+            final float width,
+            final float height,
+            final Color color1,
+            final Color color2,
+            final Color color3,
+            final Color color4,
+            final float textureX,
+            final float textureY,
+            final float textureWidth,
+            final float textureHeight,
+            final int textureId) {
+        if (!currentBatch.canAddQuad()) {
+            beginBatch(currentBatch.getBlendMode(), textureId);
+        }
+        currentBatch.addQuadInternal(x, y, width, height, color1, color2, color3, color4, textureX, textureY, textureWidth, textureHeight);
+    }
+
+    @Override
+    public int render() {
+        for (int i = 0; i < batches.size(); i++) {
+            Batch batch = batches.get(i);
+            batch.render();
+        }
+        return batches.size();
+    }
+
+    @Override
+    public void removeImageFromAtlas(final Image image, final int x, final int y, final int w, final int h, final int atlasTextureId) {
+        // Since we clear the whole texture when we switch screens it's not really necessary to remove data from the
+        // texture atlas when individual textures are removed. If necessary this can be enabled with a system property.
+        if (!fillRemovedTexture) {
+            return;
+        }
+
+        ByteBuffer initialData = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4);
+        for (int i = 0; i < image.getWidth() * image.getHeight(); i++) {
+            initialData.put((byte) 0xff);
+            initialData.put((byte) 0x00);
+            initialData.put((byte) 0x00);
+            initialData.put((byte) 0xff);
+        }
+        initialData.rewind();
+        modifyTexture(
+                getTextureAtlas(atlasTextureId),
+                new com.jme3.texture.Image(Format.RGBA8, image.getWidth(), image.getHeight(), initialData, ColorSpace.sRGB),
+                x,
+                y);
+    }
+
+    /**
+     * Whether or not to render textures with high quality settings. Usually,
+     * setting to true will result in slower performance, but nicer looking
+     * textures, and vice versa. How high quality textures are rendered versus
+     * low quality textures will vary depending on the
+     * {@link de.lessvoid.nifty.render.batch.spi.BatchRenderBackend}
+     * implementation
+     *
+     * @param shouldUseHighQualityTextures
+     */
+    @Override
+    public void useHighQualityTextures(final boolean shouldUseHighQualityTextures) {
+        // TODO when true this should use something like linear filtering
+        // not sure right now how to tell jme about that ... might not be
+        // necessary to be set?
+    }
+
+    /**
+     * Whether or not to overwrite previously used atlas space with blank data.
+     * Setting to true will result in slower performance, but may be useful in
+     * debugging when visually inspecting the atlas, since there will not be
+     * portions of old images visible in currently unused atlas space.
+     *
+     * @param shouldFill
+     */
+    @Override
+    public void fillRemovedImagesInAtlas(final boolean shouldFill) {
+        fillRemovedTexture = shouldFill;
+    }
+
+    // internal implementations
+    private Texture2D createAtlasTextureInternal(final int width, final int height) throws Exception {
+        ByteBuffer initialData = BufferUtils.createByteBuffer(width * height * 4);
+        for (int i = 0; i < width * height * 4; i++) {
+            initialData.put((byte) 0x00);
+        }
+        initialData.rewind();
+
+        Texture2D texture = new Texture2D(new com.jme3.texture.Image(Format.RGBA8, width, height, initialData, ColorSpace.sRGB));
+        texture.setMinFilter(MinFilter.NearestNoMipMaps);
+        texture.setMagFilter(MagFilter.Nearest);
+        return texture;
+    }
+
+    private void modifyTexture(
+            final Texture2D textureAtlas,
+            final com.jme3.texture.Image image,
+            final int x,
+            final int y) {
+        Renderer renderer = display.getRenderer();
+        if (renderer == null) {
+            // we have no renderer (yet) so we'll need to cache this call to the next beginFrame() call
+            modifyTextureCalls.add(new ModifyTexture(textureAtlas, image, x, y));
+            return;
+        }
+
+        // all is well, we can execute the modify right away
+        renderer.modifyTexture(textureAtlas, image, x, y);
+    }
+
+    private Texture2D getTextureAtlas(final int atlasId) {
+        return textures.get(atlasId);
+    }
+
+    private int addTexture(final Texture2D texture) {
+        final int atlasId = textureAtlasId++;
+        textures.put(atlasId, texture);
+        return atlasId;
+    }
+
+    /**
+     * Simple BatchRenderBackend.Image implementation that will transport the
+     * dimensions of an image as well as the actual bytes from the loadImage()
+     * to the addImageToTexture() method.
+     *
+     * @author void
+     */
+    private static class ImageImpl implements BatchRenderBackend.Image {
+
+        private final com.jme3.texture.Image image;
+
+        public ImageImpl(final com.jme3.texture.Image image) {
+            this.image = image;
+        }
+
+        public void modifyTexture(
+                final JmeBatchRenderBackend backend,
+                final Texture2D textureAtlas,
+                final int x,
+                final int y) {
+            backend.modifyTexture(textureAtlas, image, x, y);
+        }
+
+        @Override
+        public int getWidth() {
+            return image.getWidth();
+        }
+
+        @Override
+        public int getHeight() {
+            return image.getHeight();
+        }
+    }
+
+    /**
+     * Used to delay ModifyTexture calls in case we don't have a JME3 Renderer
+     * yet.
+     *
+     * @author void
+     */
+    private static class ModifyTexture {
+
+        private final Texture2D atlas;
+        private final com.jme3.texture.Image image;
+        private final int x;
+        private final int y;
+
+        private ModifyTexture(final Texture2D atlas, final com.jme3.texture.Image image, final int x, final int y) {
+            this.atlas = atlas;
+            this.image = image;
+            this.x = x;
+            this.y = y;
+        }
+
+        public void execute(final Renderer renderer) {
+            renderer.modifyTexture(atlas, image, x, y);
+        }
+    }
+
+    /**
+     * This class helps us to manage the batch data. We'll keep a bunch of
+     * instances of this class around that will be reused when needed. Each
+     * Batch instance provides room for a certain amount of vertices and we'll
+     * use a new Batch when we exceed this amount of data.
+     *
+     * @author void
+     */
+    private class Batch {
+        // 4 vertices per quad and 8 vertex attributes for each vertex:
+        // - 2 x pos
+        // - 2 x texture
+        // - 4 x color
+        //
+        // stored into 3 different buffers: position, texture coords, vertex color
+        // and an additional buffer for indexes
+        //
+        // there is a fixed amount of primitives per batch. if we run out of vertices we'll start a new batch.
+
+        private final static int BATCH_MAX_QUADS = 2000;
+        private final static int BATCH_MAX_VERTICES = BATCH_MAX_QUADS * 4;
+
+        // individual buffers for all the vertex attributes
+        private final VertexBuffer vertexPos = new VertexBuffer(Type.Position);
+        private final VertexBuffer vertexTexCoord = new VertexBuffer(Type.TexCoord);
+        private final VertexBuffer vertexColor = new VertexBuffer(Type.Color);
+        private final VertexBuffer indexBuffer = new VertexBuffer(Type.Index);
+
+        private final Mesh mesh = new Mesh();
+        private final Geometry meshGeometry = new Geometry("nifty-quad", mesh);
+        private final RenderState renderState = new RenderState();
+
+        private final FloatBuffer vertexPosBuffer;
+        private final FloatBuffer vertexTexCoordBuffer;
+        private final FloatBuffer vertexColorBuffer;
+        private final ShortBuffer indexBufferBuffer;
+
+        // number of quads already added to this batch.
+        private int quadCount;
+        private short globalVertexIndex;
+
+        // current blend mode
+        private BlendMode blendMode = BlendMode.BLEND;
+        private Texture2D texture;
+        private final Material material;
+
+        public Batch() {
+            // setup mesh
+            vertexPos.setupData(Usage.Stream, 2, VertexBuffer.Format.Float, BufferUtils.createFloatBuffer(BATCH_MAX_VERTICES * 2));
+            vertexPosBuffer = (FloatBuffer) vertexPos.getData();
+            mesh.setBuffer(vertexPos);
+
+            vertexTexCoord.setupData(Usage.Stream, 2, VertexBuffer.Format.Float, BufferUtils.createFloatBuffer(BATCH_MAX_VERTICES * 2));
+            vertexTexCoordBuffer = (FloatBuffer) vertexTexCoord.getData();
+            mesh.setBuffer(vertexTexCoord);
+
+            vertexColor.setupData(Usage.Stream, 4, VertexBuffer.Format.Float, BufferUtils.createFloatBuffer(BATCH_MAX_VERTICES * 4));
+            vertexColorBuffer = (FloatBuffer) vertexColor.getData();
+            mesh.setBuffer(vertexColor);
+
+            indexBuffer.setupData(Usage.Stream, 3, VertexBuffer.Format.UnsignedShort, BufferUtils.createShortBuffer(BATCH_MAX_QUADS * 2 * 3));
+            indexBufferBuffer = (ShortBuffer) indexBuffer.getData();
+            mesh.setBuffer(indexBuffer);
+
+            material = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
+            material.setBoolean("VertexColor", true);
+
+            renderState.setDepthTest(false);
+            renderState.setDepthWrite(false);
+        }
+
+        public void begin(final BlendMode blendMode, final Texture2D texture) {
+            this.blendMode = blendMode;
+            this.texture = texture;
+
+            quadCount = 0;
+            globalVertexIndex = 0;
+            vertexPosBuffer.clear();
+            vertexTexCoordBuffer.clear();
+            vertexColorBuffer.clear();
+            indexBufferBuffer.clear();
+        }
+
+        public BlendMode getBlendMode() {
+            return blendMode;
+        }
+
+        public void render() {
+            renderState.setBlendMode(convertBlend(blendMode));
+
+            vertexPosBuffer.flip();
+            vertexPos.updateData(vertexPosBuffer);
+
+            vertexTexCoordBuffer.flip();
+            vertexTexCoord.updateData(vertexTexCoordBuffer);
+
+            vertexColorBuffer.flip();
+            vertexColor.updateData(vertexColorBuffer);
+
+            indexBufferBuffer.flip();
+            indexBuffer.updateData(indexBufferBuffer);
+
+            tempMat.loadIdentity();
+            renderManager.setWorldMatrix(tempMat);
+            renderManager.setForcedRenderState(renderState);
+
+            material.setTexture("ColorMap", texture);
+            mesh.updateCounts();
+            material.render(meshGeometry, renderManager);
+            renderManager.setForcedRenderState(null);
+        }
+
+        private RenderState.BlendMode convertBlend(final BlendMode blendMode) {
+            if (blendMode == null) {
+                return RenderState.BlendMode.Off;
+            } else {
+                switch (blendMode) {
+                    case BLEND:
+                        return RenderState.BlendMode.Alpha;
+                    case MULIPLY:
+                        return RenderState.BlendMode.Alpha;
+                    default:
+                        throw new UnsupportedOperationException();
+                }
+            }
+        }
+
+        public boolean canAddQuad() {
+            return (quadCount + 1) < BATCH_MAX_QUADS;
+        }
+
+        private void addQuadInternal(
+                final float x,
+                final float y,
+                final float width,
+                final float height,
+                final Color color1,
+                final Color color2,
+                final Color color3,
+                final Color color4,
+                final float textureX,
+                final float textureY,
+                final float textureWidth,
+                final float textureHeight) {
+            indexBufferBuffer.put((short) (globalVertexIndex + 0));
+            indexBufferBuffer.put((short) (globalVertexIndex + 3));
+            indexBufferBuffer.put((short) (globalVertexIndex + 2));
+
+            indexBufferBuffer.put((short) (globalVertexIndex + 0));
+            indexBufferBuffer.put((short) (globalVertexIndex + 2));
+            indexBufferBuffer.put((short) (globalVertexIndex + 1));
+
+            addVertex(x, y, textureX, textureY, color1);
+            addVertex(x + width, y, textureX + textureWidth, textureY, color2);
+            addVertex(x + width, y + height, textureX + textureWidth, textureY + textureHeight, color4);
+            addVertex(x, y + height, textureX, textureY + textureHeight, color3);
+
+            quadCount++;
+            globalVertexIndex += 4;
+        }
+
+        private void addVertex(final float x, final float y, final float tx, final float ty, final Color c) {
+            vertexPosBuffer.put(x);
+            vertexPosBuffer.put(getHeight() - y);
+            vertexTexCoordBuffer.put(tx);
+            vertexTexCoordBuffer.put(ty);
+            vertexColorBuffer.put(c.getRed());
+            vertexColorBuffer.put(c.getGreen());
+            vertexColorBuffer.put(c.getBlue());
+            vertexColorBuffer.put(c.getAlpha());
+        }
+    }
 }

+ 19 - 10
jme3-niftygui/src/main/java/com/jme3/niftygui/NiftyJmeDisplay.java

@@ -31,9 +31,6 @@
  */
 package com.jme3.niftygui;
 
-import java.io.InputStream;
-import java.net.URL;
-
 import com.jme3.asset.AssetInfo;
 import com.jme3.asset.AssetKey;
 import com.jme3.asset.AssetManager;
@@ -48,12 +45,13 @@ 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.render.batch.BatchRenderConfiguration;
 import de.lessvoid.nifty.render.batch.BatchRenderDevice;
 import de.lessvoid.nifty.spi.time.impl.AccurateTimeProvider;
 import de.lessvoid.nifty.tools.resourceloader.ResourceLocation;
+import java.io.InputStream;
+import java.net.URL;
 
 public class NiftyJmeDisplay implements SceneProcessor {
 
@@ -68,7 +66,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
     protected SoundDeviceJme soundDev;
     protected Renderer renderer;
     protected ViewPort vp;
-    
+
     protected ResourceLocationJme resourceLocation;
 
     protected int w, h;
@@ -76,8 +74,9 @@ public class NiftyJmeDisplay implements SceneProcessor {
 
     protected class ResourceLocationJme implements ResourceLocation {
 
+        @Override
         public InputStream getResourceAsStream(String path) {
-            AssetKey<Object> key = new AssetKey<Object>(path);
+            AssetKey<Object> key = new AssetKey<>(path);
             AssetInfo info = assetManager.locateAsset(key);
             if (info != null) {
                 return info.openStream();
@@ -86,6 +85,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
             }
         }
 
+        @Override
         public URL getResource(String path) {
             throw new UnsupportedOperationException();
         }
@@ -112,6 +112,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
      * @param inputManager jME InputManager
      * @param audioRenderer jME AudioRenderer
      * @param viewport Viewport to use
+     * @return new NiftyJmeDisplay instance
      */
     public static NiftyJmeDisplay newNiftyJmeDisplay(
         final AssetManager assetManager,
@@ -142,6 +143,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
      *        you can use to further configure batch rendering. If unsure you
      *        can simply use new BatchRenderConfiguration() in here for the
      *        default configuration which should give you good default values.
+     * @return new NiftyJmeDisplay instance
      */
     public static NiftyJmeDisplay newNiftyJmeDisplay(
         final AssetManager assetManager,
@@ -171,7 +173,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
      *
      * A complete re-organisation of the texture atlas happens when a Nifty screen ends and another begins. Dynamically
      * adding images while a screen is running is supported as well.
-     * 
+     *
      * @param assetManager jME AssetManager
      * @param inputManager jME InputManager
      * @param audioRenderer jME AudioRenderer
@@ -250,7 +252,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
      * @param audioRenderer jME AudioRenderer
      * @param vp Viewport to use
      */
-    public NiftyJmeDisplay(AssetManager assetManager, 
+    public NiftyJmeDisplay(AssetManager assetManager,
                            InputManager inputManager,
                            AudioRenderer audioRenderer,
                            ViewPort vp){
@@ -280,6 +282,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
       this.inputSys = new InputSystemJme(inputManager);
     }
 
+    @Override
     public void initialize(RenderManager rm, ViewPort vp) {
         this.renderManager = rm;
         if (renderDev != null) {
@@ -295,7 +298,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
         inited = true;
         this.vp = vp;
         this.renderer = rm.getRenderer();
-        
+
         inputSys.reset();
         inputSys.setHeight(vp.getCamera().getHeight());
     }
@@ -305,7 +308,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
     }
 
     public void simulateKeyEvent( KeyInputEvent event ) {
-        inputSys.onKeyEvent(event);        
+        inputSys.onKeyEvent(event);
     }
 
     AssetManager getAssetManager() {
@@ -328,6 +331,7 @@ public class NiftyJmeDisplay implements SceneProcessor {
         return renderer;
     }
 
+    @Override
     public void reshape(ViewPort vp, int w, int h) {
         this.w = w;
         this.h = h;
@@ -335,13 +339,16 @@ public class NiftyJmeDisplay implements SceneProcessor {
         nifty.resolutionChanged();
     }
 
+    @Override
     public boolean isInitialized() {
         return inited;
     }
 
+    @Override
     public void preFrame(float tpf) {
     }
 
+    @Override
     public void postQueue(RenderQueue rq) {
         // render nifty before anything else
         renderManager.setCamera(vp.getCamera(), true);
@@ -350,9 +357,11 @@ public class NiftyJmeDisplay implements SceneProcessor {
         renderManager.setCamera(vp.getCamera(), false);
     }
 
+    @Override
     public void postFrame(FrameBuffer out) {
     }
 
+    @Override
     public void cleanup() {
         inited = false;
         inputSys.reset();

+ 111 - 88
jme3-niftygui/src/main/java/com/jme3/niftygui/RenderDeviceJme.java

@@ -57,40 +57,41 @@ import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader;
 import java.nio.ByteBuffer;
 import java.nio.FloatBuffer;
 import java.util.HashMap;
+import java.util.Map;
 
 public class RenderDeviceJme implements RenderDevice {
-    
-    private NiftyJmeDisplay display;
+
+    private final NiftyJmeDisplay display;
     private RenderManager rm;
     private Renderer r;
-    private HashMap<CachedTextKey, BitmapText> textCacheLastFrame = new HashMap<CachedTextKey, BitmapText>();
-    private HashMap<CachedTextKey, BitmapText> textCacheCurrentFrame = new HashMap<CachedTextKey, BitmapText>();
+    private Map<CachedTextKey, BitmapText> textCacheLastFrame = new HashMap<>();
+    private Map<CachedTextKey, BitmapText> textCacheCurrentFrame = new HashMap<>();
     private final Quad quad = new Quad(1, -1, true);
     private final Geometry quadGeom = new Geometry("nifty-quad", quad);
     private boolean clipWasSet = false;
-    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();
-    private RenderState renderState = new RenderState();
-    
-    private Material colorMaterial;
-    private Material textureColorMaterial;
-    private Material vertexColorMaterial;
-    
+    private final VertexBuffer quadDefaultTC = quad.getBuffer(Type.TexCoord);
+    private final VertexBuffer quadModTC = quadDefaultTC.clone();
+    private final VertexBuffer quadColor;
+    private final Matrix4f tempMat = new Matrix4f();
+    private final ColorRGBA tempColor = new ColorRGBA();
+    private final RenderState renderState = new RenderState();
+
+    private final Material colorMaterial;
+    private final Material textureColorMaterial;
+    private final Material vertexColorMaterial;
+
     private static class CachedTextKey {
-        
+
         BitmapFont font;
         String text;
 //        ColorRGBA color;
-        
+
         public CachedTextKey(BitmapFont font, String text/*, ColorRGBA color*/) {
             this.font = font;
             this.text = text;
 //            this.color = color;
         }
-        
+
         @Override
         public boolean equals(Object other) {
             CachedTextKey otherKey = (CachedTextKey) other;
@@ -108,47 +109,51 @@ public class RenderDeviceJme implements RenderDevice {
             return hash;
         }
     }
-    
+
     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);
-        
+
         // Load the 3 material types separately to avoid
         // reloading the shader when the defines change.
-        
+
         // Material with a single color (no texture or vertex color)
         colorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
-        
+
         // Material with a texture and a color (no vertex color)
         textureColorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
-        
+
         // Material with vertex color, used for gradients (no texture)
         vertexColorMaterial = new Material(display.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
         vertexColorMaterial.setBoolean("VertexColor", true);
-        
+
         // Shared render state for all materials
         renderState.setDepthTest(false);
         renderState.setDepthWrite(false);
     }
-    
+
+    @Override
     public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
     }
-    
+
     public void setRenderManager(RenderManager rm) {
         this.rm = rm;
         this.r = rm.getRenderer();
     }
 
     // TODO: Cursor support
+    @Override
     public MouseCursor createMouseCursor(String str, int x, int y) {
         return new MouseCursor() {
+
+            @Override
             public void dispose() {
             }
 
@@ -161,60 +166,72 @@ public class RenderDeviceJme implements RenderDevice {
             }
         };
     }
-    
+
+    @Override
     public void enableMouseCursor(MouseCursor cursor) {
     }
-    
+
+    @Override
     public void disableMouseCursor() {
     }
-    
+
+    @Override
     public RenderImage createImage(String filename, boolean linear) {
         //System.out.println("createImage(" + filename + ", " + linear + ")");
         return new RenderImageJme(filename, linear, display);
     }
-    
+
+    @Override
     public RenderFont createFont(String filename) {
         return new RenderFontJme(filename, display);
     }
-    
+
+    @Override
     public void beginFrame() {
     }
-    
+
+    @Override
     public void endFrame() {
-        HashMap<CachedTextKey, BitmapText> temp = textCacheLastFrame;
+        Map<CachedTextKey, BitmapText> temp = textCacheLastFrame;
         textCacheLastFrame = textCacheCurrentFrame;
         textCacheCurrentFrame = temp;
         textCacheCurrentFrame.clear();
         rm.setForcedRenderState(null);
     }
-    
+
+    @Override
     public int getWidth() {
         return display.getWidth();
     }
-    
+
+    @Override
     public int getHeight() {
         return display.getHeight();
     }
-    
+
+    @Override
     public void clear() {
     }
-    
+
+    @Override
     public void setBlendMode(BlendMode blendMode) {
         renderState.setBlendMode(convertBlend(blendMode));
     }
-    
+
     private RenderState.BlendMode convertBlend(BlendMode blendMode) {
         if (blendMode == null) {
             return RenderState.BlendMode.Off;
-        } else if (blendMode == BlendMode.BLEND) {
-            return RenderState.BlendMode.Alpha;
-        } else if (blendMode == BlendMode.MULIPLY) {
-            return RenderState.BlendMode.Alpha;
-        } else {
-            throw new UnsupportedOperationException();
+        } else
+            switch (blendMode) {
+                case BLEND:
+                    return RenderState.BlendMode.Alpha;
+                case MULIPLY:
+                    return RenderState.BlendMode.Alpha;
+                default:
+                    throw new UnsupportedOperationException();
         }
     }
-    
+
     private int convertColor(Color color) {
         int color2 = 0;
         color2 |= ((int) (255.0 * color.getAlpha())) << 24;
@@ -223,19 +240,19 @@ public class RenderDeviceJme implements RenderDevice {
         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());
     }
 
     @Override
-    public void renderFont(RenderFont font, String str, int x, int y, Color color, float sizeX, float sizeY) {        
+    public void renderFont(RenderFont font, String str, int x, int y, Color color, float sizeX, float sizeY) {
         if (str.length() == 0) {
             return;
         }
-        
+
         RenderFontJme jmeFont = (RenderFontJme) font;
-        
+
         ColorRGBA colorRgba = convertColor(color, tempColor);
         CachedTextKey key = new CachedTextKey(jmeFont.getFont(), str/*, colorRgba*/);
         BitmapText text = textCacheLastFrame.get(key);
@@ -245,12 +262,12 @@ public class RenderDeviceJme implements RenderDevice {
             text.updateLogicalState(0);
         }
         textCacheCurrentFrame.put(key, text);
-        
+
 //        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);
@@ -260,33 +277,34 @@ public class RenderDeviceJme implements RenderDevice {
         text.setColor(colorRgba);
         text.updateLogicalState(0);
         text.render(rm, colorRgba);
-        
+
 //        System.out.format("renderFont(%s, %s, %d, %d, %s, %f, %f)\n", jmeFont.getFont(), str, x, y, color.toString(), sizeX, sizeY);
     }
-    
+
+    @Override
     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();
-        
+
         textureColorMaterial.setColor("Color", convertColor(color, tempColor));
-        textureColorMaterial.setTexture("ColorMap", texture);        
-        
+        textureColorMaterial.setTexture("ColorMap", texture);
+
         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);
@@ -294,51 +312,53 @@ public class RenderDeviceJme implements RenderDevice {
         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);
         rm.setForcedRenderState(renderState);
         textureColorMaterial.render(quadGeom, rm);
-        
+
         //System.out.format("renderImage2(%s, %d, %d, %d, %d, %d, %d, %d, %d, %s, %f, %d, %d)\n", texture.getKey().toString(),
         //                                                                                       x, y, w, h, srcX, srcY, srcW, srcH,
         //                                                                                       color.toString(), scale, centerX, centerY);
     }
-    
+
+    @Override
     public void renderImage(RenderImage image, int x, int y, int width, int height,
             Color color, float imageScale) {
-        
+
         RenderImageJme jmeImage = (RenderImageJme) image;
-        
+
         textureColorMaterial.setColor("Color", convertColor(color, tempColor));
         textureColorMaterial.setTexture("ColorMap", jmeImage.getTexture());
-        
+
         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);
         rm.setForcedRenderState(renderState);
         textureColorMaterial.render(quadGeom, rm);
-        
+
         //System.out.format("renderImage1(%s, %d, %d, %d, %d, %s, %f)\n", jmeImage.getTexture().getKey().toString(), x, y, width, height, color.toString(), imageScale);
     }
-    
+
+    @Override
     public void renderQuad(int x, int y, int width, int height, Color color) {
         //We test for alpha >0 as an optimization to prevent the render of completely transparent quads.
         //Nifty use layers that are often used for logical positionning and not rendering.
@@ -346,7 +366,7 @@ public class RenderDeviceJme implements RenderDevice {
         //Since we disable depth write, there is absolutely no point in rendering those quads
         //This optimization can result in a huge increase of perfs on complex Nifty UIs.
         if(color.getAlpha() >0){
-            colorMaterial.setColor("Color", convertColor(color, tempColor));                        
+            colorMaterial.setColor("Color", convertColor(color, tempColor));
 
             tempMat.loadIdentity();
             tempMat.setTranslation(x, getHeight() - y, 0);
@@ -356,44 +376,47 @@ public class RenderDeviceJme implements RenderDevice {
             rm.setForcedRenderState(renderState);
             colorMaterial.render(quadGeom, rm);
         }
-        
+
         //System.out.format("renderQuad1(%d, %d, %d, %d, %s)\n", x, y, width, height, color.toString());
     }
-    
+
+    @Override
     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);
-                                
+
         tempMat.loadIdentity();
         tempMat.setTranslation(x, getHeight() - y, 0);
         tempMat.setScale(width, height, 0);
-        
+
         rm.setWorldMatrix(tempMat);
         rm.setForcedRenderState(renderState);
         vertexColorMaterial.render(quadGeom, rm);
-        
+
         //System.out.format("renderQuad2(%d, %d, %d, %d, %s, %s, %s, %s)\n", x, y, width, height, topLeft.toString(),
         //                                                                                        topRight.toString(),
         //                                                                                        bottomRight.toString(),
         //                                                                                        bottomLeft.toString());
     }
-    
+
+    @Override
     public void enableClip(int x0, int y0, int x1, int y1) {
         clipWasSet = true;
         r.setClipRect(x0, getHeight() - y1, x1 - x0, y1 - y0);
     }
-    
+
+    @Override
     public void disableClip() {
         if (clipWasSet) {
             r.clearClipRect();

+ 12 - 8
jme3-niftygui/src/main/java/com/jme3/niftygui/RenderFontJme.java

@@ -37,17 +37,16 @@ import de.lessvoid.nifty.spi.render.RenderFont;
 
 public class RenderFontJme implements RenderFont {
 
-    private NiftyJmeDisplay display;
-    private BitmapFont font;
-    private BitmapText text;
-    private float actualSize;
+    private final BitmapFont font;
+    private final BitmapText text;
+    private final float actualSize;
 
     /**
      * Initialize the font.
      * @param name font filename
+     * @param display
      */
     public RenderFontJme(String name, NiftyJmeDisplay display) {
-        this.display = display;
         font = display.getAssetManager().loadFont(name);
         text = new BitmapText(font);
         actualSize = font.getPreferredSize();
@@ -61,7 +60,7 @@ public class RenderFontJme implements RenderFont {
     public BitmapFont getFont() {
         return font;
     }
-    
+
     public BitmapText getText(){
         return text;
     }
@@ -70,6 +69,7 @@ public class RenderFontJme implements RenderFont {
      * get font height.
      * @return height
      */
+    @Override
     public int getHeight() {
         return (int) text.getLineHeight();
     }
@@ -79,17 +79,18 @@ public class RenderFontJme implements RenderFont {
      * @param str text
      * @return width of the given text for the current font
      */
+    @Override
     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.       
+        //       be modified in sync.
         int result = (int) font.getLineWidth(str);
 //        text.setText(str);
 //        text.updateLogicalState(0);
@@ -98,6 +99,7 @@ public class RenderFontJme implements RenderFont {
         return result;
     }
 
+    @Override
     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
@@ -113,10 +115,12 @@ public class RenderFontJme implements RenderFont {
      * @param size font size
      * @return width of the character or null when no information for the character is available
      */
+    @Override
     public int getCharacterAdvance(final char currentCharacter, final char nextCharacter, final float size) {
         return Math.round(font.getCharacterAdvance(currentCharacter, nextCharacter, size));
     }
 
+    @Override
     public void dispose() {
     }
 }

+ 5 - 2
jme3-niftygui/src/main/java/com/jme3/niftygui/RenderImageJme.java

@@ -50,7 +50,7 @@ public class RenderImageJme implements RenderImage {
 
         key.setAnisotropy(0);
         key.setGenerateMips(false);
-        
+
         texture = (Texture2D) display.getAssetManager().loadTexture(key);
         texture.setMagFilter(linear ? MagFilter.Bilinear : MagFilter.Nearest);
         texture.setMinFilter(linear ? MinFilter.BilinearNoMipMaps : MinFilter.NearestNoMipMaps);
@@ -64,7 +64,7 @@ public class RenderImageJme implements RenderImage {
         if (texture.getImage() == null) {
             throw new IllegalArgumentException("texture.getImage() cannot be null");
         }
-        
+
         this.texture = texture;
         this.image = texture.getImage();
         width = image.getWidth();
@@ -75,14 +75,17 @@ public class RenderImageJme implements RenderImage {
         return texture;
     }
 
+    @Override
     public int getWidth() {
         return width;
     }
 
+    @Override
     public int getHeight() {
         return height;
     }
 
+    @Override
     public void dispose() {
     }
 }

+ 5 - 1
jme3-niftygui/src/main/java/com/jme3/niftygui/SoundDeviceJme.java

@@ -50,20 +50,24 @@ public class SoundDeviceJme implements SoundDevice {
         this.ar = ar;
     }
 
+    @Override
     public void setResourceLoader(NiftyResourceLoader niftyResourceLoader) {
     }
 
+    @Override
     public SoundHandle loadSound(SoundSystem soundSystem, String filename) {
         AudioNode an = new AudioNode(assetManager, filename, AudioData.DataType.Buffer);
         an.setPositional(false);
         return new SoundHandleJme(ar, an);
     }
 
+    @Override
     public SoundHandle loadMusic(SoundSystem soundSystem, String filename) {
         return new SoundHandleJme(ar, assetManager, filename);
     }
 
+    @Override
     public void update(int delta) {
     }
-    
+
 }

+ 8 - 2
jme3-niftygui/src/main/java/com/jme3/niftygui/SoundHandleJme.java

@@ -34,8 +34,8 @@ package com.jme3.niftygui;
 import com.jme3.asset.AssetManager;
 import com.jme3.audio.AudioData;
 import com.jme3.audio.AudioNode;
-import com.jme3.audio.AudioSource.Status;
 import com.jme3.audio.AudioRenderer;
+import com.jme3.audio.AudioSource.Status;
 import de.lessvoid.nifty.spi.sound.SoundHandle;
 
 public class SoundHandleJme implements SoundHandle {
@@ -68,10 +68,11 @@ public class SoundHandleJme implements SoundHandle {
         if (fileName == null) {
             throw new NullPointerException();
         }
-        
+
         this.fileName = fileName;
     }
 
+    @Override
     public void play() {
         if (fileName != null){
             if (node != null){
@@ -87,6 +88,7 @@ public class SoundHandleJme implements SoundHandle {
         }
     }
 
+    @Override
     public void stop() {
         if (node != null){
             node.stop();
@@ -98,6 +100,7 @@ public class SoundHandleJme implements SoundHandle {
         }
     }
 
+    @Override
     public void setVolume(float f) {
         if (node != null) {
             node.setVolume(f);
@@ -105,14 +108,17 @@ public class SoundHandleJme implements SoundHandle {
         volume = f;
     }
 
+    @Override
     public float getVolume() {
         return volume;
     }
 
+    @Override
     public boolean isPlaying() {
         return node != null && node.getStatus() == Status.Playing;
     }
 
+    @Override
     public void dispose() {
     }
 }