Transparent textures with my texture combiner (2nd try)

Hello,



I asked this question already roughly half a year ago, but didn’t get any answer, so I’ll try again.



I have problems with a texture combiner of mine. What is it supposed to be doing? It is supposed to combine multiple texture images into one. I use this for a paperdoll character creation system, where the user can build together his avatar from different sprite parts he can choose.



The code of the class which should combine the texture parts into one is this:



[java]

import com.jme3.texture.Image;

import com.jme3.texture.Image.Format;

import com.jme3.texture.Texture;

import com.jme3.texture.Texture.MagFilter;

import com.jme3.texture.Texture2D;

import com.jme3.util.BufferUtils;



import java.awt.Color;

import java.nio.ByteBuffer;

import java.util.Arrays;



/**

  • Provides methods to combine parts of a sprite into one sprite.

    /

    public class SpriteCreator {



    /
    * Holds pixel data of the texture to create. /

    protected byte[] m_data;



    protected Texture2D m_baseTexture;

    protected Texture2D m_hairTexture;

    protected Texture2D m_topTexture;

    protected Texture2D m_bottomTexture;

    protected Texture2D m_faceTexture;

    protected Texture2D m_bagTexture;



    protected byte[] m_baseImageData;

    protected byte[] m_hairImageData;

    protected byte[] m_topImageData;

    protected byte[] m_bottomImageData;

    protected byte[] m_faceImageData;

    protected byte[] m_bagImageData;



    /
    * Width of the created texture. /

    int m_width;

    /
    * Height of the created texture. */

    int m_height;



    public SpriteCreator(int width, int height) {



    this.m_width = width;

    this.m_height = height;



    m_baseImageData = new byte[width * height * 4];

    m_hairImageData = new byte[width * height * 4];

    m_topImageData = new byte[width * height * 4];

    m_bottomImageData = new byte[width * height * 4];

    m_faceImageData = new byte[width * height * 4];

    m_bagImageData = new byte[width * height * 4];



    // create black image

    m_data = new byte[width * height * 4];

    setBackground (new Color(0,0,0,0));

    }



    /**
  • Creates a texture from the pixel data this object holds and returns it.

    *
  • @return The texture created from the pixel data this object holds.

    */

    public Texture getTexture() {

    ByteBuffer buffer = BufferUtils.createByteBuffer(m_data);

    Image spriteImage = new Image(Format.RGBA8, m_width, m_height, buffer);



    Texture combinedTexture = new Texture2D(spriteImage);

    combinedTexture.setMagFilter(MagFilter.Nearest);



    return combinedTexture;

    }



    /**
  • Sets a specified pixel to a specified color.

    *
  • @param x The x-coordinate of the pixel to set.
  • @param y The y-coordinate of the pixel to set.
  • @param color The color of the pixel to set.

    */

    private void setPixel(int x, int y, Color color) {

    int i = (x + y * m_width) * 4;

    m_data = (byte) color.getRed(); // r

    m_data = (byte) color.getGreen(); // g

    m_data = (byte) color.getBlue(); // b

    m_data = (byte) color.getAlpha(); // a

    }



    /**
  • Sets the pixel data of the texture to create to a combination of all stored
  • individual texture parts.

    */

    public void combineSprite() {

    setBackground(new Color(0,0,0,0));



    drawSpritePart(SpritePart.BASE);

    drawSpritePart(SpritePart.TOP);

    drawSpritePart(SpritePart.BOTTOM);

    drawSpritePart(SpritePart.BAG);

    drawSpritePart(SpritePart.FACE);

    drawSpritePart(SpritePart.HAIR);

    }



    private void drawSpritePart(SpritePart part) {

    Texture2D partToDraw = null;

    byte[] imageData;



    switch(part) {

    case BASE:

    partToDraw = m_baseTexture;

    imageData = m_baseImageData;

    break;

    case HAIR:

    partToDraw = m_hairTexture;

    imageData = m_hairImageData;

    break;

    case TOP:

    partToDraw = m_topTexture;

    imageData = m_topImageData;

    break;

    case BOTTOM:

    partToDraw = m_bottomTexture;

    imageData = m_bottomImageData;

    break;

    case FACE:

    partToDraw = m_faceTexture;

    imageData = m_faceImageData;

    break;

    case BAG:

    partToDraw = m_bagTexture;

    imageData = m_bagImageData;

    break;

    default:

    imageData = new byte[m_width * m_height * 4];

    break;

    }



    if(partToDraw != null) {

    if(partToDraw.getImage().getData().get(0).hasRemaining()) {

    partToDraw.getImage().getData().get(0).get(imageData);



    switch(part) {

    case BASE:

    m_baseImageData = Arrays.copyOf(imageData, imageData.length);

    break;

    case HAIR:

    m_hairImageData = Arrays.copyOf(imageData, imageData.length);

    break;

    case TOP:

    m_topImageData = Arrays.copyOf(imageData, imageData.length);

    break;

    case BOTTOM:

    m_bottomImageData = Arrays.copyOf(imageData, imageData.length);

    break;

    case FACE:

    m_faceImageData = Arrays.copyOf(imageData, imageData.length);

    break;

    case BAG:

    m_bagImageData = Arrays.copyOf(imageData, imageData.length);

    break;

    }

    }



    for(int y = 0; y < m_height; y++) {

    for(int x = 0; x < m_width; x++) {

    int i = (x + y * m_width) * 4;

    Color pixelColor;



    if(ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+3]) != 0) {

    pixelColor = new Color(ByteToUnsignedIntCaster.byteToUnsignedInt(imageData),

    ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+1]),

    ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+2]),

    ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+3]));



    setPixel(x, y, pixelColor);

    }

    }

    }

    }

    }



    public void setBaseTexture(Texture2D baseTexture) {

    m_baseTexture = baseTexture;

    }



    public void setHairTexture(Texture2D hairTexture) {

    m_hairTexture = hairTexture;

    }



    public void setTopTexture(Texture2D topTexture) {

    m_topTexture = topTexture;

    }



    public void setBottomTexture(Texture2D bottomTexture) {

    m_bottomTexture = bottomTexture;

    }



    public void setFaceTexture(Texture2D topTexture) {

    m_faceTexture = topTexture;

    }



    public void setBagTexture(Texture2D bottomTexture) {

    m_bagTexture = bottomTexture;

    }



    public final void setBackground(Color color) {



    for (int i = 0; i < m_width * m_height * 4; i += 4) {

    m_data = (byte) color.getRed(); // r

    m_data = (byte) color.getGreen(); // g

    m_data = (byte) color.getBlue(); // b

    m_data = (byte) color.getAlpha(); // a

    }

    }



    public enum SpritePart {

    BASE, HAIR, TOP, BOTTOM, FACE, BAG

    }

    }[/java]



    I first call the set…Texture methods, then I call combineSprite and then getTexture to get the endresult. I get the textures which I pass to set…Texture from assetManager.loadTexture();



    It used to work, but after a patch/change to jmonkey, I’m getting transparent textures only (where every pixel is transparent). Any idea where the error is?

Maybe it helps you? http://www.hub.jmonkeyengine.org/wiki/doku.php/jme3:faq#how_do_i_make_materials_transparent

By “transparent pixels only” do you mean that you don’t see a texture at all? That could be any of a dozen problems but would require us to see your scene and material setup.



What version of JME are you running? The latest beta with latest stable updates?

The material I use is:



[java] m_textureMat = new Material(GameClient.getInstance().getAssetManager(), “Common/MatDefs/Misc/Unshaded.j3md”);

m_textureMat.setTexture(“ColorMap”, m_sprites[0]);

m_textureMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

m_holder.setQueueBucket(Bucket.Transparent);

m_holder.setMaterial(m_textureMat);[/java]



m_holder is the spatial which holds the texture. In m_sprites[0] I have the texture created by my SpriteCreator.



I load the texture parts from png images with the assetManager.loadTexture(…).



I’m using the first JME beta.



It’s line 136. He never enters that if. If I can find out why, I can fix the mistake.

Ok so, I did a test.



I loaded a .png-image as a texture with:



[java]

textureM = GameClient.getInstance().getAssetManager().loadTexture(…);

[/java]



This didn’t throw an exception, so the texture was successfully loaded?



Then I did:



[java]

System.out.println(textureM.getImage().getData().get(0).hasRemaining());

[/java]



In the line after. I always got false? Is this intended? You load a texture from a .png-image and then texture.getImage().getData().get(0).hasRemaining() returns false?

More information:



Calling



[java]

System.out.println(textureM.getImage().getData().get(0).toString());

[/java]



yields: java.nio.DirectByteBuffer[pos=2704 lim=2704 cap=2704].



It’s a 2626 .png-image. 2626*4 = 2704.



Here is the problem: pos == lim right after loading the texture.



It appears like this wasn’t the case in older JME versions? Can we change that again? Or is there a reason behind this?



Another thing: I cannot edit my post, it bugged somehow.

Another thing: I cannot edit my post, it bugged somehow.


Yes, you can. Join the group ;).
@myamo said:
Here is the problem: pos == lim right after loading the texture.


Is there a reason you can't just call rewind() on the buffer?

No, but that’s the reason my code stopped working.



Also I had to change line 166 from:



[java]

if(ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+3]) != 0) {

pixelColor = new Color(ByteToUnsignedIntCaster.byteToUnsignedInt(imageData),

ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+1]),

ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+2]),

ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+3]));



setPixel(x, y, pixelColor);

}

[/java]



To the following:



[java]

if(ByteToUnsignedIntCaster.byteToUnsignedInt(imageData) != 0) {

pixelColor = new Color(ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+3]),

ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+2]),

ByteToUnsignedIntCaster.byteToUnsignedInt(imageData[i+1]),

ByteToUnsignedIntCaster.byteToUnsignedInt(imageData));



setPixel(x, y, pixelColor);

}

[/java]



Now it all works, problem solved.



So yeah, you guys messed with the buffers, bad boys.

Weird… that just implies that what was RGBA is now ABGR.