Some changes wrt to event recordings. Created EventStreamer class to deal

with all related event recording/loading stuff, since it really didn't
belong in either the EventHandler or Event classes.  Loading a previously
saved eventstream now loads the ROM state as well.  All that's left to
do (for basic functionality) is for the EventHandler to poll the
EventStreamer for events, and then pass them directly to the Event class.

Still TODO is decide on a GUI for all this, and what it means to 'interrupt'
an eventstream (should we just stop the load, delay processing of it,
lock out all user input until the stream is finished, etc).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@931 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2005-12-28 22:56:36 +00:00
parent c2e6893cd6
commit 1f426d245f
7 changed files with 302 additions and 197 deletions

View File

@ -13,16 +13,16 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Event.cxx,v 1.6 2005-12-17 01:23:07 stephena Exp $
// $Id: Event.cxx,v 1.7 2005-12-28 22:56:36 stephena Exp $
//============================================================================
#include "Event.hxx"
#include "Serializer.hxx"
#include "EventStreamer.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::Event()
Event::Event(EventStreamer* ev)
: myNumberOfTypes(Event::LastType),
myEventRecordFlag(false)
myEventStreamer(ev)
{
// Set all of the events to 0 / false to start with
clear();
@ -31,7 +31,6 @@ Event::Event()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::~Event()
{
myEventHistory.clear();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -46,55 +45,13 @@ void Event::set(Type type, Int32 value)
myValues[type] = value;
// Add to history if we're in recording mode
if(myEventRecordFlag)
{
myEventHistory.push_back(type);
myEventHistory.push_back(value);
}
if(myEventStreamer->isRecording())
myEventStreamer->addEvent(type, value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Event::clear()
{
for(int i = 0; i < myNumberOfTypes; ++i)
{
myValues[i] = 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Event::record(bool enable)
{
if(myEventRecordFlag == enable)
return;
else
myEventRecordFlag = enable;
if(myEventRecordFlag)
myEventHistory.clear();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Event::nextFrame()
{
if(myEventRecordFlag)
{
int idx = myEventHistory.size() - 1;
if(idx >= 0 && myEventHistory[idx] < 0)
--myEventHistory[idx];
else
myEventHistory.push_back(-1);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Event::save(Serializer& out)
{
int size = myEventHistory.size();
out.putString("EventStream");
out.putInt(size);
for(int i = 0; i < size; ++i)
out.putInt(myEventHistory[i]);
return true;
}

View File

@ -13,21 +13,20 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Event.hxx,v 1.17 2005-12-17 22:48:24 stephena Exp $
// $Id: Event.hxx,v 1.18 2005-12-28 22:56:36 stephena Exp $
//============================================================================
#ifndef EVENT_HXX
#define EVENT_HXX
class Event;
class Serializer;
#include "Array.hxx"
#include "bspf.hxx"
class Event;
class EventStreamer;
/**
@author Bradford W. Mott
@version $Id: Event.hxx,v 1.17 2005-12-17 22:48:24 stephena Exp $
@version $Id: Event.hxx,v 1.18 2005-12-28 22:56:36 stephena Exp $
*/
class Event
{
@ -85,9 +84,9 @@ class Event
public:
/**
Create a new event object
Create a new event object and use the given eventstreamer
*/
Event();
Event(EventStreamer* ev);
/**
Destructor
@ -110,31 +109,6 @@ class Event
*/
virtual void clear();
/**
Start/stop recording events to the event history
@param enable Start or stop recording
*/
virtual void record(bool enable);
/**
Indicate that a new frame has been processed
*/
virtual void nextFrame();
/**
Answers if we're in recording mode
*/
virtual bool isRecording() { return myEventRecordFlag; }
/**
Saves the current event history to the given Serializer
@param out The serializer device to save to.
@return The result of the save. True on success, false on failure.
*/
virtual bool save(Serializer& out);
protected:
// Number of event types there are
const Int32 myNumberOfTypes;
@ -142,11 +116,8 @@ class Event
// Array of values associated with each event type
Int32 myValues[LastType];
// Indicates if we're in recording mode
bool myEventRecordFlag;
// Stores the history/record of all events that have been set
IntArray myEventHistory;
// The eventstreamer to record events to
EventStreamer* myEventStreamer;
};
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.cxx,v 1.134 2005-12-24 22:09:36 stephena Exp $
// $Id: EventHandler.cxx,v 1.135 2005-12-28 22:56:36 stephena Exp $
//============================================================================
#include <sstream>
@ -21,6 +21,7 @@
#include "Event.hxx"
#include "EventHandler.hxx"
#include "EventStreamer.hxx"
#include "FSNode.hxx"
#include "Settings.hxx"
#include "System.hxx"
@ -59,24 +60,27 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandler::EventHandler(OSystem* osystem)
: myOSystem(osystem),
myState(S_NONE),
myEvent(NULL),
myEventStreamer(NULL),
myOverlay(NULL),
myState(S_NONE),
myLSState(0),
myPauseFlag(false),
myQuitFlag(false),
myGrabMouseFlag(false),
myUseLauncherFlag(false),
myEmulateMouseFlag(false),
myPaddleMode(0),
myMouseMove(3)
myPaddleMode(0)
{
int i, j;
// Add this eventhandler object to the OSystem
myOSystem->attach(this);
// Create the streamer used for accessing eventstreams/recordings
myEventStreamer = new EventStreamer(myOSystem);
// Create the event object which will be used for this handler
myEvent = new Event();
myEvent = new Event(myEventStreamer);
// Erase the key mapping array
for(i = 0; i < SDLK_LAST; ++i)
@ -121,7 +125,6 @@ EventHandler::EventHandler(OSystem* osystem)
setActionMappings();
myGrabMouseFlag = myOSystem->settings().getBool("grabmouse");
myEmulateMouseFlag = myOSystem->settings().getBool("joymouse");
setPaddleMode(myOSystem->settings().getInt("paddle"), false);
@ -131,10 +134,8 @@ EventHandler::EventHandler(OSystem* osystem)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventHandler::~EventHandler()
{
stopRecording();
if(myEvent)
delete myEvent;
delete myEventStreamer;
#ifdef JOYSTICK_SUPPORT
if(SDL_WasInit(SDL_INIT_JOYSTICK) & SDL_INIT_JOYSTICK)
@ -148,12 +149,6 @@ EventHandler::~EventHandler()
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event* EventHandler::event()
{
return myEvent;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::reset(State state)
{
@ -445,6 +440,27 @@ void EventHandler::poll(uInt32 time)
case SDLK_s: // Alt-s merges properties into user properties (user.pro)
saveProperties();
break;
// FIXME - these will be removed when a UI is added for event recording
case SDLK_e: // Alt-e starts/stops event recording
if(myEventStreamer->isRecording())
{
if(myEventStreamer->stopRecording())
myOSystem->frameBuffer().showMessage("Recording stopped");
}
else
{
if(myEventStreamer->startRecording())
myOSystem->frameBuffer().showMessage("Recording started");
else
myOSystem->frameBuffer().showMessage("Error opening eventstream");
}
break;
case SDLK_l: // Alt-l loads a recording
myEventStreamer->loadRecording();
break;
////////////////////////////////////////////////////////////////////////
}
}
}
@ -520,18 +536,6 @@ void EventHandler::poll(uInt32 time)
myOSystem->createConsole();
break;
// FIXME - these will be removed when a UI is added for event recording
case SDLK_e: // Ctrl-e starts/stops event recording
if(myEvent->isRecording())
stopRecording();
else
startRecording();
break;
case SDLK_l: // Ctrl-l loads a recording
loadRecording();
break;
////////////////////////////////////////////////////////////////////////
case SDLK_END: // Ctrl-End increases Width
myOSystem->console().changeWidth(1);
break;
@ -772,9 +776,9 @@ void EventHandler::poll(uInt32 time)
cheats[i]->evaluate();
#endif
// Tell the event object that another frame has finished
// Tell the eventstreamer that another frame has finished
// This is used for event recording
myEvent->nextFrame();
myEventStreamer->nextFrame();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1677,49 +1681,6 @@ void EventHandler::takeSnapshot()
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::startRecording()
{
if(myEvent->isRecording())
return;
string eventfile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp";
if(!myEventStream.open(eventfile))
{
myOSystem->frameBuffer().showMessage("Error opening eventstream");
return;
}
// And save the current state to it
string md5 = myOSystem->console().properties().get("Cartridge.MD5");
myOSystem->console().system().saveState(md5, myEventStream);
myEvent->record(true);
myOSystem->frameBuffer().showMessage("Recording started");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::stopRecording()
{
if(!myEvent->isRecording())
return;
// Append the event history to the eventstream
myEvent->save(myEventStream);
// And reset the state
myEvent->record(false);
myOSystem->frameBuffer().showMessage("Recording stopped");
myEventStream.close();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::loadRecording()
{
cerr << "load recording!\n";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventHandler::setPaddleMode(int num, bool showmessage)
{

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventHandler.hxx,v 1.69 2005-12-24 22:09:36 stephena Exp $
// $Id: EventHandler.hxx,v 1.70 2005-12-28 22:56:36 stephena Exp $
//============================================================================
#ifndef EVENTHANDLER_HXX
@ -32,6 +32,7 @@ class Console;
class OSystem;
class DialogContainer;
class EventMappingWidget;
class EventStreamer;
enum MouseButton {
EVENT_LBUTTONDOWN,
@ -100,7 +101,7 @@ struct JoyMouse {
mapping can take place.
@author Stephen Anthony
@version $Id: EventHandler.hxx,v 1.69 2005-12-24 22:09:36 stephena Exp $
@version $Id: EventHandler.hxx,v 1.70 2005-12-28 22:56:36 stephena Exp $
*/
class EventHandler
{
@ -125,7 +126,7 @@ class EventHandler
@return The event object
*/
Event* event();
Event* event() { return myEvent; }
/**
Set up any joysticks on the system. This must be called *after* the
@ -239,21 +240,6 @@ class EventHandler
*/
void loadState(int state);
/**
Start recording event-stream to disk
*/
void startRecording();
/**
Stop recording event-stream
*/
void stopRecording();
/**
Load recorded event-stream into the system
*/
void loadRecording();
/**
Sets the mouse to act as paddle 'num'
@ -403,6 +389,15 @@ class EventHandler
// Global OSystem object
OSystem* myOSystem;
// Global Event object
Event* myEvent;
// The EventStreamer to use for loading/saving eventstreams
EventStreamer* myEventStreamer;
// Indicates current overlay object
DialogContainer* myOverlay;
// Array of key events, indexed by SDLKey
Event::Type myKeyTable[SDLK_LAST];
@ -427,15 +422,6 @@ class EventHandler
// Indicates the current state of the system (ie, which mode is current)
State myState;
// The serializer to use for saving eventstreams
Serializer myEventStream;
// Indicates current overlay object
DialogContainer* myOverlay;
// Global Event object
Event* myEvent;
// Indicates the current state to use for state loading/saving
uInt32 myLSState;
@ -460,18 +446,9 @@ class EventHandler
// Indicates which paddle the mouse currently emulates
Int8 myPaddleMode;
// The current keymap in string form
string myKeymapString;
// The current joymap in string form
string myJoymapString;
// Used for paddle emulation by keyboard or joystick
JoyMouse myPaddle[4];
// How far the joystick will move the mouse on each frame tick
int myMouseMove;
// Type of device on each controller port (based on ROM properties)
Controller::Type myController[2];

View File

@ -0,0 +1,124 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventStreamer.cxx,v 1.1 2005-12-28 22:56:36 stephena Exp $
//============================================================================
#include "bspf.hxx"
#include "OSystem.hxx"
#include "Event.hxx"
#include "EventHandler.hxx"
#include "EventStreamer.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventStreamer::EventStreamer(OSystem* osystem)
: myOSystem(osystem),
myEventRecordFlag(false)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
EventStreamer::~EventStreamer()
{
stopRecording();
myEventHistory.clear();
myStreamReader.close();
myStreamWriter.close();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventStreamer::startRecording()
{
string eventfile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp";
if(!myStreamWriter.open(eventfile))
return false;
// And save the current state to it
string md5 = myOSystem->console().properties().get("Cartridge.MD5");
myOSystem->console().system().saveState(md5, myStreamWriter);
myEventHistory.clear();
return myEventRecordFlag = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventStreamer::stopRecording()
{
if(!myStreamWriter.isOpen() || !myEventRecordFlag)
return false;
// Append the event history to the eventstream
int size = myEventHistory.size();
myStreamWriter.putString("EventStream");
myStreamWriter.putInt(size);
for(int i = 0; i < size; ++i)
myStreamWriter.putInt(myEventHistory[i]);
myStreamWriter.close();
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool EventStreamer::loadRecording()
{
cerr << "EventStreamer::loadRecording()\n";
string eventfile = /*myOSystem->baseDir() + BSPF_PATH_SEPARATOR +*/ "test.inp";
if(!myStreamReader.open(eventfile))
return false;
// Load ROM state
string md5 = myOSystem->console().properties().get("Cartridge.MD5");
myOSystem->console().system().loadState(md5, myStreamReader);
if(myStreamReader.getString() != "EventStream")
return false;
// Now load the event stream
myEventHistory.clear();
int size = myStreamReader.getInt();
for(int i = 0; i < size; ++i)
myEventHistory.push_back(myStreamReader.getInt());
cerr << "event queue contains " << myEventHistory.size() << " items\n";
return myEventRecordFlag = false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventStreamer::addEvent(int type, int value)
{
if(myEventRecordFlag)
{
myEventHistory.push_back(type);
myEventHistory.push_back(value);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void EventStreamer::nextFrame()
{
if(myEventRecordFlag)
{
int idx = myEventHistory.size() - 1;
if(idx >= 0 && myEventHistory[idx] < 0)
--myEventHistory[idx];
else
myEventHistory.push_back(-1);
}
}

View File

@ -0,0 +1,114 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: EventStreamer.hxx,v 1.1 2005-12-28 22:56:36 stephena Exp $
//============================================================================
#ifndef EVENTSTREAMER_HXX
#define EVENTSTREAMER_HXX
#include "Array.hxx"
#include "Deserializer.hxx"
#include "Serializer.hxx"
class OSystem;
/**
This class takes care of event streams, which consist of a ROM state
file and appended event data. This appended data is defined as a
string of integers which are grouped as follows:
event; event ; ... ; -framewait; event ... ; -framewait; ...
'event' consists of type/value pairs (each event in Stella is an
enumerated type with an associated value)
'framewait' is the number of frames to wait until executing all
the following events
The EventStreamer can load and save eventstream recordings. When in
'save' mode, all events are queued from the Event class, and appended to
the ROM state when recording was started.
When in 'load' mode, the ROM state is loaded from the eventstream, and
the appended event data is available in a queue for polling.
It's the responsibility of the calling object (most likely the EventHandler)
to poll for data; this class simply makes the queued events available in
the correct order at the correct time.
@author Stephen Anthony
@version $Id: EventStreamer.hxx,v 1.1 2005-12-28 22:56:36 stephena Exp $
*/
class EventStreamer
{
public:
/**
Create a new event streamer object
*/
EventStreamer(OSystem* osystem);
/**
Destructor
*/
virtual ~EventStreamer();
public:
/**
Start recording event-stream to disk
*/
bool startRecording();
/**
Stop recording event-stream
*/
bool stopRecording();
/**
Load recorded event-stream into the system
*/
bool loadRecording();
/**
Adds the given event to the event history
*/
void addEvent(int type, int value);
/**
Answers if we're in recording mode
*/
bool isRecording() { return myEventRecordFlag; }
/**
Indicate that a new frame has been processed
*/
void nextFrame();
private:
private:
// Global OSystem object
OSystem* myOSystem;
// Indicates if we're in recording mode
bool myEventRecordFlag;
// Serializer classes used to save/load the eventstream
Serializer myStreamWriter;
Deserializer myStreamReader;
// Stores the history/record of all events that have been set
IntArray myEventHistory;
};
#endif

View File

@ -29,6 +29,7 @@ MODULE_OBJS := \
src/emucore/Driving.o \
src/emucore/Event.o \
src/emucore/EventHandler.o \
src/emucore/EventStreamer.o \
src/emucore/FrameBuffer.o \
src/emucore/FSNode.o \
src/emucore/Joystick.o \