Save/Load userData to/from .irr Scenes

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Save/Load userData to/from .irr Scenes

Post by Acki »

hi,
I wanted to store and load additional datas for nodes into an .irr file (loadScene, saveScene)...
during my researches I saw that there are no tutorials on this (at least I found none)...
so maybe this can be used as little tutorial for others who are interested in this topic... :lol:

also I'm not sure if this is the best way to do this,
so improvements are realy welcome !!! ;)

Code: Select all

#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

class mySerializer : public ISceneUserDataSerializer{
  private:
    IFileSystem* Filesys;
    IVideoDriver* Driver;

  public:
    //! called for each node loaded from the file
    void OnReadUserData(ISceneNode* forSceneNode, io::IAttributes* userData){
      // here you can save additional data for each node
      // maybe get the data from an array and use the node's ID as index ???
      switch(forSceneNode->getType()){
        case ESNT_ANIMATED_MESH:{
          stringc str = userData->getAttributeAsString("TestName");
          printf("name: %s\n", str.c_str());
        }break;
      }
    }
    //! called for each node saved to the file
    IAttributes* createUserData(ISceneNode* forSceneNode){
      // here you can load additional data for each node
      // maybe store the data in an array and use the node's ID as index ???
      switch(forSceneNode->getType()){
        case ESNT_ANIMATED_MESH:{
          IAttributes* atr = Filesys->createEmptyAttributes(Driver);
          atr->addString("TestName","name of the mesh");
          return atr;
        }break;
      }
      return 0;
    }
    //! Constructor
    mySerializer(IrrlichtDevice* dev){
      if(dev){
        Filesys = dev->getFileSystem();
        Driver = dev->getVideoDriver();
      }
    }
};

int main(){
  // create Irrlicht
  IrrlichtDevice* device = createDevice(EDT_DIRECT3D9);
  IVideoDriver* driver = device->getVideoDriver();
  ISceneManager* smgr = device->getSceneManager();

  // create the serializer
  mySerializer serializer(device);

  // create and save a scene
  IAnimatedMesh* mesh = smgr->getMesh("media/dwarf.x");
  IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
  node->setMaterialFlag(EMF_LIGHTING, false);
  smgr->saveScene("test.irr", &serializer);

  // load the scene
  smgr->loadScene("test.irr", &serializer);

  // setup and run Irrlicht render loop
  smgr->addCameraSceneNodeFPS();
  while(device->run()){
    driver->beginScene(true, true, video::SColor(0,0,0,0));
    smgr->drawAll();
    driver->endScene();
  }
  device->drop();
  return 0;
}
Last edited by Acki on Mon Dec 01, 2008 2:57 pm, edited 2 times in total.
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Acki,

Why do you keep a pointer to the created attribute object? I believe your usage is incorrect and can lead to undefined behavior.

The caller invokes serializer->createUserData() and should call attr->drop() on any valid IAttributes* that is returned. You also call drop() on the same object, so the last drop() call will actually be touching deallocated memory.

You should remove the atr member entirely and createUserData() should be changed to look like...

Code: Select all

IAttributes* createUserData(ISceneNode* forSceneNode)
{ 
   switch(forSceneNode->getType())
   { 
      case ESNT_ANIMATED_MESH:
      { 
         IAttributes* attribs = filesys->createEmptyAttributes(driver); 
         attribs->addString("TestName","name of the mesh"); 
         return atr; 
      }
      break; 
   } 
   return 0; 
} 
Also, you should not need to create the serializer on the heap. Since it is not reference counted you should be able to create it on the stack and pass the address to smgr->loadScene().

Finally, is there any reason that you always write your member variable names in all lower case? This makes it difficult to tell if you're using globals, locals or members. It might be good to adopt the Irrlicht convention and capitalize the first character of every member variable declaration.

Travis
Acki
Posts: 3496
Joined: Tue Jun 29, 2004 12:04 am
Location: Nobody's Place (Venlo NL)
Contact:

Post by Acki »

vitek wrote:Why do you keep a pointer to the created attribute object? I believe your usage is incorrect and can lead to undefined behavior.

The caller invokes serializer->createUserData() and should call attr->drop() on any valid IAttributes* that is returned. You also call drop() on the same object, so the last drop() call will actually be touching deallocated memory.
yes, this I was curious about... :oops:
I tried to follow the rule "object made with a create function must be droped"...
so I don't need to drop the new created attribute, because this will be done by saveScene(...), right ???
vitek wrote:Finally, is there any reason that you always write your member variable names in all lower case?
depends on my mood... :lol:
well, for such small snippets I often don't care, because they're pretty easy to read...
but you're right, I'll change them, too... ;)
while(!asleep) sheep++;
IrrExtensions:Image
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

If you're just returning the pointer to someone else (i.e., you're writing another create...() function), there is no need to drop() the pointer. Consider the following example...

Code: Select all

IAttributes* createSpecialAttributes(IFileSystem* fileSystem)
{
  IAttributes* attribs = fileSystem->createEmptyAttributes();
  return attribs;
}
There is no need to call drop() on attribs because we're actually implementing a create...() function, and the caller is supposed to be dropping the created object.

As for the coding style you use when writing examples, you should always consider that new C++ programmers are reading your code. You want to do everything you can to make your code easier to read and understand.

Travis
gabdab
Posts: 42
Joined: Fri May 12, 2006 5:11 pm

Post by gabdab »

The example works fine here,thanks.
I didn't understand what the flaws are with this approach, after all it is the only one I was able to have running.
I hope that the code blubberish got more comprehensible 3 years after the first post or I will need to pay an interpreter to parse the forums.
:(
Post Reply