Creating textures programmatically (Solved)

I need to create (and continually update) a texture.

Right now, I have this:

Texture texture = new Texture2D(64, 64, Format.RGBA8);
ImageRaster raster = ImageRaster.create(texture.getImage());

But I’m getting this exception when it’s uploading to GPU:

ava.lang.IllegalArgumentException: Number of remaining buffer elements is 512, must be at least 16384. Because at most 16384 elements can be returned, a buffer with at least 16384 elements is required, regardless of actual returned element count

What’s going on?

how do you write to your image?

raster.setPixel(0,0,new ColorRGBA(0,0,0,1f));

Instead of :
(1) creating a texture
(2) extracting an image from it
(3) painting on it

what happens when you :
(1) create an image
(2) create the texture (Texture2D) using the previously created image (new Texture2D(theImage))
(3) paint on it ?

It do it in this order (using ImagePainter as I’m a lazy person) and it works.

I have downloaded the ImagePainter plugin but the SDK doesn’t seem to detect it.

I’m not saying you MUST use ImagePainter.
ImageRaster should be good enough … anyway, if you want to install it, install it using the SDK. Once it is installed (through your SDK’s plugin menu), just add it as a dependency of your project.

Got it, thanks.

Follow the TestImageRaster example. You have to create the buffer for the image manually.

Some working code of mine :

final ImagePainter ip = new ImagePainter(alphaMapFormat, 512, 512);
ip.wipe(ColorRGBA.Blue);
...
ip.paintPixel(posX + subX, posY + subY, pixel, ImagePainter.BlendMode.SET);
...
texAlpha = new Texture2D();
texAlpha.setImage(ip.getImage());
...
ip.paintPixel(...)

again ImageRaster should be enough for painting pixels.

Please provide your solution if you find it. It might help somebody else.

In my works I also make us of Processing to generate textures both one-time and updated in realtime. Here is the all code required to integrate Processing as a texture renderer into a jME app (I’ve tried to clear it from all irrelevant code):

// --- 1. A generic interface. We have to use an active graphics other than the default one to be able to deal with alpha transperancy

import processing.core.PApplet;
import processing.core.PGraphics;

public abstract class JmePApplet extends PApplet {

	abstract public PGraphics getActivePGraphics();

}


// --- 2. A jME Control to update the picture

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;

import jme3tools.converters.ImageToAwt;
import processing.core.PApplet;
import processing.core.PGraphics;

import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.control.AbstractControl;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.util.BufferUtils;

public class PAppletAdapter extends AbstractControl {

	JmePApplet papplet;
	BufferedImage bimage;
	Graphics graphics;
	float fps = 60;
	float currentFrametime = 0;
	float frameTime;
	PGraphics pg;
	java.awt.Image image;
	com.jme3.texture.Image.Format format;
	com.jme3.texture.Image jmeImage;
	Texture texture;
	
	ByteBuffer bb;
	
	public PAppletAdapter(JmePApplet papplet, BufferedImage bimage, Texture texture) {
		this.papplet = papplet;
		this.bimage = bimage;
		this.texture = texture;
		frameTime = 1f / fps;
		int colorComponents = 4;
		jmeImage = texture.getImage();
		int bufferSize = colorComponents * papplet.getWidth() * papplet.getHeight();
		bb = BufferUtils.createByteBuffer(bufferSize);
		jmeImage = texture.getImage();
		format = jmeImage.getFormat();
	}
	
	@Override
	protected void controlUpdate(float tpf) {
		currentFrametime += tpf;
		if(currentFrametime > frameTime) {
			currentFrametime = currentFrametime % frameTime;
			pg = papplet.getActivePGraphics();
			image = (java.awt.Image) pg.getNative();
			graphics = bimage.getGraphics();
			graphics.drawImage(image, 0, 0, null);
			bb.rewind();
			int bimageSize = bimage.getWidth() * bimage.getHeight() * 4;
			ImageToAwt.convert(bimage, format, bb);
			jmeImage.setData(bb);
			texture.setImage(jmeImage);
		}
	}

	@Override
	protected void controlRender(RenderManager rm, ViewPort vp) {
		// TODO Auto-generated method stub
		
	}

}


// --- 3. Actual applet example


import jumper.processing.gui.GuiMarkers;
import jumper.processing.gui.GuiRadar;
import processing.core.PApplet;
import processing.core.PGraphics;

public class GuiPApplet extends JmePApplet{

	PGraphics activeGraphics;
	int w, h;

	GuiRadar radar;
	GuiMarkers markers;
	
	public GuiPApplet() {
		this(300, 200, null, null);
	}
	
	public GuiPApplet(int w, int h) {
		this.w = w;
		this.h = h;
	}
	
	public void setup() {
		size(w, h);
		frameRate(-1);
		activeGraphics = createGraphics(w, h);
		System.out.println("GUI PAPPLET, w = " + getWidth() + " h = " + getHeight());
		noLoop();
	}
	
	public void draw() {
		activeGraphics.beginDraw();
		activeGraphics.clear();
//		activeGraphics.background(100, 70, 45, 10);
		activeGraphics.rect(20, 20, 100, 100);
		activeGraphics.endDraw();
	}
	
	@Override
	public PGraphics getActivePGraphics() {
		return activeGraphics;
	}

    // this method here is only for testing purpoess to be able to start this class as a java app
	public static void main(String[] args) {
		PApplet.main(new String[] { "--present", "jumper.processing.GuiPApplet" });
//		GuiPApplet test = new GuiPApplet(800, 600);
//		test.init();
//		test.loop();
//		test.start();
		
	}

	public PGraphics createFullSizeGraphics() {
		return createGraphics(getWidth(), getHeight());
	}
	
}

And the code where from you create and update that stuff, here it’s just an extract:

	Geometry screen;
	GuiPApplet papplet;
	PAppletAdapter adapter;
	
	@Override
	protected void initialize(Application app) {
		super.initialize(app);
		
		width = app.getViewPort().getCamera().getWidth();
		height = app.getViewPort().getCamera().getHeight();
		Image image = new Image(Image.Format.ABGR8, width, height, null);
		Texture2D gui = new Texture2D(image);
		Quad quad = new Quad(width, height);
		Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
		mat.setTexture("ColorMap", gui);
		mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
		screen = new Geometry("GUI Screen", quad);
		screen.setMaterial(mat);
		
		papplet = new GuiPApplet(width, height, ed, entities);
		papplet.init();
		papplet.start();
		    		
		BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
		adapter = new PAppletAdapter(papplet, bimage, gui);
		
//		screen.setLocalTranslation(100, 100, 10);
		screen.addControl(adapter);
		((SimpleApplication) app).getGuiNode().attachChild(screen);
	}

	@Override
	protected void cleanup(Application app) {
		((SimpleApplication) app).getGuiNode().detachChild(screen);
		screen.removeControl(adapter);
		System.out.println("TEST STATE: terminating");
		papplet.finished = true;
		papplet.stop();
		papplet.destroy();
		papplet = null;
	}

   @Override
   public void update(float tpf) {
      	super.update(tpf);
     	papplet.redraw();
   }

I am generating textures, but not for visual use. I’m just generating a texture that describes visibility of a mesh. (Fog of War).

But that’s kinda cool though.

Interesting! So your fog of war is a texture that is over the actual map, and that veils certain areas with everything there?

It’s a 32x32 texture used by the shader I use for objects that need fog of war. I just paint circles on the alpha channel.