I have finished the second milestone coding on my schedule, and would be good to explain what the refactoring changes are. Still some testing is needed for the refactored backends that I am not able to compile, but the main coding is complete.
For this milestone I have been working on refactoring the SDL backend, and also its sub backends, including the ports for GP2X and GP2XWIZ, LINUXMOTO, Samsung TV, Symbian, and of course the Windows, Mac OS X and POSIX based OS.
My first step for refactoring the SDL backend was to organize the SDL code and functions into specialized Managers classes, which are namely: SdlTimerManager, SdlMutexManager, SdlMixerManager, SdlGraphicsManager, SdlEventManager, SdlAudioCDManager.
The OSystem functions are already divided into categories which make the job easier, and there were already some modular classes before I started working (Like DefaultTimerManager, AudioCDManager, FilesystemFactory, SaveFileManager and others). However, some SDL specific code and functions were a bit ambiguous and took a bit more to decide how to deal with the code, as they were used by the graphics code and the events code. In most cases I just opted to create some extra public functions on the SDL Managers, so the other managers can call that code or get some data.
I will explain now a bit about each new manager in particular
The SdlTimerManager was a simply class to implement. It subclass from DefaultTimerManager, and what I only needed to do was to setup the SDL timer callback and invoke the callback handle from the parent class.
There was a bit of discussion when I added to the manager the getMillis, delayMillis and getTimeAndDate functions. I added them to the timer manager thinking on the manager as a “Time” related manager, but after some feedback from Fingolfin, I realized that the purpose of the Timer Manager was indeed only related to “Timers” and no “Time” in general. After that, I just moved them back to OSystem_SDL.
This class inhereits from DefaultAudioCDManager, which was initialy called AudioCDManager and was declared as a singleton class. I removed its singleton status, having to subclass a singleton class is painful and bad for health. And so, I renamed the AudioCDManager to DefaultAudioCDManager, and created a pure abstract class “AudioCDManager” (Not to confuss :P) as base for the DefaultAudioCDManager.
The functionality of the DefaultAudioCDManager is practically the same as before, it emulates the cd playback trying to read the sound files from the local folder, and if it fails makes a try, and call the real cd playback functions. Those real cd functions were previously on OSystem, but I moved them to the AudioCDManager insteand.
This last move, allows that a subclass from DefaultAudioCDManager be able to easily implement the real cd functions when overriding.
One other major change, appart from moving some OSystem functions, was to redirect all calls to the singleton instance of the manager to g_system->getAudioCDManager()->function(). Not really tough, a CTRL+SHIFT+H did most of the work 🙂
The mixer manager was a bit more complicated. There was already an Audio::MixerImpl class being used, but there was many SDL mixer related functions on the OSystem_SDL class. My first thought, was to use the same approach I have been using with other managers, like the SdlTimerManager or the SdlEventManager, and I subclassed the Audio::MixerImpl with the SdlMixerImpl class (Named this way for consistency with MixerImpl).
But having things this way created a big incovenient. The Audio::MixerImpl has the audio sample rate saved in a constant variable that is initialized taking the value from an argument from its constructor. Having things this way, leaved 2 ways open, or making the sample rate variable not constant (something not really good), or making a kinda hackish way for getting and passing the sample rate at the contructor list.
Seeing both options weren’t really good, Fingolfin suggested me to have the SdlMixerManager wrap the Audio::MixerImpl insteand of inhereiting from it. So, I moved this way, and all went well.
I also created a new class, DoubleBufferSDLMixerManager, for the double buffering playback, needed for Mac OS X and GP2X platforms. This class inhereits from the SdlMixerManager, and changes a bit how the audio callback is handled.
And finaly, there is also a SymbianSdlMixerManager subclassing the SdlMixerManager. Symbian port needs to downmix the sound buffer if there is no stereo support.
The biggest manager and the most complex one. There are many graphics related functions, and took some time to revise all code. I created a new abstract class as base for it, called GraphicsManager and a NullGraphicsManager for the null backend.
There did not arise many problems, some thought was needed for deciding what to do with variables shared by both events code and graphics code, for which I ended creating and making public some functions.
This class has also many subclasses for different ports, Symbian, GP2X, GP2XWIZ and Linuxmoto. Most changes needed because low resolutions and being unable to support scalers or some other features.
The events manager subclass from the DefaultEventManager, which handles the engine related events. The SdlEventManager insteand handles the backend related events, but it also implements the real code to poll the events that the platform sends.
The way this works now is a bit “tricky”. Engines can get the event manager from OSystem, g_system->getEventManager() and update the events queue calling the pollEvent() function. However, when constructing, the SdlEventManager passes the OSystem class to the DefaultEventManager as a EventSource. This makes the DefaultEventManager to call pollEvents() from OSystem, but OSystem_SDL calls to pollSdlEvents from its sdl event manager. Before, the actual pollSdlEvents() was directly on OSystem_SDL, just that now is on the sdl events manager. The call stack is kind of recursive, but it isn’t that bad.
The SdlEventManager has some backend specific subclass also, for GP2X (And GP2XWiz also), Linuxmoto and Samsung TV. Most of the functions overrides are for remapping some joystick or buttons from the handheld devices.
The mutex manager is the tyniest manager, only 4 functions. It inhereits from the abstract class MutexManager I created for it, and the SDL code was practically copy pasted from the OSystem_SDL.
On the other hand, the OSystem_SDL class, aka the SDL backend inhereits from the ModularBackend class, designed for the first milestone. Most of the calls to the Managers functions are made in the ModularBackend, so now OSystem_SDL needs to implement only some few functions, that include general functions (like initBackend()) and other misc functions that can’t be in a manager.
And, I have also created 3 subclasses for the SDL backend. OSystem_Win32, for Windows. OSystem_POSIX, for unix systems. And OSystem_MacOSX, which inhereits from the posix class. This way things are a bit more organized, and there are some less #ifdefs definitions in middle of the code that make it harder to read.
Well, that is all for now, I will start working on the OpenGL implementation from now on. My bad I am 6 days late, I should have started last moday…
However, the week I had reserved for the OpenGL ES implementation can be fused with the other OpenGL weeks in the schedule, as it is more like OpenGL ES testing rather than implementing new features.