BuGLe object management

Introduction

This file documents the object layer in BuGLe. It is NOT an OOP layer to add C++-like features to C. So what is it? Well, OpenGL has a number of types of “object” — things like contexts, drawables, display lists, texture objects etc — and various bits of code in BuGLe want to associate data with these objects. The object layer makes this easier. It should be understood, however, that the object layer has no knowledge of OpenGL. It is up to you to track the OpenGL calls that manage objects and mirror them within the the object layer (some of this is done in the core code, particularly context and display list tracking).

The important concepts are:

class (bugle_object_class *)
A class is like an OOP class, in that objects are instanciations of classes with data
registrant
Several units of code may wish to attach storage to an object, and they need to be kept separate from each other. Each such unit is known as a registrant. There is no explicit structure to represent registrants.
object (void *)
An object holds all the data that all registrants have attached to a GL object. It should be treated as being opaque.
view (void *)
A view is a pointer to the data that a single registrant attached to a GL object. The interpretation of the data is up to the registrant.

The object system also has a concept of scope. This has nothing to do with inheritence. It refers to the scope at which an object can be considered to be current. For example, each thread has a current context, and each context may have a current display list. BuGLe allows you so specify what the current object for each class is (which may be NULL), and retrieve it later.

Class management functions

The class management functions are not thread-safe; any concurrent access to the same class should be protected with a mutex.

bugle_object_class_init(object_class *klass, object_class *parent)
Initialises the structures for a class. The parent field may be set to either NULL (in which case the scope of the class is the thread), or an existing class (in which case the scope is the parent class).
bugle_object_class_clear(object_class *klass)
Frees the structures for a class (although it does not delete any instances, which should be deleted first).
bugle_object_class_register(object_class *klass, void (*constructor)(const void *, void *), void (*destructor)(void *), size_t size)
Called by each registrant to request size bytes of storage within a class. The constructor is documented later; the destructor is simply given the view of the object, so that it can do cleanup (but it must not try to free the view itself). Both the constructor and destructor may be NULL. The size may be zero, if one only wants notification of object creation and destruction through the constructor and destructor. The return value is of type size_t, and acts as a handle in other calls.

Object management functions

The object management functions do not modify the object_class structures. Hence they are thread-safe, provided that they are not used concurrently with the class management functions. The exception is that if an object of class Ais current to more than one thread, then setting the current object of class B whose scope is inside that of class A, may not be thread-safe.

bugle_object_new(object_class *klass, const void *key, bool make_current)
Instantiate an instance of the given class. Firstly, if make_current is true then the new object is immediately made the current object of its class. Then, for each registrant the constructor is called to initialise the data in its view. The constructor is passed key and the view (the key parameter exists only to pass extra information to the constructor, usually about the associated GL object). Where no constructor is specified, the view is filled with zeros.
bugle_object_delete(object_class *klass, void *object)
For each registrant, calls the destructor (if any) with the view. It then frees the memory associated with the object. Don't forget that some GL objects don't actually die when you delete them, only when they are no longer referenced. Also be sure to pass an object, not a view.
bugle_object_get_data(object_class *klass, void *object, size_t handle)
Maps an object to the view for a particular registrant (given by the handle returned by bugle_object_class_register).

Setting and fetching the current object

bugle_object_get_current(const object_class *klass)
Returns the current object of the given class.
bugle_object_get_current_data(const object_class *klass, size_t handle)
A shortcut to combine bugle_object_get_current and bugle_object_get_data.
bugle_object_set_current(const object_class *klass, void *object)
Sets the current object of class klass to object.