Tuesday 3 June 2008

Events & Graphics in ScummVM

After my initial research into the virtual keyboard implementation on the PSP port, I thought it was time to start working out how my generalised virtual keyboard would be implemented. This involved me looking further into ScummVM's event management system, working out how the graphics would be displayed, and thinking about how it will all fit together.

Event Management

I had already discovered that each OSystem had a pollEvent() function that assigned the state of the system's input device to an Event object. But I needed to extend my knowledge, working out how the game engine came into it. To do this I chose to look at the source code of the Scumm engine. In the main loop of the Scumm engine - ScummEngine::go() - two important things occurred on each iteration:
  • waitForTimer() is called to limit scumm update
  • the scummLoop() is called to update engine
waitForTimer() basically just pauses the thread for a specified time, but as user input may occur in this time it has to handle it. So:
  • waitForTimer() calls parseEvents() every 10 ms.
  • parseEvents() calls EventManager::pollEvent() in a loop until it returns false (ie. no more events)
  • EventManager::pollEvent() just calls OSystem::pollEvent() and also adds record/playback functionality, as well as key repeat functionality
  • for each event returned by the EventManager, parseEvents() sets up engine-specific input state variables
Then from within scummLoop(), processInput() is called. This function sets up the mouseAndKeyboardStat variable which is used by the Verbs part of the engine to execute scripts. So, as the EventManager already handles special input events it makes sense for this class to be responsible for feeding virtual keyboard events back to the game engine. I envisage the EventManager::pollEvent() method including code like this:
result = virtualKbd->pollEvent(event); if (!result) result = system->pollEvent(event);

Graphical display

In Eugene's ideas for the virtual keyboard he had recommended that the virtual keyboard should live in the same 16-bit surface as the GUI. This made sense to me, as it should not be mixed up with the game graphics, but I did not really have a proper grasp of how the graphical layers of ScummVM were organised. Therefore I looked at the OSystem interface, and found out that graphics in ScummVM were implemented in three layers: game, overlay and mouse, and it was the backends job to draw these layers to its screen in that order. The OSystem interface provided a method for each of these layers that copies (or blits) a given bitmap into the layer. So for my virtual keyboard implementation I would have to call the OSystem::copyRectToOverlay() function in order to copy the keyboard's bitmap into the overlay. If I were to implement some sort of roll-over or keypress effects then that would involve additional calls to this function to update the key concerned.

GUI loop

While investigating the way overlay graphics are done, I looked through a lot of the existing ScummVM GUI code. As well as looking at the graphics stuff, I also had a look at how the GUI main loop is carried out. This main loop basically allowed the GUI to process all the user input until all dialogs were closed. It made sense for my virtual keyboard to use a similar method as Eugene's notes said that it was safe to assume the game engine would be paused when the keyboard was active. What this meant was that while the virtual keyboard was active it would process the mouse clicks, and build up a list of virtual key pressed events. Then once the virtual keyboard is inactive, it will deliver these events to the EventManager via its pollEvent() method (see the code fragment above).

Conclusions

My plans for the virtual keyboard are coming together well. The main concern I have at the moment is whether my assumption of having a separate virtual keyboard class is a good one. I have considered these other approaches:
  • build functionality into base OSystem class - probably not a good idea because it may involve modifying existed back-end implementations.
  • implement as a GUI dialog - makes sense in that its use will be very similar to a GUI dialog. However, probably not a good idea to tie it to the existing GUI implementation, especially as it will use its own configuration files. Although separate from GUI there is nothing stopping us making the keyboard look consistent with the GUI theme.
The obvious next step is to start thinking about the various initialisation files that the virtual keyboard will need, this will include:
  • what extra information needs to be stored in the imagemap file?
  • how will this imagemap file be parsed - using an xml library (e.g. TinyXML) or by writing my own specialised code?
  • ini file - what information is needed in here?
If having rollover effects will be a good feature to include, I will also investigate some efficient way to do this.

No comments: