Connect node with custom class? (ISceneNode User data)

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
suliman
Posts: 379
Joined: Sat Sep 23, 2006 2:06 pm

Connect node with custom class? (ISceneNode User data)

Post by suliman »

Hi
Lets say i have something like:

Code: Select all

class unit
{
public:
	float vel;
	vect3d pos;
	irr::scene::IAnimatedMeshSceneNode* node;


	unit(void);
	~unit(void);
};
When running collision etc i will get the node, but how to connect the node and my unit class, so when i get the node, i can also get the unit that is using the node as its body?

Thanks
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

I don't think you actually can, would be good for nodes to have a user_data pointer that could point back to a class that owns the node in the user's app.

You could do something clever with the id of the node and use that to link it to, say, an array that contains the units and the id is the index of the unit in the array that the node belongs to.

Or you could search through your unit array until you find the one that owns that node by comparing the pointers.
Image Image Image
suliman
Posts: 379
Joined: Sat Sep 23, 2006 2:06 pm

Post by suliman »

Seems not very optimized.
would it be stupid to do like this?

Code: Select all

class unit: public irr::scene::IAnimatedMeshSceneNode{


}

then the unit itself would be the node! This might result in other problems maybe
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

It's certainly another option... I'm not sure what problems it would really cause, though people have said before that encapsulation is better than inheritance, maybe one of those people can chip in on some reasons for that.
Image Image Image
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

It's a bit nasty to have to hijack the ID (which is already abused for collision detection), or to keep a map of Irrlicht -> application objects in your app.

Is there a principled objection to something like this?

Code: Select all

Index: include/ISceneNode.h
===================================================================
--- include/ISceneNode.h	(revision 1278)
+++ include/ISceneNode.h	(working copy)
@@ -44,7 +44,7 @@
 			: RelativeTranslation(position), RelativeRotation(rotation), RelativeScale(scale),
 				Parent(0), ID(id), SceneManager(mgr), TriangleSelector(0),
 				AutomaticCullingState(EAC_BOX), IsVisible(true),
-				DebugDataVisible(EDS_OFF), IsDebugObject(false)
+				DebugDataVisible(EDS_OFF), IsDebugObject(false), UserData(0)
 		{
 			if (parent)
 				parent->addChild(this);
@@ -650,6 +650,21 @@
 			return 0; // to be implemented by derived classes
 		}
 
+		//! Set opaque user data.  This is any data that you want to associate with
+		//! this scene node.  It will not be used by Irrlicht.
+		//! \param userData	The data to set
+		void setUserData(void * userData)
+		{
+			UserData = userData;
+		}
+
+		//! Set opaque user data.
+		//! \return  The user data that you previously provided, or 0.
+		void * getUserData(void)
+		{
+			return UserData;
+		}
+
 	protected:
 
 		//! A clone function for the ISceneNode members.
@@ -739,6 +754,9 @@
 
 		//! is debug object?
 		bool IsDebugObject;
+
+		//! Opaque user data, supplied and used by the user application.
+		void * UserData;
 	};
 
 } // end namespace scene

Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, that of having a typeless and user code related void* in all scene nodes.
JP
Posts: 4526
Joined: Tue Sep 13, 2005 2:56 pm
Location: UK
Contact:

Post by JP »

You're opposed to it hybrid? What's wrong with a typeless and user code related void?

I've been using it in my personal engine and i didn't think there were any problems with it...

Is it just in principal or do you have some other reason?
Image Image Image
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

It has been discussed many times now, but the dev team always concluded to avoid this, especially Niko is against it. Use the map to get back to the original object.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I don't really like the idea of stuffing a void* into ISceneNode. It isn't really necessary [though I'd like to see some performance numbers to prove me wrong], and I see three issues. One with deallocation, one with type safety, and one with extensibility and serialization.

The issue with deallocation is that the scene node has no idea what to do with the user data pointer when the scene node destructor is called. i.e. If the user data pointer is a newton body, that newton body needs to be destroyed and deallocated with the proper newton functions. The scene node has no idea about how to do this, and it shouldn't. So how does the body get cleaned up?

The application would somehow need to know when every scene node was destroyed so that it would have the opportunity to deallocate the body of the user data pointer. It would also have to be able to determine the actual type of the user data and how it was allocated. In some cases, this is acceptable. The application often knows all of this information a priori. If this is the case then they can explicitly clean up the user data just before the node that holds it is deallocated. Unfortunately this doesn't work well for all cases because not everyone knows when a node is destroyed [delete animator], where the allocation came from [new/malloc/stack/global], or the actual type of the user data object.

A possible solution to this problem would be to use an IReferenceCounted* member. This fixes the above problem. The destructor of the scene node would just drop the UserData pointer and be done with it. The derived user data destructor would be written to clean up the necessary resources.

I don't really think it would be that bad to add an unserialized IReferenceCounted* to the scene node and let the user work out the other details.

Travis
Last edited by vitek on Wed Mar 05, 2008 6:28 am, edited 2 times in total.
suliman
Posts: 379
Joined: Sat Sep 23, 2006 2:06 pm

Post by suliman »

uh?
im not totally on level with you guys here but with loads of bullets going around and hitting various nodes, its not efficient to loop through all nodes in the scene every time a node is hit to figure out what unit to damage.

Is there any real problem with inheritance (my units are actually also nodes themselfes)? I didnt get it.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

You don't have to do a linear search [which is slow when you have many nodes] to find what scene node is associated with an entity.

You can use a binary search which is an order of magnitude faster than a linear search for sufficiently large data sets. Searching through an array of 10000 elements for a specific item will, on average, take 10000 compares in the worst case and 5000 compares in the average case. A binary search will take 14 compares in the worst and 10 compares average case. It isn't constant time, but it is fast.

As an aside, if you are doing bullets and you are checking each bullet against every scene node, you are probably wasting a lot of cycles doing unnecessary intersection tests. This is likely to have more of an effect on performance than searching for the unit that maps to the node that was hit. If you partition your environment and only check bullets against nodes in the same area you will see a dramatic improvement.

As for inheritance, there is no problem with it, but often that doesn't work. The user of the library can't really inherit from CMeshSceneNode, so that isn't a possibility for them.

Travis
Last edited by vitek on Tue Mar 04, 2008 7:21 pm, edited 1 time in total.
Vsk
Posts: 343
Joined: Thu Sep 27, 2007 4:43 pm

Post by Vsk »

vitek wrote:You don't have to do a linear search [which is slow when you have many nodes] to find what scene node is associated with an entity.

You can use a binary search which is an order of magnitude faster than a linear search for sufficiently large data sets. Searching through an array of 10000 elements for a specific item will, on average, take 5000 compares. A binary search will take 14. It isn't constant time, but it is fast.

As an aside, if you are doing bullets and you are checking each bullet against every scene node, you are probably wasting a lot of cycles doing unnecessary intersection tests. This is likely to have more of an effect on performance than searching for the unit that maps to the node that was hit. If you partition your environment and only check bullets against nodes in the same area you will see a dramatic improvement.

As for inheritance, there is no problem with it, but often that doesn't work. The user of the library can't really inherit from CMeshSceneNode, so that isn't a possibility for them.

Travis
Why don't use a Hash for this query, if you do it properly (very easy) you have O(1) query for searching.

By the way, you guys that have experience, why hash aren use it everywhre in video games for this kind of querys?
if you are doing other system you don't use it because it has a ungly order query, but in this case that we are looking for one element that posible have a key (that can be goo maped) why not use it?.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Why don't use a Hash for this query, if you do it properly (very easy) you have O(1) query for searching.
Last I checked, Irrlicht doesn't provide a hash map, so I didn't recommend it. The current C++ standard library doesn't provide hash containers either, so there really isn't a single portable implementation that I could refer everyone to.
By the way, you guys that have experience, why hash aren use it everywhre in video games for this kind of querys?
People do use hash maps/sets in games.

I don't deny that having the extra data pointer in there would be a nice thing to have. It would definitely be useful for some users. I just don't feel that it is absolutely necessary. The framework that is provided provides enough to get things working.

If, at optimization time, you actually find that there is a performance bottleneck when doing lookups, then you should optimize it. A binary search will likely be fast enough. If it isn't, then carefully constructed hash table should be plenty fast. If that isn't enough, then a user data pointer may be the only option.

Travis
Last edited by vitek on Tue Mar 04, 2008 7:34 pm, edited 1 time in total.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I don't have any strong opinion on that (I would just hack the engine if I need it). But if they are used then void data pointers should not be thought of as pointers, even when they are of type void*, but simply as custom number type which a user might abuse for pointers on his own risk (I think MFC even uses it's DWORD type for similar members). So the problems with destruction and serialization do not really matter.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

CuteAlien wrote:So the problems with destruction and serialization do not really matter.
Yeah, I can agree with that in some ways.

Unfortunately I feel that we need to consider the abilities of the users of the library and the functionality that is already offered. Irrlicht users aren't necessarily C++ gurus, and Irrlicht already offers functionality that allows them to shoot themselves in the foot if the user data is not managed.

Travis
Post Reply