No screenshots today, sorry.
There are a few problems with the current iEditorObject abstraction which I've come across so far. I'll deal with them each and try to come up with a solution.
1. The wxTreeCtrl requires that each element you add specifies its parent. Without a function like GetChildren, I would have to make two passes, one to add them all and, one to reparent the nodes. This is unacceptable, so I'll add a GetChildren function to the interface. This function should return an iterator over iEditorObjects. I could provide the API by making iEditorObject derive from iObjectList. This makes some sense since it provides a consistent interface. Also I should note that since the child objects are wrapped, I need a way to get access to already-created objects. I could do this by keeping a hash of iBase mapped to iEditorObject, perhaps in iObjectList, so I could have say, iEditorObject* FindObject (iBase*).
2. There can be multiple names and multiple hierarchies for a particular editor object. Maybe I wasn't thinking too clearly about this, but the current interface means there's only one name and one parent per object. Right now, I've only got iObject wrapped. One use of iObject is to have custom objects attached to engine objects (for example, iMapNode), which the loader does for you if you make the world file a certain way. So that hierarchy will be represented. But what about say, the scene node hierarchy? Surely both hierarchies are useful to know about.
The scene browser could show different views depending on which kind of names or which hierarchy you'd like to see.
3. There is a reliance on the SCF metadata, which determines which interfaces a given instance implements. The problem with this is that it is dependent on the implementation. Often, an interface will provide a QueryObject() to get iObject*, but that same class need not inherit from csObject. So when the map load listeners add their objects, they just have to hope that the object is implemented like that. And that won't always be the case. When I came up with the design, I was thinking that I would just have a mess of objects and have to figure out what interfaces each of them had. But that's not the case, since I must get each individual object from a separate source and add it to the editor, it makes sense that the code that's creating the iEditorObject knows more about the object than some SCF metadata might glean. So, it seems it's not such a great idea to rely on this SCF stuff. I'm thinking about another way to do it, where the thing adding the object to the editor tells it what interfaces it should know about.
A nice thing about making the iEditorObject an interface is that you can make an implementation such that it doesn't have to wrap an iBase object, but it could wrap your own object. It could be anything you want. This isn't the way it is currently though, since it exposes a GetIBase function. This function was made available so that a tool might query for a particular interface to perform its work. I think this can be replaced with a QueryInterface () function which gives access to the specified interface. The reasoning behind this is that iEditorObject's can be composed of interfaces rather than have only one object which inherits all of the interfaces. This way if you have a custom object that you want the editor to know about and you aren't using SCF, you can just implement say iMovable which works with your object, return that for QueryInterface<iMovable>(), and the Transform tools will work appropriately. It would seem that some sort of "capability" interface would be more appropriate, e.g. iTransformable, for objects able to be transformed with the transform tool. But I don't want to duplicate the CS API. Therefore, iTransformable would probably only have a member like iMovable* GetMovable(). This is just brainstorming right now, as I haven't gotten to the tools implementation yet. But it seems like it is the direction I'm heading.
I still am not completely confident with these solutions. But I will take a shot at implementing them and see how that goes. Luckily, the code is revision-controlled, so I can always refer to previous versions.
|<< <||> >>|