Page 1 of 2

Changing model during run time?

Posted: Fri May 14, 2010 1:13 pm
by Spinland
Hi, total newbie here, both to Irrlicht and to C++ (did some C coding back in the late 80s, and am fairly comfortable with Java), and I have a how-to question...

I'm using the Dev-C++ IDE, and have the Hello World and mesh Viewer tutorials up and running successfully, and am able to bring in an .obj model of my own making.

Based on my understanding (admittedly still very sketchy) of the process, the code first reads in the geometry of a model, then goes into the display loop where it's displayed and that display is refreshed during each iteration of the while loop. Am I on track thus far?

What I'd like to be able to do is over-write the contents of the .obj file during run time, and have that change reflected in the display loop. Not an animation, but a situation where the actual geometry changes over time and the display keeps up with the changes.

Is this a straightforward operation? Could some kind soul point me to help on how I'd re-work the display while loop to manage this--or is it best done in some other fashion?

Many thanks in advance!

Posted: Fri May 14, 2010 1:21 pm
by hybrid
You can simply create a new scene node with the new geometry, and take the position etc. from the old one. Then remove the old node. But better use a different file and load it from there. If you get the data from a different process, you need to remove the mesh from mesh cache in order to get the same file reloaded from disk.

Posted: Fri May 14, 2010 4:19 pm
by Spinland
Thanks for your response thus far, but I'm still running into difficulty.

Let's say I have created two nodes, each with a different mesh:

Code: Select all

	
	IMesh* mesh1 = smgr->getMesh("mesh1.obj");
	if (!mesh1)
	{
		device->drop();
		return 1;
	}
	IMeshSceneNode* node1 = smgr->addMeshSceneNode( mesh1 );

	IMesh* mesh2 = smgr->getMesh("mesh2.obj");
	if (!mesh2)
	{
		device->drop();
		return 1;
	}
	IMeshSceneNode* node2 = smgr->addMeshSceneNode( mesh2 );
And now inside the while loop, I have this from the tutorial:

Code: Select all

	while(device->run())
	{
		driver->beginScene(true, true, SColor(255,100,101,140));

		smgr->drawAll();

		driver->endScene();
        }
That displays both nodes at the same time until I exit the loop. I tried adding, for example, node2->drop(); right after the driver->endScene(); in the idea that after one iteration the second node would disappear. All it did was crash the program.

Is it possible to have new nodes created inside the while loop? Do you put them before the beginScene() call, and does that process use the same syntax as the node definitions I have above?

How do you drop nodes inside the loop?

Is it possible (or preferable) to draw only some nodes at a time, or must you always use drawAll()?

I'm trying to get through the documentation and understand this basic process of controlling what nodes to display when, but either I'm not looking in the right places or I'm just not getting it.

Many thanks!

Posted: Fri May 14, 2010 4:58 pm
by randomMesh
Spinland wrote:How do you drop nodes inside the loop?
You are not supposed to drop() nodes, you remove() them. Or add them to the deletion queue of the scene manager.

Only drop() objects that have been created by a method starting with create, e.g. ISceneManager::createFlyCircleAnimator().

Posted: Fri May 14, 2010 5:23 pm
by Spinland
Okay, thanks. Now, it seems logical that you need a test that the node exists before you remove() it, right? I tried this:

Code: Select all

	while(device->run())
	{
		driver->beginScene(true, true, SColor(255,100,101,140));

		smgr->drawAll();
		driver->endScene();
		
		Sleep(1000);
		if(node2) {
                  node2->remove();
                  }
	}
It started out well, after 1 second the second mesh vanished, but on the second iteration the program crashed. Is that not how you're supposed to test for a node being in the scene?

Thanks!

Posted: Fri May 14, 2010 5:26 pm
by randomMesh
Spinland wrote:Okay, thanks. Now, it seems logical that you need a test that the node exists before you remove() it, right?
Yes, you could do it like this

Code: Select all

if(node2)
{ 
	node2->remove(); 
	node2 = 0; //don't forget to 0 the pointer
}
But it's not a good idea to do this in your main loop. Rather call the node->remove() from your event receiver upon a key press or something.

Having a sleep() in your main render loop's not a good idea. :wink:

Posted: Fri May 14, 2010 5:29 pm
by Spinland
Okay, I failed to null the pointer, that makes sense.

As for the practice, the point here is I want to display a mesh, then after a time period drop it in favor of a revised version of the same mesh, and so on forever until I stop the loop. The mesh being displayed will change over time.

Posted: Fri May 14, 2010 5:40 pm
by Spinland
Oh, and thanks again. This stuff is coning to me slowly, and help climbing the learning curve is invaluable. 8)

Posted: Fri May 14, 2010 6:05 pm
by hybrid
If you're sure that only one instance of a mesh exists in your scene, you should call remove first, then remove the mesh from mesh cache (you should store the mesh pointer for this as well), then getMesh() on that mesh again, and finally addMeshSceneNode() storing the new pointer on the old one. This will completely exchange the first mesh instance by the second.
In order to place the new mesh at the position of the old, you need to store position and rotation (if necessary) in extra variables. The old position does not exist anymore after you removed the node.
Just make sure that you don't do this too often, because loading from disk takes some time, so rendering will halt for at least a few seconds.

Posted: Fri May 14, 2010 6:44 pm
by Spinland
Awesome, thanks. Words can't express how helpful you guys are! :wink:

Posted: Wed May 19, 2010 1:00 pm
by Spinland
Okay, I'm stuck again. I've searched through the documentation but I can't find what I need to be able to clear the mesh cache.

To recap: I have a single, static model on .obj format displayed, that never moves. The only thing that changes is the content of the .obj file gets over-written periodically, and I want the display to change to reflect the contents of the new .obj file instead of the old. Since this over-writing will happen many thousands of times over a run, using some sort of iterative node-adding technique doesn't seem advisable.

Here's what I have thus far:

Prime the node before the main loop:

Code: Select all

	IMesh* mesh1 = smgr->getMesh("media/control_loops.obj");
	if (!mesh1)
	{
		device->drop();
		return 1;
	}
	IMeshSceneNode* node1 = smgr->addMeshSceneNode( mesh1 );
Now the main loop starts: drop the node contents and re-load it from the .obj file:

Code: Select all

	while(device->run())
	{
		driver->beginScene(true, true, SColor(255,100,101,140));

		smgr->drawAll();
		driver->endScene();
	
                node1->remove();
                node1 = 0;

                mesh1 = smgr->getMesh("media/control_loops.obj");
	        if (!mesh1)
	        {
		       device->drop();
		       return 1;
	        }
	        node1 = smgr->addMeshSceneNode( mesh1 );
 	}

	device->drop();

	return 0;
}
When I replace the contents of the .obj file, as you probably knew, nothing changes in the display. Could you give me more specific pointers as to where and how I'm supposed to flush the cache so the new model displays when over-written?

Many thanks in advance!

Posted: Wed May 19, 2010 1:23 pm
by Acki
the problem is that the old mesh is still in mesh cache...
when you try to load another mesh with the same file name Irrlicht will search if it was already loaded and use the old one that's still in memory... ;)

the solution is to remove the mesh from the cache, too...
before new loading try:

Code: Select all

smgr->getMeshCache()->removeMesh(mesh1);

Posted: Wed May 19, 2010 1:32 pm
by Spinland
Okay, so if I have this inside my loop:

Code: Select all

driver->beginScene(true, true, SColor(255,100,101,140));

smgr->drawAll();

driver->endScene();
	
node1->remove();
node1 = 0;
        
smgr->getMeshCache()->removeMesh(mesh1);

mesh1 = smgr->getMesh("media/control_loops.obj");

    if (!mesh1)
    {
	   device->drop();
	   return 1;
    }

node1 = smgr->addMeshSceneNode( mesh1 );
And I over-write the contents of control_loops.obj with new geometry while it's running it still persists in showing the original model. Did I put the command in the wrong place?

Thanks!

Posted: Wed May 19, 2010 2:35 pm
by Spinland
Bingo, found it. See, I do RTFM sometimes! :wink:

The answer is to add this after I've removed the node:

Code: Select all

        smgr->getMeshCache()->clearUnusedMeshes();
Now it's working perfectly. Your clue led me towards looking at the correct classes for what I needed, so thank you so much! 8)

Posted: Wed May 19, 2010 3:36 pm
by bitplane
Sounds like you've found a bug, removing the mesh should work. We only added removeUnusedMeshes for people who have a huge scene and wanted to clear down their cache (it removes all meshes with a reference count of 1, ie, those which belong only to the mesh cache).

If the size of the mesh cache doesn't change after doing

Code: Select all

smgr->getMeshCache()->removeMesh(mesh1); 
then that must be a bug!