Free Class/Example for Model Previewing for an Editor or something

Hey so i have been on the forums trying to figure out how to do this for a few times now and I have finally found a way to do it. So just to give back to a community that is very helpful, I am going to be posting some of the code from the project i am working on, which is basically a world editor. I know there are probably plenty of people interested in making world editors or something like it, so here is an example (which should be usable in its current form) of how to do model previews.





import com.jme3.app.SimpleApplication;

import com.jme3.bounding.BoundingBox;

import com.jme3.light.DirectionalLight;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.post.SceneProcessor;

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.Spatial;

import com.jme3.system.AppSettings;

import com.jme3.system.JmeContext;

import com.jme3.texture.FrameBuffer;

import com.jme3.texture.Image;

import com.jme3.util.BufferUtils;

import com.jme3.util.Screenshots;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.image.BufferedImage;

import java.nio.ByteBuffer;

import java.util.logging.Level;

import java.util.logging.Logger;

import javax.swing.JPanel;



public class AssetPreview extends SimpleApplication implements SceneProcessor

{



private FrameBuffer offBuffer;

private ViewPort offView;

private Camera offCamera;

private AssetPreview.ImageDisplay display;

private int x, y, width, height;

private final ByteBuffer cpuBuf;

private final BufferedImage image;

private String model;

private boolean isStarted = false;

private boolean startRender = false;

private Thread curThread;



private class ImageDisplay extends JPanel

{



@Override

public void paintComponent(Graphics gfx)

{

super.paintComponent(gfx);

Graphics2D g2d = (Graphics2D) gfx;



synchronized (image)

{

g2d.drawImage(image, null, 0, 0);

}

}

}



public AssetPreview(int x, int y, int width, int height)

{

// initializing members

this.x = x;

this.y = y;

this.width = width;

this.height = height;

cpuBuf = BufferUtils.createByteBuffer(width * height * 4);

image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);



// making panel

display = new AssetPreview.ImageDisplay();



Logger logger = Logger.getLogger(AssetPreview.class.getName());

logger.getLogger("").setLevel(Level.OFF);

}



public void loadModel(String model)

{

while (curThread != null && curThread.isAlive())

{

try

{

Thread.sleep(2);

} catch (Exception e)

{

e.printStackTrace();

}

}

this.model = model;

if (isStarted)

{

this.restart();

} else

{

isStarted = true;

// setting up jmonkey renderer

this.setPauseOnLostFocus(false);

AppSettings settings = new AppSettings(true);

settings.setResolution(1, 1);

this.setSettings(settings);

this.start(JmeContext.Type.OffscreenSurface);

}

}



public void setupOffscreenView()

{

offCamera = new Camera(width, height);



// create a pre-view. a view that is rendered before the main view

offView = renderManager.createPreView(“Offscreen View”, offCamera);

offView.setBackgroundColor(ColorRGBA.White);

offView.setClearFlags(true, true, true);



// this will let us know when the scene has been rendered to the

// frame buffer

offView.addProcessor(this);



// create offscreen framebuffer

offBuffer = new FrameBuffer(width, height, 1);



// setup framebuffer’s cam

offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f);

offCamera.setLocation(new Vector3f(0f, 0f, -2.6f));

offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);





// setup framebuffer to use renderbuffer

// this is faster for gpu → cpu copies

offBuffer.setDepthBuffer(Image.Format.Depth);

offBuffer.setColorBuffer(Image.Format.RGBA8);



// set viewport to render to offscreen framebuffer

offView.setOutputFrameBuffer(offBuffer);

}



@Override

public void simpleInitApp()

{

curThread = Thread.currentThread();

setupOffscreenView();



// show model

Spatial loadedModel = assetManager.loadModel(model);

float height = ((BoundingBox) loadedModel.getWorldBound()).getYExtent();

float width = ((BoundingBox) loadedModel.getWorldBound()).getZExtent();



// scale the model to size 1

float scale = 0.0f;

if (height > width)

{

scale = 1f / height;

}else{

scale = 1f / width;

}

loadedModel.scale(scale, scale, scale);



// center the model

loadedModel.setLocalTranslation(loadedModel.getWorldBound().getCenter().mult(-1));

rootNode.attachChild(loadedModel);



// create light

DirectionalLight light = new DirectionalLight();

light.setDirection(new Vector3f(0.0f, 0.0f, 1.0f));

rootNode.addLight(light);

offView.attachScene(rootNode);

startRender = true;

}



public JPanel getJPanel()

{

display.setLocation(x, y);

display.setSize(width, height);

return (JPanel) display;

}



public void initialize(RenderManager rm, ViewPort vp)

{

}



public void reshape(ViewPort vp, int w, int h)

{

}



public boolean isInitialized()

{

return true;

}



public void preFrame(float tpf)

{

}



public void postQueue(RenderQueue rq)

{

}



/**

  • Update the CPU image’s contents after the scene has been rendered to the
  • framebuffer.

    */

    public void postFrame(FrameBuffer out)

    {



    if (startRender)

    {

    cpuBuf.clear();

    renderer.readFrameBuffer(offBuffer, cpuBuf);



    synchronized (image)

    {

    Screenshots.convertScreenShot(cpuBuf, image);

    }



    if (display != null)

    {

    display.repaint();

    }

    startRender = false;

    this.stop(true);

    }

    }



    public void cleanup()

    {

    }

    }





    I literally just got this working, so I will probably edit this code later on since it is an essential part of my project. Anyway it is really just a modification of the TestRenderToMemory.java example that doesn’t eat up 30% of your cpu. An example usage of the class would be:





    JFrame window = new JFrame();

    // … do all your window init junk



    // the layout is null for absolute positioning. That’s how i use it, but you don’t have too.

    window.setLayout(null);



    AssetPreview assetPreview = new AssetPreview(x,y,width,height);

    assetPreview.loadModel(“Models/Ninja/Ninja.mesh.xml”);

    window.add(assetPreview.getJPanel());

    window.setVisible(true);





    And that’s it.

    Btw, you can make multiple instances of the class (unlike a normal JME3 canvas) and you can also reuse the same one by calling loadModel again to load a different model.

    I am going to add texture support in the next few days.



    Tell me if you have any problems with it.

Thanks for sharing though I guess most users just double-click the model or look at it in the model import window :wink:

Uhh, like in the jme ide? I’m talking about this for making your own swing UI or for example if someone wanted to remake a jme world editor you would use something like this.

1 Like