OpenGL Graphics manager almost there

 

The OpenGL Graphics Manager is now usable 😀 It displays games well, and has all the features that the SDL Graphics Manager has (but all the scalers filters), and includes some new features like windows resizing to any size.

It is now able to use GL_NEAREST and GL_LINEAR as filters for scaling the textures. You can switch filter modes with Ctrl-Alt-F hotkey. That is not a great variety of filters, compared to the scalers that uses the SDL Graphics Manager, but they should be hardware accelerated rather than software processed.

It is now able to use GL_NEAREST and GL_LINEAR as filters for scaling the textures. You can switch filter modes with Ctrl-Alt-F hotkey. That is not a great variety of filters, compared to the scalers that uses the SDL Graphics Manager, but they should be hardware accelerated rather than software processed.

I also changed the overlay pixel format to RGBA5551 insteand of a RGBA4444, allowing a better color display. I had some problems working with the alpha channel of the overlay, because OpenGL doesn’t include any function for blitting into a texture when updating it. Also, the SDL Graphics Manger uses a RGB565 format for the overlay, but thanks to its dirty rect system it doesn’t need to use and alpha channel, as it only draws the modified overlay areas. However, I don’t make use of a extensive dirty rect system on OpenGL, so I need to use an alpha channel.

So after some work I finaly decided to nulify the alpha bit from the pixels buffer when updating the texture, and it is working now almost exactly as the SDL Graphics Manager does. The only difference is that it has a bit less for green colors in favor for a bit for alpha.

One of the major changes was redesigning the blitting system. Previously I had a copy of the texture data on each GLTexture, and when updating the texture I also updated the extra data. Then I could use this data for recreating the textures after an OpenGL context change or a filter change. However, functions like lockScreen() and grabOverlay() have to return the original pixel data from that texture, but the copy I had wasn’t the original data, as in most cases it was already converted from a palette format to a RGB/RGBA format. So I decided to remove this extra data from GLTexture, and add inteand some new variables on the graphics manager that would save the original pixel data. Now, when updating the screen or the overlay, the pixel data is saved on those variables, and the a dirty rect is extended with the modified area. When updating the screen the pixel data in its original format is converted to the OpenGL texture format in case they have paletted/clut8 format and the OpenGL texture is updated. For RGBA8888, RGBA5551 and other common RGB/A formats there is no conversion needed, OpenGL will do it already for us.

The other major change is the aspect ratio feature. Its mode can be switched with Ctrl-Alt-A, and it will loop through all aspect ratio modes. The default, aka “Normal”, mode will not conserve the aspect ratio when resizing the screen, it will just stretch the contents to the screen size. The “Conserve” mode, will mantain the current aspect ratio in use. And the “4/3″, “16/9″, and “16/10″ modes will stretch the contents to that size. When resizing the window, or using a fullscreen mode that doesn’t have the current aspect ratio in use, only one dimension of the screen contents will be stretched to the window size, and the other will not fill all the window size. So black stripes will wrap the contents and the aspect ratio will be mantained.

Another addition is Ctrl-Alt-Enter. While Alt-Enter will enter fullscreen with the best available mode (and exit it if already in fullscreen), Ctrl-Alt-Enter will loop through all available fullscreen modes. This enables the user to select what fullscreen mode to use.

Other minor implementations:

  • OSD messages, pretty much like the SDL Graphics Manager style
  • Ctrl-S will save now a bmp screenshot of the current screen
  • Screen shake effect is working

Still, I need to complete some more things before finishing with the OpenGL Graphics Manager:

  • Add options for switching between OpenGL manager and SDL manager
  • Porting to OpenGL ES and testing, most OpenGL code should work for GLES, still I need some testing
  • Code cleanup and documentation

 

OpenGL Advances

SDL/OpenGL Graphics Manager in action

I have advanced in many things this week. And the OpenGL Graphics Manager can now display the ScummVM start menu (There are still some little issues to fix).

I started the week merging from trunk, so I can make sure that my changes are fully compatible with the actual development. But, I had to merge manually some files, and also to revise all merged code (There were some merging errors, and ton of conflicts).

I also fixed lots of errors on the GL manager, there were lots of segfaults thanks to bad memory allocation, I was reserving less than I should, and some problems with non power of two textures.

x2 Scale Factor

Now, the Overlay and Cursor are working. The overlay was simpler to implement, as it uses a 16 bit rgba pixel format, but the cursor was complicated because it is needed to convert the cursor from a paletted surface to a rgba one, because OpenGL does not support nicely paletted textures.

I have worked too on scaling and resizing the ScummVM window. With OpenGL a texture scaling is pretty easy, though it can complicate because resizing the window causes problems with the OpenGL context, and I also had some hard time for adjusting the mouse coordinates to the current scaling.

Resized x1 Window

After many tries, and fixes, now the graphics manager supports x1, x2, and x3 scale factors (Hotkeys: Ctrl+Alt+(Plus/Minus)), which will resize the overlay size, and it also supports the window to be resized from the borders to any size. Resizing from the borders won’t modify the overlay or game screen size, so it they will be stretched to fit into the window.

However, I still need to implement a feature for maintaining the aspect ratio while resizing the window, so black borders will be added around the screen instead of breaking the aspect ratio.

Finally, I implemented fullscreen support. Had some bad time debugging it, because thanks to some segfaults raising when ScummVM was in fullscreen, not allowing me to change to Visual Studio. Still, I could find the problem revising the code, and now fullscreen works well. But, I need to do a better testing of fullscreen and also scaling on linux, I have made most tests on a virtual machine and the virtual machine does not handle OpenGL and fullscreen well.

My plan for this week is to implement aspect ratio support and game screen drawing. This 2 things are the last biggest things I need to work on, and only some small functions, documentation and some code cleanup will be left.

Status Report

I have created a new class “OpenGLSDLGraphicsManager”, which is a subclass from the OpenGLGraphicsManager. This way, I will not mix SDL code, and so allow other backends to make use from the OpenGLGraphicsManager.

I had some problems with how the OpenGLSDLGraphicsManager and the SDLGraphicsManager worked with the SDL backend. I need that both managers be able to work with the SDL backend and that implies that they need to be able to work along with the other SDL managers.

The problem is that the SDL event manager needs to get access to some intern data and call some functions from the graphics manager. So, I need to have some extra public functions declared in the SDL graphics managers that are not the ones called from OSystem.

For allowing the SDL event manager to call these functions, my first approach was to create an abstract “BaseSdlGraphicsManager”, which would be parent from SdlGraphicsManager and OpenGLGraphicsManager. However, this would lead to class ambiguity and a inheritance diamond problem. Not something really nice.

Finaly, I decided to move those functions to the virtual GraphicsManager class. This will polute a bit the GraphicsManager, as some other backends may not need to use those functions. However, any other way for resolving this would be much more complex and would not be really worth the problem.

Another solution, could have been to move those functions to OSystem_SDL, and include in each one a condition like:

1 if (_graphicsManagerType == kOpenGL) {
2  ((OpenGLSDLGraphicsManager  *)_graphicsManager)->callFunction(arg1, arg2, ...);
3 } else if (_graphicsManagerType == kSDL) {
4  ((SDLGraphicsManager  *)_graphicsManager)->callFunction(arg1, arg2, ...);
5
6 }

But that is not very elegant…

Also, I implemented the PixelFormat related functions, and changed how the GLTexture class manages the pixel format. Now GLTexture setups its pixel format from the constructor insteand of having multiple classes for each format.

And, after implementing the GFX functions, at last I could make a blank opengl screen to pop up in my screen. Still nothing is blitted into the screen, but that will be the next step 🙂

So, for this week, I plan to implement the drawing to the screen. That will be the main task, but I plan to do some cleanup and improve the actual code as well (It is a bit messy in some parts)

Unexpected Problems

Last Wednesday, I had some problems with partitions from my hard drive 🙁

The system partition would not be recognized, so I could not boot the pc, and it seems that when I tried to fix it I damaged it harder…

But now I am back with a reformatted disk. I lost some data, but at least I could backup some of my files before reformatting. Well, now I shall continue with the project.

Second Milestone Completed

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

SdlTimerManager

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.

SdlAudioCDManager

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 🙂

SdlMixerManager

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.

SdlGraphicsManager

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.

SdlEventManager

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.

SdlMutexManager

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.

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.

Alejandro