Basic Architecture #

Data storage

OpenGL includes the concept of vertex arrays. The idea is that instead of calling glVertex3f (and it's cousins) everytime a polygon is defined, you create a list of vertices (which can be stored in the 3D accelerator card for optimal perfomance) and then when displaying polygons, you simply make references to positions within that list. Parallel lists can be maintained for surface normals, colors, etc. or they can be put in the same array, and a "skip" value can be used to jump from one set of coordinates to another.

What I'm currently considering is to store all of the vertices used in a model in a central location, and then each of the objects make references to that central vertex array. In this way, sharing vertices between different objects will be very easy. The model file would then start off with a big list of points, followed by the actual objects (e.g. in the case of polygons there would be an enumeration of vertex numbers to define the corners of the polygon). As far as I know, this is how games such as Marathon store the world levels (which is why with the level editor you first lay down the points, and then in a separate step connect them).

As an alternative, I can store the vertices (still within a vertex array) within each object. The main advantage of this would be that when deleting or inserting vertices, I wouldn't have to search for the objects which make use of the vertices whose positions are affected and have to adjust the indices appropriately. There might be some wasted space (since there might be duplicate vertices), but there can't be that much. I really can't think of too many situations where you would want different objects to share a vertex (e.g. for a sphere's center to be attached to a corner of a polygon). For things such as triangle meshes, each vertex array will encompass the entire mesh (as opposed to a single triangle) so the big savings are still there. Actually, for things like spheres (which only need a single point and a scalar to be defined) there's no point in using vertex arrays. The only problem which I foresee is if there can be a limited number of distinct vertex arrays be loaded in memory at the same time. I don't mean limitations due to not enough memory, I mean limitations caused by OpenGL's implementation (similarly how some 3D accelerator cards can only handle 8 lights at a time). If that's the case, I'll have to implement an architecture which keeps track of the vertex arrays as they are loaded, and disposes of the least used one (or the one used the longest ago) if a new one is to be loaded but there isn't enough space.

Heh, looks like I totally eliminated the first choice. Well, this isn't quite the IB dossier write-up yet, so I can ramble on.

Classes

I'll be needing a base Object3D class which will a stub-like thing (that is, it'll never be used directly in the application, rather I'll be using classes which use Object3D as a base). It'll have basic fields (and the appropriate functions to set them, I'll try to have as little public variable as possible, and instead rely on accessor functions) for position, rotation. There'll be virtual functions for loading, displaying, scaling, etc.

For object identification, I plan to have both a name field, and a four letter code (which translates into a nice long) which shows the object type. Then the loading function could look at the four letter code in the file, and create the appropriate instace of the class and call it's loading function (which is virtual, remember).

First of all, I said "the appropriate instance" above. As implied by the fact that Object3D is a base class, I'll be having other classes layer on top of it. There'll be simple ones like Sphere3D, Cone3D, Cube3D, etc. and more complicated ones like Mesh3D. Since they share a base class, the rendering loop can treat them all like Object3Ds and call the display function. Things might get a little bit more complicated with the user interaction, but it's the same idea.

I want the program to be as flexible as possible. Ideally, if I wanted to add a new object type, I shouldn't have to chase down all of the case statements which involve the four letter object codes and add the new one. A plug-in architecture is overkill, but I can implement an way to "register" new object class types. Basically, there's a central "hub" which stores pointers to "mini hubs" for each object type. These "mini hubs" would share a base class which has a virtual function to create a new instace. The "mini hub" class is only a few lines really, since all it has is a "return new ". Perhaps it could also be done as a static function in the actual object class. In any case, all that would be required to add a new object type (once the class has been written) would be to "register" it with the "hub" (e.g. ObjectHub.Register('Cube', &CubeHub); or perhaps ObjectHub.Register('Cube', Cube3D::Instantiator)). Then, while reading the file, the main function would look up the four letter code, if it finds a function pointer then it calls it and assigns the value to an Object3D class pointer (in reality the class is of a specific, high level type, but the function doesn't care which one, as long as it can call the loading function, etc. which are virtual).

I'm not sure if the above is totally coherent. In any case, as far as I can tell (from what I've just been told) the process I'm describing is the factory method (as described in Design Patterns : Elements of Reusable Object-Oriented Software (I have this book, but I haven't really used it) and other places). My plan is to implement the architecture as best I can, and then read the relevant chapter(s) in the book. Then I can 1. make much better sense of what they're trying to say and 2. say to myself "that's how I should have done it."

Post a Comment