Load XML in a loop

Hello,



I try to test an idea, where I want to load an xml model in a loop e.g. the SimpleUpdate(). I wrote a simple application to test it, but the loaded model is displayed only the first time and then never again. What do I have to do, to let jME display the different xml models?



this is my code:

package uk.ac.ljmu.lab.jme;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.light.DirectionalLight;
import com.jme.light.PointLight;
import com.jme.light.SpotLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.state.LightState;
import com.jmex.model.XMLparser.JmeBinaryReader;
import com.jmex.model.XMLparser.JmeBinaryWriter;
import com.jmex.model.XMLparser.XMLtoBinary;
import com.jmex.model.util.ModelLoader;



public class XMLLoader extends SimpleGame{
   
   private Node tempNode;
   private Node Model;
   private int i = 1;
   String Path = "";
   
   private  LightState lightState;
   SpotLight sl = new SpotLight();
   PointLight light = new PointLight();
   DirectionalLight dl = new DirectionalLight();
   
   public static void main(String[] args) {
      //LoggingSystem.getLogger().setLevel(java.util.logging.Level.OFF);
      XMLLoader app = new XMLLoader();
      app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
   
       app.start();
   }

   
   protected void simpleInitGame() {
      RoomLight();      
   }
   
   protected void simpleUpdate() {
      LoadModel();
      i++;
      if (i == 8){
         i = 1;
      }
   }
   
   private void LoadModel(){
      Path = "walk0"+ i +".xml";
      Model = LoadXML(Path);
      System.out.println(Path);
      Model.setModelBound(new BoundingBox());
      Model.updateModelBound();
      rootNode.attachChild(Model);
      Model.updateWorldBound();            
   }
   
   private void RoomLight(){
      /* Set up a basic, default light */
      light = new PointLight();
      light.setDiffuse(new ColorRGBA( 0.75f, 0.75f, 0.75f, 0.75f ));
      light.setAmbient(new ColorRGBA( 0.75f, 075f, 0.75f, 1.0f ));
      light.setLocation(new Vector3f( 0, 60, 0 ));
      light.setEnabled(true);
      
      dl = new DirectionalLight();
      dl.setDiffuse (new ColorRGBA (0.2f, 0.2f, 0.2f, 0.75f));
      dl.setAmbient (new ColorRGBA (0.5f, 0.5f, 0.5f, 1f));
      dl.setDirection(new Vector3f( 0, -0.5f, -0.75f));
      dl.setEnabled(true);
      
      /* Attach the light to a lightState and the lightState to rootNode */
      lightState = display.getRenderer().createLightState();
      lightState.setEnabled(true);
      lightState.attach(light);
      lightState.attach(dl);
      rootNode.setRenderState(lightState);
   }
   
   
   private Node LoadXML(String filePath){
      try{
         //   Initialise binary converter
         XMLtoBinary converter = new XMLtoBinary();
          
         //Initialise binary reader
         JmeBinaryReader jbr = new JmeBinaryReader();
         
         //Initialise binary writer
         JmeBinaryWriter jbw = new JmeBinaryWriter();
           
         // convert the input file to a jme-binary "LabCube"
           ByteArrayOutputStream LabNoExtra = new ByteArrayOutputStream();
           URL LabModel = ModelLoader.class.getClassLoader().getResource(filePath);
           converter.sendXMLtoBinary(new BufferedInputStream(LabModel.openStream()), LabNoExtra);
           
           //get the "LabCube"
           tempNode = new Node ("Temporary Node");
           tempNode = jbr.loadBinaryFormat(new ByteArrayInputStream(LabNoExtra.toByteArray()));
           
           // write the "LabCube"
           ByteArrayOutputStream BO2 = new ByteArrayOutputStream();
           jbw.writeScene(tempNode,BO2);
           
           // Send the new jME binary to a jME SceneGraph and attach it.
           tempNode = jbr.loadBinaryFormat(new ByteArrayInputStream(BO2.toByteArray()));
      }
      catch(IOException e){
           System.out.println("Couldn't load the input file:" + e);
           e.printStackTrace();}
      catch (java.lang.NullPointerException npe ) {
          npe.printStackTrace();
      }
      return tempNode;
   }

}

Not sure what you intend to do, but the code you posted does as follows:

It loads a model from xml by converting it to the old binary format, then it saves the model to disk in binary, then it loads the same model yet again, this time fro m binary… every frame!  :-o



You should be able to see the number of objects in your scene (and your triangle count) rapidly shooting up, stopping only when java hits the memory limit.

Is that not the case? Then what do you see instead?

Whatever it is, you'll want to think again about if what you are doing really is the best way to do whatever you want to accomplish. For example, there is no reason to load your model twice each frame, and loading a model every frame is just overkill to begin with.



Have you tried looking at the user guide and tutorials, or maybe some of the test classes? Those might give you some new, and possibly better ideas how to solve your problem!

Hi,



the idea of my project supervisor was to simulate an animation of a model with xml files(for each frame a different xml file). And thats why I had this idea for the code (as a simple test).

And yes…the triangle count is increasing. I used the load method from an example and thought it would be ok… :?I will remove the binary writer and test it again.



Thanks for your advice.

You'll probably want to use SwitchNode in that case, and set it up in simpleInitGame() rather than simpleUpdate().

Then you'll only have to set the SwitchNode's active child accordingly in simpleUpdate().

Try this:


    private SwitchNode switchNode;
    private int numFrames = 7;
    protected void simpleInitGame() {
        RoomLight();
        switchNode  = new SwitchNode("switcher");
        for(int frame = 1; frame <= numFrames; frame++){
            switchNode.attachChild(LoadXML("walk0"+frame+".xml"));
        }
        switchNode.setActiveChild(0);
        rootNode.attachChild(switchNode);
    }
   
    protected void simpleUpdate() {
        switchNode.setActiveChild(i-1);
        i++;
        if (i > numFrames){
            i = 1;
        }
    }


It will give you a nice "performance boost" as well ;)
But are you aware that the xml format supports morph target animations using KeyframeController, with the additional bonus of being able to set your animation time without having to worry about when to switch frames yourself, and morphing between keyframes?

Thanks, yes I've heard about this. But I guess in Blender it is not possible to export animations to xml. Is that right?..

No, it's not! In fact, the most important reason I started the blender exporter to begin with, was that I needed a way to export animations from blender to jME.

Just be sure to pick up the most recent version of the exporter from http://wwwhomes.uni-bielefeld.de/krabien/jmestuff/jmeXMLExport.py, the older ones may have problems with coordinate conversion and/or controller timing.

All it takes is to set the "Morph Target animations" button in the exporter, define some keyframes in a text window (in blender), and hit "Export"!

Okay, good to know. I've tested your code and it works now. There was a little bug in the if-statement. I had to change it to "if(i>=numFrames)". But now it works and is pretty fast…after it takes a while to load the files at the program start.

Oh, I forgot the NullPointerException…I catch it but perhaps you can tell me why this happens.

ByteArrayOutputStream BAOS = new ByteArrayOutputStream();
URL Model = XMLLoader.class.getClassLoader().getResource(filePath);
converter.sendXMLtoBinary(new BufferedInputStream(Model.openStream()), BAOS); <-- it's in this line, in the xml load method

JDK 21 Documentation - Home

Returns:
    A URL object for reading the resource, or null if the resource could not be found or the invoker doesn't have adequate privileges to get the resource.

That should give you an idea.
It can be a bit tricky at first to understand how resources are resolved by ClassLoader. If in doubt, best read up on it in a good java reference manual.

hm…okay… I'm confused because the same methof works fine in another project…without NullPointerException.