Archives for: May 2007


Editor Object Abstraction

Permalink 06:15:29 am, Categories: World Editor  

Since my last post, I realized how important SCF is in Crystal Space and how it could help me implement the property editor, tools, scene browser, and asset browser in a way that remains extensible.

In my last post, I talked about how I will implement the property editor. I'll now talk about how to do the rest of the major parts.

When something in the editor needs to know about what interfaces an object implements, it must query each possible SCF interface until it finds a match. When you have all of the CS interfaces, all of the CEL interfaces, and user-defined interfaces represented, there is a lot of querying going on.

Editor object diagram

Over the weekend, I spent some time to come up with a class EditorObject which abstracts each iBase* object in the editor. This class will keep a list of the interfaces which an object implements. Since I need to do a lot of SCF interface querying, and querying isn't particularly efficient, this cache should boost performance. More importantly, it provides an abstraction of an editor object--no matter what kind of interfaces the object implements, there should be a consistent way of getting/setting the name, parent, and getting the type (factory, instance, or other) and properties.

For each SCF interface, there will be an implementation of iInterfaceWrapperFactory. This will create instances of iInterfaceWrapper, only if the passed iBase* implements the particular interface which the iInterfaceWrapperFactory wraps (it determines this using QueryInterface). Each iInterfaceWrapper implementation will keep a pointer to the queried interface to carry out requests for the Name, Parent, Properties, etc.

Upon construction with an iBase* object, the EditorObject calls each registered iInterfaceWrapperFactory on the object, and stores the resulting iInterfaceWrappers in a list. It stores iInterfaceWrappers whose iInterfaceWrapperFactory::HasNameAttribute() and HasParentAttribute(), respectively, return true, separately, but in addition to the aforementioned list. It does this so it can provide constant time access to name and parent attributes. I can't think of a case at the moment in which one object has at least two interfaces which provide a Name attribute, but if this becomes a problem, certain interfaces could be given a higher priority than others. Even in this case, the other Name attribute can still be edited in the property editor.

How does the Scene Browser and Asset Browser know which objects to display? EditorObject asks each iInterfaceWrapperFactory for the type of the object implementing the interface. By type, I mean instance or factory. For those interfaces which do not help identify whether an object is an instance or a factory, they return unknown type. The EditorObject then stores the resulting type. Ideally, all interfaces return unknown, but one which returns either instance or factory. If there is a conflict where at least one interface says it is an instance type and at least one says it is a factory type, then the logical solution would be to set the resulting EditorObject type to unknown. In this case, both the Scene Browser and the Asset Browser could show it. This isn't as uncommon as it might sound, although I can't think of an example.

The Property Editor will also need to know about the properties from each interface. Here EditorObject will ask each interface for a list of properties. I still need to come up with a property representation which these GetProperties functions use. I don't think it would be a good idea to have the interface wrappers tied to wxPropertyGrid.

Instead of showing the interface name as the category in the property editor, there will be a name based on logical groupings of properties, like "Surface", for properties related to a surface. The idea is that there is a better grouping of properties for editing than the groupings dictated by the interfaces, which were designed to be good groupings for runtime. To implement this, each property will specifie under which category that property should be displayed. Ideally, these category names would be standardized. For the advanced user, the underlying interface name can be shown in the property description, and optionally, the properties could be grouped by interface.

Finally, Tools are interested in what interfaces an object has so that they can determine whether they are available. They can use EditorObject::HasInterface to query for interfaces using cached results.

On a more practical note...
My mentor kindly created a branch for me in
I've gotten both wxAUI and wxPropertyGrid samples to compile from within the CSExtra source tree, by including wxPropertyGrid sources in the tree and assuming wxAUI is built into wxWidgets. I should require wxWidgets 2.8+ since only that has wxAUI, but I haven't messed with the standard configure check yet. A more elegant way would be to make an additional check for wxAUI. In the case that it isn't present, I could have the PanelManager use some sort of static layout with splitters, but this isn't a priority.

In my next post, I'll talk a bit about registering objects with the editor and selections.

I hope to really iron out the design during this week so I can get a good start on the code. I'll try to come up with a schedule tomorrow. Signing out.


Class Diagram and some Q&A with myself

Permalink 03:33:13 am, Categories: World Editor  

Now that exams are over, I can start the real work on the CS editor.

I decided to start off by trying to make a class diagram of the editor. This allows me visualize the system and locate problem areas in the design.

Class Diagram

There are a few issues that I've identified right now:

  1. What type do I use for the selections?

    Since I'm allowing heterogeneous selections, I need an array which can hold basically any CS engine object, including factories. I'm thinking a csWeakRefArray of iBase will work. It should use weak references since, we don't want to keep objects around if they deleted. Perhaps I need to call csWeakRefArray::Compact() before any function dealing with the selection, so I don't need to deal with invalid objects.

  2. How do I get the property editor for the selected objects?

    Each SCF interface will have its own property category, and each of these categories will be registered with the main property editor. To display the appropriate property editor for the selection, for each object, I should query each possible SCF interface until I find a match. The downside of this is that it has to test each and every interface for each object.

    Something like:

    class MeshWrapperPropertyCategory {
      // Pretty name for the category
      const char* GetCategory() {
        return "Mesh Wrapper";
      bool AddToEditor(iBase* obj, PropertyEditor* propEditor) {
        iMeshWrapper* mesh = scfQueryInterface<iMeshWrapper>(obj);
        if (!mesh) return false;
        // ...
        // Add properties to propEditor.
        // These will also setup property change handlers which will call the interface's functions.
        // ...
        return true;
      // Property change handlers go here.

    This should allow you to edit objects of different types as long as they share some common SCF interface. The property editor will only show the interfaces in common. This will also reduce the amount of querying being done, since if the first object doesn't have interface X, we don't have to check if the next object has it.

  3. How do I register the tools with the toolbox?

    When a tool will registers itself with the tool manager, the tool manager should publish a ToolAdded event to its listeners. Among the listeners will be the ToolboxPanel. This should solve that.

  4. How to draw special stuff like the selection, manipulators for the move, rotate, and scale tools, or billboard icons for lights so you can select them visually?

    These should be handled in different classes.

    The CS view should draw the selection bounding box and the billboards for lights.
    The move, rotate, and scale tools should draw the manipulators.

  5. Where to use SCF interfaces in the code?

    I think one of the annoyances of CStudio was that everything was an interface and you had to put up with a lot of SCF boilerplate and interface querying to do anything. That said, I think that parts of the editor which are meant to be implemented by plugins should use SCF so that I can leave the dirty work of plugin loading to SCF. So, you'll probably end up seeing iTool, iPanel, and iAction. I'll have to read up more on SCF and talk to my mentor to make sure this is what I want.

Still, the diagram is missing some detail, e.g. tool and property category registration, various events/listeners, settings manager, and many tools/actions are not shown.

I will try to come up with a more complete diagram tomorrow and then I'll try to sort out any further difficulties. Hopefully I can get my hands on some code soon. In the meantime, to entertain my thirst for action rather than abstract thinking, I will try to set up the build system to work with wxAUI and wxPropertyGrid.

May 2007
Mon Tue Wed Thu Fri Sat Sun
 << < Current> >>
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      





XML Feeds

What is this?

powered by