Engine

From DaphneWiki

Revision as of 03:13, 16 February 2014 by Matt (Talk | contribs)
Jump to: navigation, search

Contents

DAPHNE Engine

This information applies mostly to the unreleased Daphne v2.0 code base. I am making notes as I develop it. This info is subject to change.

Program Entry

Program entry must be implemented on a platform-specific basis. It can be something like a main() function which loops and calls Daphne functions or whatever you need it to be. In short, these daphne-specific functions must be called regardless of the platform:

  • daphne_init (parses command line and returns an instance of the IGenericLoop interface)
  • IGenericLoop->Go() (call this over and over again until get_quitflag() returns true; this value returns the number of milliseconds before calling Go() again; this value must be respected in order for Daphne to run at the proper speed)
  • daphne_shutdown (when get_quitflag() has returned true)

Platform-specific

Platform-specific code inherits from the IPlatform interface and lives in the src/platform folder. It is responsible for providing the following functions:

  • Platform input event handling (keyboard, mouse, joystick, any other abstract means of input)
  • Sound (providing a mechanism to stream PCM audio to audio device)
  • Video (can be as simple as providing platform initialization to OpenGL code to as complex as providing a complete video object)
  • Timing (millisecond precision)

Video

All video functionality is inherits from the IVideoObject interface. The IPlatform interface returns an instance of IVideoObject. So you can extend pre-written IVideoObject classes or write your own from scratch. Very flexible.

TODO: The IVideoObject interface needs to be split up into smaller interfaces because it currently tries to do too many things.

Sound

The IPlatform interface has a SoundInit method, one argument of which is AudioStreamCallback. Your platform specific code must call this callback regularly (when audio buffer needs to be filled) to grab PCM audio generated by Daphne's sound code. Daphne's sound code currently is hard-coded to generate audio at 44.1khz, 16-bit stereo.

Input

The platform-specific code is responsible for returning an implementation of the IGenericInput interface. As of right now, it appears it is safe for all platforms to just return an instance of GenericInput.

The platform-specific code must implement some event handler to call the IGenericInput methods input_enable, input_disable to indicate that input has come in. The platform-specific code may optionally also support mouse motion by capturing mouse events and then calling IGenericInput->OnMouseMotion. The platform-specific code may optionally also support keyboard events (to handle Thayer's Quest and SINGE games) by calling IGenericInput->key_enable and IGenericInput->key_disable.

Input Events

The IGenericInput interface provides the option for any code in Daphne to register to receive input events. This means that, for example, a game class could receive events when the user takes a screenshot even though game classes normally have no knowledge of this. The reason for this design is so that the IGenericInput interface doesn't know what it is sending events to (to reduce coupling). The events that are available for notification are: game input (joystick, button), keyboard input, mouse movement, screenshot/pausing of Daphne, when enabling/disabling the debug console.

Timers

Daphne has an IGenericLoop interface which is essentially the outer loop that runs over and over again until the program exits. The loop generates an event every 1 millisecond called a "Think" event which basically means that anything that receives this event can check every 1 ms to see if it has any work to do. Any part of the Daphne code can register to receive think events by calling IGenericLoop->RegisterThinkObserver. All game and ldp classes automatically register to receive these events (so if you write your own you will get these events without having to do any work).

In addition, IGenericLoop can optionally also generate vblank events (when vblank starts and stops). Call IGenericLoop->ToVBlankSubject and it will either return an IVBlankSubject interface instance or null. If it returns the former, you can call IVblankSubject->RegisterVBlankObserver to get vblank events. The reason these events are optional is because the Dexter side-project software does not support generating vblank events but Daphne does. All game and ldp classes automatically receive vblank events so if you write your own you will not have to do any extra work to get them.

Game Drivers

All game drivers must inherit from the 'game' base class.

CPUs should be set up in the game's init() method (see star rider driver for preferred method). Many of the game drivers currently set up CPUs and sound chips inside the game's constructor but this method is deprecated and discouraged. ROM paths may still be set up inside the constructor.

Most methods have defaults in the 'game' base class and do not need to be explicitly defined, but some of the methods you probably will need to define if you want the game driver to do anything useful:

  • init
  • cpu_mem_read
  • cpu_mem_write
  • input_enable
  • input_disable
  • OnVblankChanged

if using video overlay

  • palette_calculate
  • video_repaint

Video Overlay

If using video overlay, you must set the following variables:

  • m_game_uses_video_overlay = true;
  • m_video_overlay_width = [your game's video overlay width]
  • m_video_overlay_height = [your game's video overlay height]
  • m_palette_color_count = [your game's colors per palette, not to exceed 256]

It currently is required for each game to call video_blit manually, but I am going to change this Real Soon Now.

Personal tools