@ -57,13 +57,15 @@ import com.jme3.texture.Texture.MinFilter;
import com.jme3.texture.Texture2D ;
import com.jme3.util.BufferUtils ;
import de.lessvoid.nifty.batch.spi.BatchRenderBackend ;
import de.lessvoid.nifty.render. batch.spi.BatchRenderBackend ;
import de.lessvoid.nifty.render.BlendMode ;
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.ObjectPool.Factory ;
import de.lessvoid.nifty.tools.resourceloader.NiftyResourceLoader ;
import java.util.HashMap ;
import java.util.Map ;
/ * *
* Nifty GUI BatchRenderBackend Implementation for jMonkeyEngine .
@ -82,18 +84,21 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
private RenderManager renderManager ;
private NiftyJmeDisplay display ;
private Texture2D textureAtlas ;
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
private boolean fillRemovedTexture =
Boolean . getBoolean ( System . getProperty ( JmeBatchRenderBackend . class . getName ( ) + ".fillRemovedTexture" , "false" ) ) ;
// 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 > ( 2 , new Factory < Batch > ( ) {
this . batchPool = new ObjectPool < Batch > ( new Factory < Batch > ( ) {
@Override
public Batch createNew ( ) {
return new Batch ( ) ;
@ -152,9 +157,18 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
@Override
public MouseCursor createMouseCursor ( final String filename , final int hotspotX , final int hotspotY ) throws IOException {
return new MouseCursor ( ) {
public void dispose ( ) {
}
} ;
@Override
public void dispose ( ) {
}
@Override
public void enable ( ) {
}
@Override
public void disable ( ) {
}
} ;
}
@Override
@ -166,9 +180,9 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
}
@Override
public void createAtlasTexture ( final int width , final int height ) {
public int createTextureAtlas ( final int width , final int height ) {
try {
createAtlasTextureInternal ( width , height ) ;
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 ) ;
@ -178,15 +192,18 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
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 clearAtlas Texture ( final int width , final int height ) {
initialData . rewind ( ) ;
textureAtlas . getImage ( ) . setData ( initialData ) ;
public void clearTextureAtlas ( final int atlasId ) {
initialData . rewind ( ) ;
ge tT extureAtlas( atlasId ) . getImage ( ) . setData ( initialData ) ;
}
@Override
@ -200,16 +217,41 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
}
@Override
public void addImageToTexture ( final Image image , final int x , final int y ) {
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 ) ) ;
}
@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 ;
imageImpl . modifyTexture ( this , textureAtlas , x , y ) ;
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 void beginBatch ( final BlendMode blendMode ) {
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 ) ;
currentBatch . begin ( blendMode , getTextureAtlas ( textureId ) ) ;
}
@Override
@ -225,9 +267,10 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
final float textureX ,
final float textureY ,
final float textureWidth ,
final float textureHeight ) {
final float textureHeight ,
final int textureId ) {
if ( ! currentBatch . canAddQuad ( ) ) {
beginBatch ( currentBatch . getBlendMode ( ) ) ;
beginBatch ( currentBatch . getBlendMode ( ) , textureId ) ;
}
currentBatch . addQuadInternal ( x , y , width , height , color1 , color2 , color3 , color4 , textureX , textureY , textureWidth , textureHeight ) ;
}
@ -242,7 +285,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
}
@Override
public void removeFromTexture ( final Image image , final int x , final int y , final int w , final int h ) {
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 ) {
@ -258,24 +301,47 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
}
initialData . rewind ( ) ;
modifyTexture (
textureAtlas ,
ge tT extureAtlas( atlasTextureId ) ,
new com . jme3 . texture . Image ( Format . RGBA8 , image . getWidth ( ) , image . getHeight ( ) , initialData ) ,
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 void createAtlasTextureInternal ( final int width , final int height ) throws Exception {
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 ) 0x80 ) ;
initialData . put ( ( byte ) 0x0 0 ) ;
}
initialData . rewind ( ) ;
textureAtlas = new Texture2D ( new com . jme3 . texture . Image ( Format . RGBA8 , width , height , initialData ) ) ;
textureAtlas . setMinFilter ( MinFilter . NearestNoMipMaps ) ;
textureAtlas . setMagFilter ( MagFilter . Nearest ) ;
Texture2D texture = new Texture2D ( new com . jme3 . texture . Image ( Format . RGBA8 , width , height , initialData ) ) ;
texture . setMinFilter ( MinFilter . NearestNoMipMaps ) ;
texture . setMagFilter ( MagFilter . Nearest ) ;
return texture ;
}
private void modifyTexture (
@ -294,6 +360,16 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
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 .
@ -389,6 +465,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
// current blend mode
private BlendMode blendMode = BlendMode . BLEND ;
private Texture2D texture ;
private Material material ;
public Batch ( ) {
@ -416,8 +493,10 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
renderState . setDepthWrite ( false ) ;
}
public void begin ( final BlendMode blendMode ) {
public void begin ( final BlendMode blendMode , final Texture2D texture ) {
this . blendMode = blendMode ;
this . texture = texture ;
quadCount = 0 ;
globalVertexIndex = 0 ;
vertexPosBuffer . clear ( ) ;
@ -449,7 +528,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
renderManager . setWorldMatrix ( tempMat ) ;
renderManager . setForcedRenderState ( renderState ) ;
material . setTexture ( "ColorMap" , textureAtlas ) ;
material . setTexture ( "ColorMap" , texture ) ;
mesh . updateCounts ( ) ;
material . render ( meshGeometry , renderManager ) ;
renderManager . setForcedRenderState ( null ) ;