[SOLVED]:Dividing an image into multiple textures

Ok, what I need to do, is load an image file, split it into 16 images (a 4x4 grid), then load all the chunks into a Texture array, ready to be applied to materials/geometries. The textures should be able to collate back together to look like the original image, naturally.



I have tried a few things, with varying and interesting results. If anyone can provide a handy solution, this would be wonderful.

Why not just leave it as one texture and use different texture coordinates?



Do you have a requirement to repeat across large geometry or something?

The image I need to break up is an alphamap used for tri-plannar mapping texture splatting and is a continuation of this problem here, recently solved (the mesh has no texcoords). Since solving this issue, I edited the code to break my terrain mesh into chunks (16 ground meshes, 16 cliff meshes total), to increase FPS/performance. It works well now exactly as I had hoped, only now the ground alphamap starts anew from the corner of each terrain chunk. By splitting the alphamap in to 16 pieces and appling each piece to its relative material/geometry this will fix my problem of that much I am sure, and it will look like one big happy alpha map again.

Most graphics programs (gimp, photoshop, etc) either directly or via plugins allow you to split images.

Yes, I know. I need it done this way though, so alphamaps can be created and loaded as a single file, not 16 files, and so the map editors can easily go too and from editing the alpha map without having to collate 16 individual images.

You tried splitting a 2d array of pixels into smaller 2d arrays but failed? :?



Handy solution - go read a 5’th grade math book.

Why don’t you just use BufferedImages and convert them all to JME textures…?

@androlo said:
You tried splitting a 2d array of pixels into smaller 2d arrays but failed? :?

Handy solution - go read a 5'th grade math book.


No. I didnt. :x

Im taking it no one has actually tried to do this before.

[java]BufferedImage alphaImage = ImageUtilities.loadImage("Textures/alpha.png", assetManager);

BufferedImage[][] alphaArray = new BufferedImage[chunkCountX][chunkCountZ];



int arrayX = alphaImage.getWidth()/chunkCountX; //chunkCountX = 4

int arrayY = alphaImage.getHeight()/chunkCountZ; //chunkCountZ = 4



for(int cX=0;cX<chunkCountX;cX++){

for(int cZ=0;cZ<chunkCountZ;cZ++){

alphaArray[cX][cZ] = alphaImage.getSubimage(cXarrayX, cZarrayY, arrayX, arrayY);

}

}



AWTLoader loader = new AWTLoader();



for(int cX=0;cX<chunkCountX;cX++){

for(int cZ=0;cZ<chunkCountZ;cZ++){

groundAlpha[cX][cZ] = new Texture2D();

groundAlpha[cX][cZ].setImage(loader.load(alphaArray[cX][cZ],true));



}

}[/java]



AWTLoader throws a buffer overflow exception.

Can you show us the full exception? You left out the important parts.

And actually, reading about getSubImage() it’s going to cause you problems. It’s javadoc says: “The returned BufferedImage shares the same data array as the original image.”



Some of what the AWTLoader does is grab the raw underlying array… and unfortunately JME does an unbounded put() (arguably a bug) and so tries to shove the whole original image buffer into a buffer that is now only 1/4 the size each way.



You may have to jump through some extra hoops to turn those subimages into their own images… at least without patching JME.



Edit: I don’t think there is a JME fix that will help you. A bounded put is probably a good idea for other reasons but it would still be interpreting the buffer wrong. Probably best to get the subimage and then copy it into a new buffered image… or look at how AWTLoader does it and create your own (slightly slower) routine to use getRGB to copy your subimages directly to a JME Image.

1 Like

Sorry I didnt mention a few things I should have in my last post. Yeah I figured the exception was likely caused by getSubImage not working how i hoped it would. I used an image splitting method included in the SpriteLibrary I am using, instead of SubImage, with some pretty crazy undesirable effects before I tried that.



I might have to bite the bullet on this one and just have 16 images for one alpha map, load, and collate them for editing. Like I was trying to avoid. But now we know! Thanks and once I find a solution I will update.

Turning a sub image (like you do above) into its own BufferedImage is really quite trivial though. It’s not necessarily optimal but it would get you past this to work on more interesting things.



It’s not pretty but off the top of my head… for each subimage:

[java]

BufferedImage subImage = …create the sub image in the right size…

Graphics g = subImage.getGraphics();

g.drawImage( alphaImage.getSubimage(cXarrayX, cZarrayY, arrayX, arrayY), 0, 0, null );

g.dispose();

[/java]

1 Like

Ok, i figured it out.



[java]private void loadAlphaMap(){



BufferedImage alphaImage = ImageUtilities.loadImage("Textures/alpha.png", assetManager);

BufferedImage[][] alphaArray = new BufferedImage[chunkCountX][chunkCountZ];

BufferedImage alphaChunk;



int arrayX = alphaImage.getWidth()/chunkCountX;

int arrayY = alphaImage.getHeight()/chunkCountZ;



for(int cX=0;cX<chunkCountX;cX++){

for(int cZ=0;cZ<chunkCountZ;cZ++){



alphaChunk = new BufferedImage(arrayX,arrayY,BufferedImage.TYPE_INT_ARGB);

alphaChunk.setData(alphaImage.getSubimage(cXarrayX, cZarrayY, arrayX, arrayY).getData());

alphaArray[cX][cZ] = alphaChunk;



}

}



AWTLoader loader = new AWTLoader();



for(int cX=0;cX<chunkCountX;cX++){

for(int cZ=0;cZ<chunkCountZ;cZ++){

groundAlpha[cX][cZ] = new Texture2D();

groundAlpha[cX][cZ].setImage(loader.load(alphaArray[cX][cZ],false));



}

}



}[/java]



Yeah I had to create a BufferedImage object to hold the subimage data to be passed to alphaArray. The object sets its raster data to that of the subimage defined in the loop, then passes it to my array.

Won’t you have problems at the tile borders when having non-NN interpolation? Just curios…

yeah there is a little bit of an abnomaly where the image has been split around the edge. its mainly apparent in places like below, where the path crosses the tile edge at an angle. Right now though this is low on my priority list to fix. It can be worked around.