Reloading textures on a geometry

Is there a way to reload a texture on a quad? im trying to get it to update but i’m having no luck,

also if anyone knows a slick way to go from a java.awt.image.BufferedImage to a com.jme3.texture.Image

ima try at it some more, just wondering if anyone knows of some refrence documentation i can read up on :slight_smile:

Thanks in advance

-Allman

http://hub.jmonkeyengine.org/javadoc/jme3tools/converters/ImageToAwt.html

1 Like

Thanks a bunch normen! you gave me the missing puzzle piece :slight_smile:

So this is what i have come up with so far, still working on it just really excited to share my results :smiley:

my reader class :

[java]

/*

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

    */

    /**

    *
  • @author Programmer

    /

    import com.jme3.texture.Image;

    import com.jme3.texture.Image.Format;

    import java.awt.image.BufferedImage;

    import java.io.IOException;

    import java.net.MalformedURLException;

    import java.net.URL;

    import java.nio.ByteBuffer;

    import javax.imageio.ImageIO;

    import jme3tools.converters.ImageToAwt;

    public class JPGStreamReader {

    private String imgLocation;

    private URL imgURL;

    private BufferedImage awtImage;

    private Image jmeImage;

    private ByteBuffer byteBuffer;

    final public Format jmeformat = Format.RGBA8;

    public JPGStreamReader(String imgLocation){

    this.imgLocation = imgLocation;

    byteBuffer = ByteBuffer.allocateDirect((640
    4804));

    changeURL(imgLocation);

    readImage();

    }

    private void changeURL(String imgLocation){

    try{

    imgURL = new URL(imgLocation);

    System.out.println(imgURL);

    }

    catch(MalformedURLException e){

    }

    }

    public void readImage(){

    try{

    byteBuffer.clear();

    awtImage = ImageIO.read(imgURL);

    ImageToAwt.convert(awtImage, jmeformat,byteBuffer);

    jmeImage = new Image(jmeformat,640,480, byteBuffer, null);

    System.out.println("JME IMAGE: " + jmeImage);

    }catch(IOException e){

    }

    }

    public Image getJMEImage(){

    readImage();

    return jmeImage;

    }

    }

    [/java]

    and my test class

    [java]

    import com.jme3.app.SimpleApplication;

    import com.jme3.material.Material;

    import com.jme3.scene.Geometry;

    import com.jme3.scene.shape.Quad;

    import com.jme3.texture.Image;

    import com.jme3.texture.Texture2D;

    /

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

    */

    /**

    *
  • @author Programmer

    /

    public class JPGStreamReaderTest extends SimpleApplication{

    private JPGStreamReader reader;

    Texture2D rendertex;

    JPGStreamReaderTest(){

    reader = new JPGStreamReader(“somewebcamurl”);

    }

    public static void main(String args[]){

    JPGStreamReaderTest test = new JPGStreamReaderTest();

    test.start();

    }

    @Override

    public void simpleInitApp() {

    Image jmeImage = reader.getJMEImage();

    /
    * A simple textured cube – in good MIP map quality. */

    Quad plane = new Quad(640f,480f, true);

    Geometry cube = new Geometry(“My Textured Plane”, plane);

    Material mat_stl = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

    rendertex = new Texture2D(640, 480, reader.jmeformat);

    rendertex.setImage(jmeImage);

    // mat_stl.setColor(“Color”, ColorRGBA.Blue);

    mat_stl.setTexture(“ColorMap”, rendertex);

    cube.setMaterial(mat_stl);

    System.out.print(“Textured applied about to attach cube”);

    cube.setLocalTranslation(-500f, 0f, -500f);

    // cube.setLocalRotation(new Quaternion(FastMath.PI,0f, 0f, 0f));

    rootNode.attachChild(cube);

    }

    @Override

    public void simpleUpdate(float tpf) {

    rendertex.setImage(reader.getJMEImage());

    }

    }

    [/java]



    Its working out suprisingly smoth atm, if anyone sees any suggestions right away let me know :slight_smile:
1 Like

Good job, gratz :slight_smile: You are updating the image every render frame, so I take it this is some kind of webcam or something you read from. For a full application you can probably save some CPU cycles when you update the image e.g. only every 1/25 frame? Something like:

[java]

private float counter = 0;

private float max = 1f / 25f; //25 frames per second

public void simpleUpdate(float tpf) {

counter = counter+tpf;

if(counter>=max){

rendertex.setImage(reader.getJMEImage());

counter = 0;

}

}

[/java]



Also it would be probably easiest to handle as some Control that you attach to a quad (if there should be multiple instances of these) or as an AppState that already brings the quad (if its a global “thing” in your application).

1 Like

You could also look at moving the image loading to another thread so the load placed on the system to read in the image doesn’t impact on your frame rate.



it’s looking good mate, keep up the good work :slight_smile:



… actually something may be a bit wrong: while your app is running, is the ‘Textures (M)’ value constant increasing ? also 916 is very large number of verts for a single quad ?

1 Like

Yes Textures (M) is constantly increasing, it was very rapid at first but after implementing normans trick to run it at 1/25 frame rate it slowed down.

the quad is the only geometry in the scene, i dont think i did anything to overide the default number of verticies

Thanks for the thread link, ill read up on it and try to get it to work :slight_smile:

-allman

i watched it for a bit and it climbs to various numbers and then drops back down to zero, so im guessing its the way im creating the jmeImages that its just putting up all the old textures up for garbage collection ?

jmeImage = new Image(jmeformat,640,480, byteBuffer, null);

Moved my quad creation and management to a app state (Thanks Normen!) put the image loading in a thread(Thanks thetoucher!)

Still have allot of vertices, but my frame rate is 1142.5 times faster :slight_smile:

i called System.gc() after loading the new texture and the Texture(m) stays at 4! :slight_smile:

My concurrency skills aren’t all that great, i have a run-away thread after i close the window, any thoughts?



[java]

import com.benkyou.webcam.WebcamViewerAppState;

import com.jme3.app.SimpleApplication;



/*

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

    */



    /**

    *
  • @author Programmer

    /

    public class JPGStreamReaderTest extends SimpleApplication{

    public static void main(String args[]){

    JPGStreamReaderTest test = new JPGStreamReaderTest();

    test.start();



    }



    @Override

    public void simpleInitApp() {

    WebcamViewerAppState webcamState = new WebcamViewerAppState(assetManager, "somewebcamurl", 10f, 10f);

    stateManager.attach(webcamState);

    rootNode.attachChild(webcamState.getWebcamNode());



    }

    @Override

    public void simpleUpdate(float tpf) {

    }



    }

    [/java]

    [java]

    package com.benkyou.util;



    /

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

    */



    /**

    *
  • @author Programmer

    /

    import com.jme3.texture.Image;

    import com.jme3.texture.Image.Format;

    import java.awt.image.BufferedImage;

    import java.io.IOException;

    import java.net.MalformedURLException;

    import java.net.URL;

    import java.nio.ByteBuffer;

    import java.util.concurrent.Callable;

    import javax.imageio.ImageIO;

    import jme3tools.converters.ImageToAwt;

    public class JPGStreamReader implements Callable{

    private String imgLocation;

    private URL imgURL;

    private BufferedImage awtImage;

    private Image jmeImage;

    private ByteBuffer byteBuffer;

    final public Format jmeformat = Format.RGBA8;

    public JPGStreamReader(String imgLocation){

    this.imgLocation = imgLocation;

    byteBuffer = ByteBuffer.allocateDirect((640
    4804));

    changeURL(imgLocation);

    readImage();

    }

    private void changeURL(String imgLocation){

    try{

    imgURL = new URL(imgLocation);

    }

    catch(MalformedURLException e){



    }

    }



    public void readImage(){

    try{

    byteBuffer.clear();

    awtImage = ImageIO.read(imgURL);

    ImageToAwt.convert(awtImage, jmeformat,byteBuffer);

    jmeImage = new Image(jmeformat,640,480, byteBuffer, null);

    }catch(IOException e){

    }

    }

    public Image getJMEImage(){

    readImage();

    return jmeImage;

    }



    public Object call() throws Exception {

    readImage();

    return getJMEImage();

    }



    }

    [/java]



    [java]

    /

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

    */

    package com.benkyou.webcam;



    import com.benkyou.util.JPGStreamReader;

    import com.jme3.app.state.AbstractAppState;

    import com.jme3.asset.AssetManager;

    import com.jme3.material.Material;

    import com.jme3.scene.Geometry;

    import com.jme3.scene.Node;

    import com.jme3.scene.shape.Quad;

    import com.jme3.texture.Image;

    import com.jme3.texture.Texture2D;

    import java.util.concurrent.Callable;

    import java.util.concurrent.Future;

    import java.util.concurrent.ScheduledThreadPoolExecutor;



    /**

    *
  • @author Programmer

    */

    public class WebcamViewerAppState extends AbstractAppState{

    private Node webcamNode = new Node(“Webcam Node”);

    private Geometry webcam;

    private Quad plane;

    private Texture2D webcamImage;

    private String url;

    private float xSize, ySize;

    private Material mat_stl;

    private AssetManager assetManager;

    private JPGStreamReader reader;

    private Image jmeImage;

    private ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(4);

    private float counter = 0;

    private float max = 1f/25f; //25 frames per second

    Future future = null;

    public WebcamViewerAppState(AssetManager assetManager, String url, float xSize, float ySize){

    reader = new JPGStreamReader(url);

    jmeImage = reader.getJMEImage();

    this.assetManager = assetManager;

    this.url = url;

    this.xSize = xSize;

    this.ySize = ySize;

    createViewer();

    }

    public Node getWebcamNode(){

    return webcamNode;

    }



    private void createViewer() {

    plane = new Quad(xSize, ySize, true);

    webcam = new Geometry(“My Webcam Plane”, plane);

    mat_stl = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

    webcamImage = new Texture2D(640, 480, reader.jmeformat);

    webcamImage.setImage(jmeImage);

    mat_stl.setTexture(“ColorMap”, webcamImage);

    webcam.setMaterial(mat_stl);

    webcamNode.attachChild(webcam);

    }



    @Override

    public void update(float tpf) {

    super.update(tpf);

    counter = counter + tpf;

    if(counter >= max){

    try{

    if(future == null){

    future = executor.submit(reader);

    }

    else if(future != null){

    if(future.isDone()){

    webcamImage.setImage((Image) future.get());

    System.gc();

    future = null;

    }else if(future.isCancelled()){

    //Set future to null. Maybe we succeed next time…

    future = null;

    }

    }

    }catch(Exception e){

    }

    }



    }

    }



    [/java]







    Not as exciting to look at with the lights off :slight_smile:

    Thanks again guys for all the help!