That's why everyone asks about BufferedImages

After all this time, i finally got around to wanting to add a canvas to the guiNode. After picking through every post I could find, It still took a lot of work and I still have one problem. First, there is a BitmapText node, why is there still not a CanvasNode (what it looks like everyone wants)? So, here is mine. I’ll put in in Contribudions, too. That said, I’m resizing my BufferedImage but the output doesn’t resize. The dump of my BufferedImage says that the size changed, but it still comes out at the old size. It looks like it is scaling 1:2 (going from 200, 200 to 100,100). But, why? I’ll try going from small to big rather than big to small and see if that makes a difference.
Also, FYI, you have to remove comment blocks before posting code here. Otherwise the code gets broken up in segments. (or my browser is broken)

 * To change this template, choose Tools | Templates
 * and open the template in the editor.

package my.asteroid.nodes;

import com.jme3.asset.AssetManager;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.shape.Line;
import com.jme3.scene.shape.Quad;
import com.jme3.shader.VarType;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.jme3.texture.Texture3D;
import com.jme3.texture.plugins.AWTLoader;
import com.jme3.ui.Picture;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import my.asteroid.utilities.Utilities;

 * @author Peter
public class CanvasNode extends Node implements SceneProcessor{
 //protected Point[] point;\
 protected AssetManager assetManager;
 protected AWTLoader awtLoader;
 protected VarType varType;
 protected int imageType;
 protected int width = 1;
 protected int height = 1;
 protected int newWidth = 1;
 protected int newHeight = 1;
 protected BufferedImage bufferedImage;
 protected Picture picture;
 protected Geometry geometry;
 protected Graphics graphics;
 protected Material material;
 protected Texture2D texture;
 protected Object lock = new Object();
 protected RenderManager rm;
 protected ViewPort vp;
 protected boolean reshapeNeeded = false;
 protected int counter = 0;
 protected boolean clearBackground = false;

 public CanvasNode(String name, int width, int height, AssetManager assetManager){
  this(name, width, height, assetManager, VarType.Texture2D, BufferedImage.TYPE_INT_ARGB);//type_int_argb
 public CanvasNode(String name, int width, int height, AssetManager assetManager, VarType varType, int imageType){
  this.width = width;
  this.height = height;
  this.assetManager = assetManager;
  this.awtLoader = awtLoader = new AWTLoader();
  this.varType = varType;
  this.imageType = imageType;
  Mesh mesh = new Quad(width, height);
  geometry = new Geometry("quad", mesh);
  bufferedImage = new BufferedImage(width, height, imageType);//BufferedImage.TYPE_INT_ARGB
  graphics = bufferedImage.createGraphics();
  texture = new Texture2D(awtLoader.load(bufferedImage, true));
  material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");//"Common/MatDefs/Misc/Unshaded.j3md"
  material.setTexture("ColorMap", texture);
  //material.setTextureParam("ColorMap", varType, new Texture2D(awtLoader.load(bufferedImage, true)));
  setImage(bufferedImage, true);

 protected final void setImage(BufferedImage bufferedImage, boolean flipY){
  //material.setTextureParam("ColorMap", new Texture2D(awtLoader.load(bufferedImage, flipY)));
  material.setTexture("ColorMap", new Texture2D(awtLoader.load(bufferedImage, flipY)));
 public void setRGB(Raster raster){
 public void setRGB(int x, int y, int color){
  System.out.println("CanvasNode.setRGB(" + x + "," + y + "," + color + " Illegal value");
  bufferedImage.setRGB(x, y, color);
 public void setRGB(int startX, int startY, int[] rgbArray, int offset, int scansize){
  boolean ok = true;
  bufferedImage.setRGB(startX, startY, width, width, rgbArray, offset, scansize);
 public void initialize(RenderManager rm, ViewPort vp){
  if (this.rm == null){
   this.rm = rm;
   this.vp = vp;
   reshape(new ViewPort("test", new Camera(newWidth, newHeight)), newWidth, newHeight);
 private void reshapeInThread(int newWidth, int newHeight){
  System.out.println("CN.reshapeInThread(" + width + "," + height + ", " + newWidth + "," + newHeight + ")");
  width = newWidth;
  height = newHeight;
  bufferedImage = new BufferedImage(width, height, imageType);//BufferedImage.TYPE_INT_ARGB
  graphics = bufferedImage.createGraphics();
  texture = new Texture2D(awtLoader.load(bufferedImage, true));
  material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");//"Common/MatDefs/Misc/Unshaded.j3md"
  material.setTexture("ColorMap", texture);
  setImage(bufferedImage, true);
 public boolean isInitialized(){
  return(bufferedImage != null);

 public void update(Graphics g){
  System.out.println("CN.update()" + " width=" + width + ", height=" + height + ", counter=" + counter);
  if (clearBackground){
   g.fillRect(0, 0, width, height);

    public void paint(Graphics g){
  System.out.println("CN.paint()" + " width=" + width + ", height=" + height);
  System.out.println("CN.paint()" + " bufferedImage=" + bufferedImage);
       // Graphics2D g2d = (Graphics2D) g;
        synchronized (lock){
            g.drawImage(bufferedImage, 0, 0, null);
  if (counter == 100){
   System.out.println("CN.paint() " + " test reshape()");
   reshape(new ViewPort("test", new Camera(100, 100)), 100, 100);

 public void preFrame(float tpf){
  System.out.println("CN.preframe())" + " width=" + width + ", height=" + height);
  //graphics.fillRect(0, 0, width, height);
  for (int h = 0;h < height;h++){
   for (int w = 0;w < width;w++){
    bufferedImage.setRGB(h, w, (int)(Math.random() * Integer.MAX_VALUE));
  setImage(bufferedImage, true);
 public void postQueue(RenderQueue rq){
 public void postFrame(FrameBuffer out){
        if (reshapeNeeded){
            reshapeInThread(newWidth, newHeight);
   reshapeNeeded = false;
 public void reshape(ViewPort vp, int w, int h){
  System.out.println("CN.reshape(" + w + "," + h + ")");
  newWidth = w;
  newHeight = h;
  reshapeNeeded = true;
 public void cleanup(){


…or you didn’t read the sticky topic at the top of the forum about how to post code blocks…

It sounds like you are trying to put a canvas into your 3D scene? Honestly, I haven’t seen anyone wanting this.

Is it that you just want to use Swing to draw on the image? Or?

Most of the talk of “canvas” and images is going the other direction. They want the 3D scene in their Swing/AWT/etc. GUI.

I put canvases in swing all the time. I’m trying something different. Swingless. I’m adding my 3D radar to the guiNode. It looks like this. And it needs to update every frame.

For something like a radar screen, a canvas is awfully heavyweight. There are much more efficient ways to do the same thing with standard 3D meshes, and I think you’ll find that they’re easier than doing the math to draw concentric circles. The end result will also be much, much easier to incorporate correctly with the rest of your 3D scene (I.e. placing it on a command console in the 3D world, partial transparency, etc.).

Or write directly to the ImageRaster of the JME Image. Someone even put together a library for that somewhere. ImagePainter or something like that… it had circle primitives and so on.

Ok. I’ll have to decipher what you said and then work on it. Here is the heart of the 3D radar. The math is done. You can see, I need to get each geometry/s translation every frame. I’m not sure I could move points in a mesh. If you can point me in the right direction, I’ll look at it. I have considered it.


        worldCenter = new Vector3d();
        controlledLocation = new Vector3d(toVector3d(controlled.getWorldTranslation()));
        controlledRotation = new Vector3d(toVector3d(controlled.getWorldRotation()));//degree

        euler[X] = controlledRotation.x;//degree
        euler[Y] = controlledRotation.y;//degree
        euler[Z] = controlledRotation.z;//degree

        positionArray = Math3D.Translate(positionArray, controlledLocation, worldCenter);//move to 0,0,0

        positionArray = Math3D.RotateX(positionArray, -euler[X]); //Pitch deg
        positionArray = Math3D.RotateY(positionArray, -euler[Y]); //Heading deg
        positionArray = Math3D.RotateZ(positionArray, -euler[Z]); //Roll deg

        positionArray = Math3D.Translate(positionArray, worldCenter, controlledLocation);//move back x,y,z


It’s like right at the top of the forum page. Not sure how people manage to miss it.

1 Like