|
|
|
@ -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,41 +45,50 @@ 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 static final Logger log = Logger.getLogger(JmeBatchRenderBackend.class.getName()); |
|
|
|
|
|
|
|
|
|
private final ObjectPool<Batch> batchPool; |
|
|
|
|
private final List<Batch> batches = new ArrayList<Batch>(); |
|
|
|
|
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<ModifyTexture>(); |
|
|
|
|
private final List<ModifyTexture> modifyTextureCalls = new ArrayList<>(); |
|
|
|
|
|
|
|
|
|
private RenderManager renderManager; |
|
|
|
|
private NiftyJmeDisplay display; |
|
|
|
|
private Map<Integer, Texture2D> textures = new HashMap<Integer, Texture2D>(); |
|
|
|
|
private Map<Integer, Texture2D> textures = new HashMap<>(); |
|
|
|
|
private int textureAtlasId = 1; |
|
|
|
|
private Batch currentBatch; |
|
|
|
|
private Matrix4f tempMat = new Matrix4f(); |
|
|
|
@ -102,7 +102,8 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
|
|
|
|
|
public JmeBatchRenderBackend(final NiftyJmeDisplay display) { |
|
|
|
|
this.display = display; |
|
|
|
|
this.batchPool = new ObjectPool<Batch>(new Factory<Batch>() { |
|
|
|
|
this.batchPool = new ObjectPool<>(new Factory<Batch>() { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public Batch createNew() { |
|
|
|
|
return new Batch(); |
|
|
|
@ -132,7 +133,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
public void beginFrame() { |
|
|
|
|
log.fine("beginFrame()"); |
|
|
|
|
|
|
|
|
|
for (int i=0; i<batches.size(); i++) { |
|
|
|
|
for (int i = 0; i < batches.size(); i++) { |
|
|
|
|
batchPool.free(batches.get(i)); |
|
|
|
|
} |
|
|
|
|
batches.clear(); |
|
|
|
@ -140,7 +141,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
// 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++) { |
|
|
|
|
for (int i = 0; i < modifyTextureCalls.size(); i++) { |
|
|
|
|
modifyTextureCalls.get(i).execute(renderer); |
|
|
|
|
} |
|
|
|
|
modifyTextureCalls.clear(); |
|
|
|
@ -157,7 +158,6 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: Cursor support
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public MouseCursor createMouseCursor(final String filename, final int hotspotX, final int hotspotY) throws IOException { |
|
|
|
|
return new MouseCursor() { |
|
|
|
@ -189,8 +189,8 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
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 = 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); |
|
|
|
@ -219,8 +219,8 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
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) { |
|
|
|
|
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); |
|
|
|
@ -306,7 +306,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public int render() { |
|
|
|
|
for (int i=0; i<batches.size(); i++) { |
|
|
|
|
for (int i = 0; i < batches.size(); i++) { |
|
|
|
|
Batch batch = batches.get(i); |
|
|
|
|
batch.render(); |
|
|
|
|
} |
|
|
|
@ -321,8 +321,8 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ByteBuffer initialData = BufferUtils.createByteBuffer(image.getWidth()*image.getHeight()*4); |
|
|
|
|
for (int i=0; i<image.getWidth()*image.getHeight(); i++) { |
|
|
|
|
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); |
|
|
|
@ -337,9 +337,14 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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. |
|
|
|
|
* 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) { |
|
|
|
@ -349,9 +354,12 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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. |
|
|
|
|
* 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) { |
|
|
|
@ -359,10 +367,9 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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++) { |
|
|
|
|
ByteBuffer initialData = BufferUtils.createByteBuffer(width * height * 4); |
|
|
|
|
for (int i = 0; i < width * height * 4; i++) { |
|
|
|
|
initialData.put((byte) 0x00); |
|
|
|
|
} |
|
|
|
|
initialData.rewind(); |
|
|
|
@ -400,12 +407,14 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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. |
|
|
|
|
* 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) { |
|
|
|
@ -432,14 +441,17 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Used to delay ModifyTexture calls in case we don't have a JME3 Renderer yet. |
|
|
|
|
* 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 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; |
|
|
|
@ -454,9 +466,10 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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. |
|
|
|
|
* 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 |
|
|
|
|
*/ |
|
|
|
@ -470,6 +483,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
// 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; |
|
|
|
|
|
|
|
|
@ -483,10 +497,10 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
@ -495,7 +509,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
// current blend mode
|
|
|
|
|
private BlendMode blendMode = BlendMode.BLEND; |
|
|
|
|
private Texture2D texture; |
|
|
|
|
private Material material; |
|
|
|
|
private final Material material; |
|
|
|
|
|
|
|
|
|
public Batch() { |
|
|
|
|
// setup mesh
|
|
|
|
@ -566,14 +580,17 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
private RenderState.BlendMode convertBlend(final BlendMode blendMode) { |
|
|
|
|
if (blendMode == null) { |
|
|
|
|
return RenderState.BlendMode.Off; |
|
|
|
|
} else if (blendMode == BlendMode.BLEND) { |
|
|
|
|
} else { |
|
|
|
|
switch (blendMode) { |
|
|
|
|
case BLEND: |
|
|
|
|
return RenderState.BlendMode.Alpha; |
|
|
|
|
} else if (blendMode == BlendMode.MULIPLY) { |
|
|
|
|
case MULIPLY: |
|
|
|
|
return RenderState.BlendMode.Alpha; |
|
|
|
|
} else { |
|
|
|
|
default: |
|
|
|
|
throw new UnsupportedOperationException(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public boolean canAddQuad() { |
|
|
|
|
return (quadCount + 1) < BATCH_MAX_QUADS; |
|
|
|
@ -592,13 +609,13 @@ public class JmeBatchRenderBackend implements BatchRenderBackend { |
|
|
|
|
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 + 3)); |
|
|
|
|
indexBufferBuffer.put((short) (globalVertexIndex + 2)); |
|
|
|
|
|
|
|
|
|
indexBufferBuffer.put((short)(globalVertexIndex + 0)); |
|
|
|
|
indexBufferBuffer.put((short)(globalVertexIndex + 2)); |
|
|
|
|
indexBufferBuffer.put((short)(globalVertexIndex + 1)); |
|
|
|
|
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); |
|
|
|
|