I have some problems with procedurally generated textures, so I decided to export them as PNG and see what is wrong. I googled, and soon enough found a way to do it
Sadly, this spits errors when I try to do it:
at java.nio.DirectIntBufferU.get(DirectIntBufferU.java:271)
at java.nio.IntBuffer.get(IntBuffer.java:715)
at com.jme3.util.Screenshots.convertScreenShot2(Screenshots.java:50)
at com.jme3.system.JmeDesktopSystem.writeImageFile(JmeDesktopSystem.java:94)
at com.jme3.system.JmeSystem.writeImageFile(JmeSystem.java:137)
at mytest.TextureManagerTest.savePng(TextureManagerTest.java:53)
at mytest.TextureManagerTest.simpleInitApp(TextureManagerTest.java:42)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
at java.lang.Thread.run(Thread.java:745)```
This error appears both with my real generated texture and 256x256px test image, loaded from PNG file. Both of them have alpha channels, could that break stuff? I'm running with 3.1.0 (stable) on desktop+LWJGL 2.
Well, I just used what you suggested in the thread I linked⦠As youāre core developer I thought it would be ācorrectā way to do it.
Anyway, I checked ScreenshotAppState, which did sadly produce quite similar error:
at java.nio.DirectIntBufferU.get(DirectIntBufferU.java:271)
at java.nio.IntBuffer.get(IntBuffer.java:715)
at com.jme3.util.Screenshots.convertScreenShot2(Screenshots.java:50)
at com.jme3.system.JmeDesktopSystem.writeImageFile(JmeDesktopSystem.java:94)
at com.jme3.system.JmeSystem.writeImageFile(JmeSystem.java:137)
at mytest.TextureManagerTest.writeImageFile(TextureManagerTest.java:63)
at mytest.TextureManagerTest.simpleInitApp(TextureManagerTest.java:43)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
at java.lang.Thread.run(Thread.java:745)```
I basically copied writeImageFile (as it is protected), with only little changes, so this way doesn't seem to be any different in practise. As you can see, both are essentially doing the same thing, while the latter might be *cleaner* code.
I checked that my 256x256px RGBA image buffer indeed has correct amount (256² * 4) bytes, so that shouldn't be the issue either.
I also had many problems with saving images, thatās why I did my own utilities. If you want you can try them (If so, let me know if it works. It does for me )
I encountered āthe sameā java.nio.BufferUnderflowException. Actually @NemesisMate already provided some solution, but I thought its worth to provide a test case to get this (or some other reasonable) fix into core. This testcase:
package jme3test.texture;
import com.jme3.app.SimpleApplication;
import com.jme3.light.PointLight;
import com.jme3.scene.Spatial;
import com.jme3.system.JmeSystem;
import com.jme3.texture.Image;
import com.jme3.texture.Texture;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class TestSaveNormalTexture extends SimpleApplication {
float angle;
PointLight pl;
Spatial lightMdl;
public static void main(String[] args) {
TestSaveNormalTexture app = new TestSaveNormalTexture();
app.start();
}
@Override
public void simpleInitApp() {
Texture t = assetManager.loadTexture("Textures/BumpMapTest/Simple_normal.png");
try {
savePng(File.createTempFile("test", ".png"), t.getImage());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static void savePng(File f, Image img) throws IOException {
f.createNewFile();
try (OutputStream out = new FileOutputStream(f)) {
JmeSystem.writeImageFile(out, "png", img.getData(0), img.getWidth(), img.getHeight());
}
}
}
causes this exception stack trace:
SEVERE: Uncaught exception thrown in Thread[jME3 Main,6,main]
java.nio.BufferUnderflowException
at java.nio.DirectIntBufferU.get(DirectIntBufferU.java:271)
at java.nio.IntBuffer.get(IntBuffer.java:715)
at com.jme3.util.Screenshots.convertScreenShot2(Screenshots.java:50)
at com.jme3.system.JmeDesktopSystem.writeImageFile(JmeDesktopSystem.java:94)
at com.jme3.system.JmeSystem.writeImageFile(JmeSystem.java:137)
at jme3test.texture.TestSaveNormalTexture.savePng(TestSaveNormalTexture.java:39)
at jme3test.texture.TestSaveNormalTexture.simpleInitApp(TestSaveNormalTexture.java:29)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:220)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
at java.lang.Thread.run(Thread.java:745)
This happens for all textures that have a format that uses != 32 bits per pixel - so in this case the normal map from the jme3 testdata āTextures/BumpMapTest/Simple_normal.pngā has only 24 which causes the bufferconversion to fail with this exception. This might also be the reason why it never bothered anyone because its mainly used for saving screenshots i guess.
The above mentioned fix uses different conversions for these two cases:
Yeah thatās basically the reason. That method is a backdoor to get platform-independent screenshot export functionality working, itās not really intended for general use.
Thereās a note that the image has to be in the RGBA8 format:
Perhaps a better approach would have been to fallback to ImageRaster, which allows reading color data from any jME image, in case a format other than RGBA8 is used. You can implement a PR for that if you like