add session recording and playback

This commit is contained in:
David Rose 2004-01-30 18:20:47 +00:00
parent f8ce9193c2
commit 889be29b47
124 changed files with 4537 additions and 446 deletions

View File

@ -17,6 +17,8 @@ class ClientRepository(ConnectionRepository.ConnectionRepository):
def __init__(self, dcFileName):
ConnectionRepository.ConnectionRepository.__init__(self, base.config)
self.recorder = base.recorder
self.number2cdc={}
self.name2cdc={}

View File

@ -44,6 +44,7 @@ class ConnectionRepository(DirectObject.DirectObject):
self.cw = None
self.tcpConn = None
self.recorder = None
# Reader statistics
self.rsDatagramCount = 0
@ -65,6 +66,22 @@ class ConnectionRepository(DirectObject.DirectObject):
known.
"""
if self.recorder and self.recorder.isPlaying():
# If we have a recorder and it's already in playback mode,
# don't actually attempt to connect to a gameserver since
# we don't need to. Just let it play back the data.
self.notify.info("Not connecting to gameserver; using playback data instead.")
self.connectHttp = 1
self.tcpConn = SocketStreamRecorder()
self.recorder.addRecorder('gameserver', self.tcpConn)
self.startReaderPollTask()
if successCallback:
successCallback(*successArgs)
return
hasProxy = 0
if self.checkHttp():
proxies = self.http.getProxiesForUrl(serverList[0])
@ -151,6 +168,24 @@ class ConnectionRepository(DirectObject.DirectObject):
if ch.isConnectionReady():
self.tcpConn = ch.getConnection()
self.tcpConn.userManagesMemory = 1
if self.recorder:
# If we have a recorder, we wrap the connect inside a
# SocketStreamRecorder, which will trap incoming data
# when the recorder is set to record mode. (It will
# also play back data when the recorder is in playback
# mode, but in that case we never get this far in the
# code, since we just create an empty
# SocketStreamRecorder without actually connecting to
# the gameserver.)
stream = SocketStreamRecorder(self.tcpConn, 1)
self.recorder.addRecorder('gameserver', stream)
# In this case, we pass ownership of the original
# connection to the SocketStreamRecorder object.
self.tcpConn.userManagesMemory = 0
self.tcpConn = stream
self.startReaderPollTask()
if successCallback:
successCallback(*successArgs)

View File

@ -1,5 +1,4 @@
from libpandaexpressModules import *
from MessengerGlobal import *
from TaskManagerGlobal import *
from DirectNotifyGlobal import *
@ -16,15 +15,8 @@ class EventManager:
if (EventManager.notify == None):
EventManager.notify = directNotify.newCategory("EventManager")
if eventQueue != None:
self.eventQueue = eventQueue
else:
self.eventQueue = EventQueue.getGlobalEventQueue()
try:
self.eventHandler = EventHandler.getGlobalEventHandler(self.eventQueue)
except:
self.eventHandler = EventHandler(self.eventQueue)
self.eventQueue = eventQueue
self.eventHandler = None
def doEvents(self):
"""
@ -78,13 +70,29 @@ class EventManager:
else:
messenger.send(eventName)
# Also send the event down into C++ land
self.eventHandler.dispatchEvent(event)
if self.eventHandler:
self.eventHandler.dispatchEvent(event)
else:
# An unnamed event from C++ is probably a bad thing
EventManager.notify.warning('unnamed event in processEvent')
def restart(self):
from PandaModules import EventQueue, EventHandler
if self.eventQueue == None:
self.eventQueue = EventQueue.getGlobalEventQueue()
if self.eventHandler == None:
if self.eventQueue == EventQueue.getGlobalEventQueue():
# If we are using the global event queue, then we also
# want to use the global event handler.
self.eventHandler = EventHandler.getGlobalEventHandler(self.eventQueue)
else:
# Otherwise, we need our own event handler.
self.eventHandler = EventHandler(self.eventQueue)
taskMgr.add(self.eventLoopTask, 'eventManager')
def shutdown(self):

View File

@ -132,6 +132,28 @@ class ShowBase(DirectObject.DirectObject):
self.cameraList = []
self.camera2d = self.render2d.attachNewNode('camera2d')
# Maybe create a RecorderController to record and/or play back
# the user session.
self.recorder = None
playbackSession = self.config.GetString('playback-session', '')
recordSession = self.config.GetString('record-session', '')
if playbackSession:
self.recorder = RecorderController()
self.recorder.beginPlayback(Filename.fromOsSpecific(playbackSession))
elif recordSession:
self.recorder = RecorderController()
self.recorder.beginRecord(Filename.fromOsSpecific(recordSession))
if self.recorder:
# If we're either playing back or recording, pass the
# random seed into the system so each session will have
# the same random seed.
import random, whrandom
seed = self.recorder.getRandomSeed()
random.seed(seed)
whrandom.seed(seed & 0xff, (seed >> 8) & 0xff, (seed >> 16) & 0xff)
# Now that we've set up the window structures, assign an exitfunc.
self.oldexitfunc = getattr(sys, 'exitfunc', None)
sys.exitfunc = self.exitfunc
@ -563,6 +585,16 @@ class ShowBase(DirectObject.DirectObject):
self.mak = self.dataRoot.attachNewNode(MouseAndKeyboard(win, 0, 'mak'))
self.mouseWatcherNode = MouseWatcher('mouseWatcher')
self.mouseWatcher = self.mak.attachNewNode(self.mouseWatcherNode)
if self.recorder:
# If we have a recorder, the mouseWatcher belongs under a
# special MouseRecorder node, which may intercept the
# mouse activity.
mouseRecorder = MouseRecorder('mouse')
self.recorder.addRecorder('mouse', mouseRecorder.upcastToRecorderBase())
np = self.mak.attachNewNode(mouseRecorder)
self.mouseWatcher.reparentTo(np)
mb = self.mouseWatcherNode.getModifierButtons()
mb.addButton(KeyboardButton.shift())
mb.addButton(KeyboardButton.control())
@ -867,6 +899,9 @@ class ShowBase(DirectObject.DirectObject):
# as we reasonably can before the renderFrame().
onScreenDebug.render()
if self.recorder:
self.recorder.recordFrame()
# Finally, render the frame.
self.graphicsEngine.renderFrame()
if self.clusterSyncFlag:
@ -876,6 +911,9 @@ class ShowBase(DirectObject.DirectObject):
# We clear the text buffer for the onScreenDebug as soon
# as we reasonably can after the renderFrame().
onScreenDebug.clear()
if self.recorder:
self.recorder.playFrame()
if self.mainWinMinimized:
# If the main window is minimized, slow down the app a bit

View File

@ -10,15 +10,15 @@
#define WIN_SYS_LIBS $[WIN_SYS_LIBS] Ws2_32.lib
#define COMPONENT_LIBS \
pgraph \
recorder pgraph \
pvrpn grutil chan chancfg pstatclient \
char chat collide cull device \
dgraph display gobj graph gsgbase \
dgraph display event gobj graph gsgbase \
gsgmisc light linmath mathutil net \
parametrics pnm \
pnmimagetypes pnmimage sgattrib sgmanip sgraph sgraphutil \
switchnode pnmtext text tform tiff lerp loader putil \
audio pgui pandabase
audio pgui pandabase

View File

@ -8,7 +8,7 @@
#define BUILDING_DLL BUILDING_PANDAEXPRESS
#define USE_PACKAGES net
#define COMPONENT_LIBS downloader event ipc express pandabase
#define COMPONENT_LIBS downloader ipc express pandabase
#define OTHER_LIBS dtoolconfig dtool
#begin metalib_target

View File

@ -27,7 +27,7 @@
#include "collisionRecorder.h"
#include "transformState.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
#include "luse.h"
#include "pointerTo.h"
#include "pandaNode.h"
@ -47,7 +47,7 @@
// is up to the handler to determine what information is
// known and to do the right thing with it.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA CollisionEntry : public TypedReferenceCount {
class EXPCL_PANDA CollisionEntry : public TypedWritableReferenceCount {
public:
INLINE CollisionEntry();
CollisionEntry(const CollisionEntry &copy);
@ -150,9 +150,9 @@ public:
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "CollisionEntry",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -30,9 +30,9 @@ TrackerNode::
TrackerNode(ClientBase *client, const string &device_name) :
DataNode(device_name)
{
_transform_output = define_output("transform", EventStoreTransform::get_class_type());
_transform_output = define_output("transform", TransformState::get_class_type());
_transform = new EventStoreTransform(TransformState::make_identity());
_transform = TransformState::make_identity();
nassertv(client != (ClientBase *)NULL);
set_tracker_coordinate_system(client->get_coordinate_system());
@ -99,7 +99,7 @@ do_transmit_data(const DataNodeTransmit &, DataNodeTransmit &output) {
// Now send our matrix down the pipe. TODO: store this
// componentwise instead of just as a matrix-based transform.
_transform->set_value(TransformState::make_mat(_mat));
_transform = TransformState::make_mat(_mat);
output.set_data(_transform_output, EventParameter(_transform));
}
}

View File

@ -63,7 +63,7 @@ private:
// outputs
int _transform_output;
PT(EventStoreTransform) _transform;
CPT(TransformState) _transform;
private:
PT(ClientTrackerDevice) _tracker;

View File

@ -18,12 +18,16 @@
#include "config_dgraph.h"
#include "dataNode.h"
#include "dataNodeTransmit.h"
#include <dconfig.h>
#include "dconfig.h"
Configure(config_dgraph);
NotifyCategoryDef(dgraph, "");
ConfigureFn(config_dgraph) {
DataNode::init_type();
DataNodeTransmit::init_type();
DataNodeTransmit::register_with_read_factory();
}

View File

@ -333,3 +333,26 @@ reconnect() {
<< "No data connected to " << *this << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: DataNode::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void DataNode::
write_datagram(BamWriter *manager, Datagram &dg) {
PandaNode::write_datagram(manager, dg);
}
////////////////////////////////////////////////////////////////////
// Function: DataNode::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new Lens.
////////////////////////////////////////////////////////////////////
void DataNode::
fillin(DatagramIterator &scan, BamReader *manager) {
PandaNode::fillin(scan, manager);
}

View File

@ -119,6 +119,12 @@ private:
typedef pvector<DataConnection> DataConnections;
DataConnections _data_connections;
public:
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -47,15 +47,6 @@ operator = (const DataNodeTransmit &copy) {
_data = copy._data;
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE DataNodeTransmit::
~DataNodeTransmit() {
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::reserve
// Access: Public

View File

@ -17,6 +17,19 @@
////////////////////////////////////////////////////////////////////
#include "dataNodeTransmit.h"
#include "bamReader.h"
#include "bamWriter.h"
TypeHandle DataNodeTransmit::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
DataNodeTransmit::
~DataNodeTransmit() {
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::slot_data
@ -31,3 +44,91 @@ slot_data(int index) {
_data.push_back(EventParameter());
}
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
void DataNodeTransmit::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void DataNodeTransmit::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritable::write_datagram(manager, dg);
dg.add_uint16(_data.size());
Data::const_iterator di;
for (di = _data.begin(); di != _data.end(); ++di) {
const EventParameter &param = (*di);
TypedWritableReferenceCount *ptr = param.get_ptr();
manager->write_pointer(dg, ptr);
}
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int DataNodeTransmit::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = TypedWritable::complete_pointers(p_list, manager);
Data::iterator di;
for (di = _data.begin(); di != _data.end(); ++di) {
(*di) = EventParameter(DCAST(TypedWritableReferenceCount, p_list[pi++]));
}
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *DataNodeTransmit::
make_from_bam(const FactoryParams &params) {
DataNodeTransmit *xmit = new DataNodeTransmit;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
xmit->fillin(scan, manager);
return xmit;
}
////////////////////////////////////////////////////////////////////
// Function: DataNodeTransmit::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new Lens.
////////////////////////////////////////////////////////////////////
void DataNodeTransmit::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
int num_params = scan.get_uint16();
_data.reserve(num_params);
for (int i = 0; i < num_params; i++) {
manager->read_pointer(scan);
_data.push_back(EventParameter());
}
}

View File

@ -21,6 +21,12 @@
#include "pandabase.h"
#include "eventParameter.h"
#include "typedWritable.h"
class Datagram;
class DatagramIterator;
class BamReader;
class BamWriter;
////////////////////////////////////////////////////////////////////
// Class : DataNodeTransmit
@ -29,12 +35,12 @@
// array of EventParameters, one for each registered
// input or output wire.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DataNodeTransmit {
class EXPCL_PANDA DataNodeTransmit : public TypedWritable {
public:
INLINE DataNodeTransmit();
INLINE DataNodeTransmit(const DataNodeTransmit &copy);
INLINE void operator = (const DataNodeTransmit &copy);
INLINE ~DataNodeTransmit();
virtual ~DataNodeTransmit();
INLINE void reserve(int num_wires);
@ -47,6 +53,33 @@ private:
typedef pvector<EventParameter> Data;
Data _data;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual int complete_pointers(TypedWritable **plist,
BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritable::init_type();
register_type(_type_handle, "DataNodeTransmit",
TypedWritable::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "dataNodeTransmit.I"

View File

@ -29,7 +29,7 @@
#include "graphicsStateGuardian.h"
#include "clearableRegion.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
#include "mouseData.h"
#include "modifierButtons.h"
#include "buttonEvent.h"
@ -55,8 +55,14 @@
// input. The actual rendering, and anything associated
// with the graphics context itself, is managed by the
// window's GraphicsStateGuardian.
//
// GraphicsWindows are not actually writable to bam
// files, of course, but they may be passed as event
// parameters, so they inherit from
// TypedWritableReferenceCount instead of
// TypedReferenceCount for that convenience.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA GraphicsWindow : public TypedReferenceCount, public ClearableRegion {
class EXPCL_PANDA GraphicsWindow : public TypedWritableReferenceCount, public ClearableRegion {
protected:
GraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
@ -183,9 +189,9 @@ public:
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "GraphicsWindow",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -1,4 +1,4 @@
#define LOCAL_LIBS event express pandabase
#define LOCAL_LIBS express pandabase
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#define USE_PACKAGES zlib net ssl

View File

@ -1,4 +1,4 @@
#define LOCAL_LIBS express pandabase
#define LOCAL_LIBS putil express pandabase
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
@ -8,20 +8,28 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx
#define SOURCES \
config_event.h event.I event.h eventHandler.h eventHandler.I eventParameter.I \
eventParameter.h eventQueue.I eventQueue.h eventReceiver.h \
pt_Event.h throw_event.I throw_event.h
config_event.h \
buttonEvent.I buttonEvent.h \
buttonEventList.I buttonEventList.h \
event.I event.h eventHandler.h eventHandler.I \
eventParameter.I eventParameter.h \
eventQueue.I eventQueue.h eventReceiver.h \
pt_Event.h throw_event.I throw_event.h
#define INCLUDED_SOURCES \
config_event.cxx event.cxx eventHandler.cxx \
eventParameter.cxx eventQueue.cxx eventReceiver.cxx \
pt_Event.cxx
buttonEvent.cxx \
buttonEventList.cxx \
config_event.cxx event.cxx eventHandler.cxx \
eventParameter.cxx eventQueue.cxx eventReceiver.cxx \
pt_Event.cxx
#define INSTALL_HEADERS \
event.I event.h eventHandler.h eventHandler.I eventParameter.I eventParameter.h \
eventQueue.h eventQueue.I throw_event.h throw_event.I \
eventReceiver.h \
pt_Event.h
#define INSTALL_HEADERS \
buttonEvent.I buttonEvent.h \
buttonEventList.I buttonEventList.h \
event.I event.h eventHandler.h eventHandler.I \
eventParameter.I eventParameter.h \
eventQueue.I eventQueue.h eventReceiver.h \
pt_Event.h throw_event.I throw_event.h
#define IGATESCAN all

View File

@ -125,3 +125,23 @@ operator < (const ButtonEvent &other) const {
return _type < other._type;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEvent::update_mods
// Access: Published
// Description: Calls button_down() or button_up(), as appropriate,
// according to the ButtonEvent.
////////////////////////////////////////////////////////////////////
INLINE bool ButtonEvent::
update_mods(ModifierButtons &mods) const {
switch (_type) {
case T_down:
return mods.button_down(_button);
case T_up:
return mods.button_up(_button);
default:
return false;
}
}

View File

@ -0,0 +1,94 @@
// Filename: buttonEvent.cxx
// Created by: drose (01Mar00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "buttonEvent.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "buttonRegistry.h"
////////////////////////////////////////////////////////////////////
// Function: ButtonEvent::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEvent::
output(ostream &out) const {
switch (_type) {
case T_down:
out << "button " << _button << " down";
break;
case T_resume_down:
out << "button " << _button << " resume down";
break;
case T_up:
out << "button " << _button << " up";
break;
case T_keystroke:
out << "keystroke " << _keycode;
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEvent::write_datagram
// Access: Public
// Description: Writes the event into a datagram.
////////////////////////////////////////////////////////////////////
void ButtonEvent::
write_datagram(Datagram &dg) const {
dg.add_uint8(_type);
switch (_type) {
case T_down:
case T_resume_down:
case T_up:
// We write the button name. This is not particularly compact, but
// presumably we don't get thousands of button events per frame, and
// it is robust as the button index may change between sessions but
// the button name will not.
dg.add_string(_button.get_name());
break;
case T_keystroke:
dg.add_int16(_keycode);
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEvent::read_datagram
// Access: Public
// Description: Restores the event from the datagram.
////////////////////////////////////////////////////////////////////
void ButtonEvent::
read_datagram(DatagramIterator &scan) {
_type = (Type)scan.get_uint8();
switch (_type) {
case T_down:
case T_resume_down:
case T_up:
_button = ButtonRegistry::ptr()->get_button(scan.get_string());
break;
case T_keystroke:
_keycode = scan.get_int16();
break;
}
}

View File

@ -23,6 +23,10 @@
#include "buttonHandle.h"
#include "clockObject.h"
#include "modifierButtons.h"
class Datagram;
class DatagramIterator;
////////////////////////////////////////////////////////////////////
// Class : ButtonEvent
@ -81,8 +85,14 @@ public:
INLINE bool operator != (const ButtonEvent &other) const;
INLINE bool operator < (const ButtonEvent &other) const;
INLINE bool update_mods(ModifierButtons &mods) const;
void output(ostream &out) const;
void write_datagram(Datagram &dg) const;
void read_datagram(DatagramIterator &scan);
public:
// _button will be filled in if type is T_down, T_resume_down, or
// T_up.
ButtonHandle _button;

View File

@ -0,0 +1,163 @@
// Filename: buttonEventList.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "buttonEventList.h"
#include "modifierButtons.h"
#include "indent.h"
TypeHandle ButtonEventList::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::add_events
// Access: Public
// Description: Appends the events from the other list onto the end
// of this one.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
add_events(const ButtonEventList &other) {
_events.reserve(_events.size() + other._events.size());
Events::const_iterator ei;
for (ei = other._events.begin(); ei != other._events.end(); ++ei) {
_events.push_back(*ei);
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::update_mods
// Access: Public
// Description: Updates the indicated ModifierButtons object with all
// of the button up/down transitions indicated in the
// list.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
update_mods(ModifierButtons &mods) const {
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
(*ei).update_mods(mods);
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEventList::
output(ostream &out) const {
if (_events.empty()) {
out << "(no buttons)";
} else {
Events::const_iterator ei;
ei = _events.begin();
out << "(" << (*ei);
++ei;
while (ei != _events.end()) {
out << " " << (*ei);
++ei;
}
out << ")";
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEventList::
write(ostream &out, int indent_level) const {
indent(out, indent_level) << _events.size() << " events:\n";
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
indent(out, indent_level + 2) << (*ei) << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritable::write_datagram(manager, dg);
dg.add_uint16(_events.size());
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
(*ei).write_datagram(dg);
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *ButtonEventList::
make_from_bam(const FactoryParams &params) {
ButtonEventList *list = new ButtonEventList;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
list->fillin(scan, manager);
return list;
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::fillin
// Access: Public
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new ButtonEventList.
//
// This function is normally protected, but it is
// declared public in this case so that MouseRecorder
// may call it to read a ButtonEventList from the middle
// of a datagram.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
int num_events = scan.get_uint16();
_events.clear();
_events.reserve(num_events);
for (int i = 0; i < num_events; i++) {
ButtonEvent event;
event.read_datagram(scan);
_events.push_back(event);
}
}

View File

@ -27,6 +27,8 @@
#include "pvector.h"
class ModifierButtons;
class Datagram;
class DatagramIterator;
////////////////////////////////////////////////////////////////////
// Class : ButtonEventList
@ -45,6 +47,7 @@ public:
INLINE const ButtonEvent &get_event(int n) const;
INLINE void clear();
void add_events(const ButtonEventList &other);
void update_mods(ModifierButtons &mods) const;
virtual void output(ostream &out) const;
@ -53,6 +56,16 @@ public:
private:
typedef pvector<ButtonEvent> Events;
Events _events;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {

View File

@ -17,21 +17,28 @@
////////////////////////////////////////////////////////////////////
#include "config_event.h"
#include "buttonEventList.h"
#include "event.h"
#include "eventHandler.h"
#include "eventParameter.h"
#include <dconfig.h>
#include "dconfig.h"
Configure(config_event);
NotifyCategoryDef(event, "");
ConfigureFn(config_event) {
ButtonEventList::init_type();
Event::init_type();
EventHandler::init_type();
EventStoreValueBase::init_type();
EventStoreInt::init_type("EventStoreInt");
EventStoreDouble::init_type("EventStoreDouble");
EventStoreString::init_type("EventStoreString");
ButtonEventList::register_with_read_factory();
EventStoreInt::register_with_read_factory();
EventStoreDouble::register_with_read_factory();
EventStoreString::register_with_read_factory();
}

View File

@ -21,7 +21,7 @@
#include "pandabase.h"
#include <notifyCategoryProxy.h>
#include "notifyCategoryProxy.h"
NotifyCategoryDecl(event, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS);

View File

@ -36,7 +36,7 @@ class EventReceiver;
// makes it too expensive to get its name the Python
// code. Now it just copies the Namable interface in.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS Event : public TypedReferenceCount {
class EXPCL_PANDA Event : public TypedReferenceCount {
PUBLISHED:
Event(const string &event_name, EventReceiver *receiver = NULL);
Event(const Event &copy);

View File

@ -1,5 +1,5 @@
// Filename: eventHandler.h
// Created by: drose (08Feb99)
// Filename: eventHandler.I
// Created by: skyler (27Jan04)
//
////////////////////////////////////////////////////////////////////
//

View File

@ -35,8 +35,8 @@ EventParameter() {
// Function: EventParameter::Pointer constructor
// Access: Public
// Description: Defines an EventParameter that stores a pointer to
// any kind of TypedReferenceCount object. This is the
// most general constructor.
// any kind of TypedWritableReferenceCount object. This
// is the most general constructor.
//
// This accepts a const pointer, even though it stores
// (and eventually returns) a non-const pointer. This
@ -45,7 +45,7 @@ EventParameter() {
// constness. Be careful.
////////////////////////////////////////////////////////////////////
INLINE EventParameter::
EventParameter(const TypedReferenceCount *ptr) : _ptr((TypedReferenceCount *)ptr) { }
EventParameter(const TypedWritableReferenceCount *ptr) : _ptr((TypedWritableReferenceCount *)ptr) { }
////////////////////////////////////////////////////////////////////
@ -105,7 +105,7 @@ operator = (const EventParameter &other) {
////////////////////////////////////////////////////////////////////
INLINE bool EventParameter::
is_empty() const {
return (_ptr == (TypedReferenceCount *)NULL);
return (_ptr == (TypedWritableReferenceCount *)NULL);
}
////////////////////////////////////////////////////////////////////
@ -201,7 +201,7 @@ get_string_value() const {
// contains. This is the only way to retrieve the value
// when it is not one of the above predefined types.
////////////////////////////////////////////////////////////////////
INLINE TypedReferenceCount *EventParameter::
INLINE TypedWritableReferenceCount *EventParameter::
get_ptr() const {
return _ptr;
}
@ -248,3 +248,63 @@ void EventStoreValue<Type>::
output(ostream &out) const {
out << _value;
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreValue::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
template<class Type>
void EventStoreValue<Type>::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreValue::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
template<class Type>
void EventStoreValue<Type>::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritable::write_datagram(manager, dg);
generic_write_datagram(dg, _value);
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreValue::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
template<class Type>
TypedWritable *EventStoreValue<Type>::
make_from_bam(const FactoryParams &params) {
EventStoreValue<Type> *esv = new EventStoreValue<Type>;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
esv->fillin(scan, manager);
return esv;
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreValue::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new Lens.
////////////////////////////////////////////////////////////////////
template<class Type>
void EventStoreValue<Type>::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
generic_read_datagram(_value, scan);
}

View File

@ -33,7 +33,7 @@ TypeHandle EventStoreValueBase::_type_handle;
////////////////////////////////////////////////////////////////////
void EventParameter::
output(ostream &out) const {
if (_ptr == (TypedReferenceCount *)NULL) {
if (_ptr == (TypedWritableReferenceCount *)NULL) {
out << "(empty)";
} else if (_ptr->is_of_type(EventStoreValueBase::get_class_type())) {

View File

@ -23,23 +23,26 @@
#include "typedef.h"
#include "typedObject.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
#include "pointerTo.h"
#include "bamReader.h"
#include "bamWriter.h"
////////////////////////////////////////////////////////////////////
// Class : EventParameter
// Description : An optional parameter associated with an event. Each
// event may have zero or more of these. Each parameter
// stores a pointer to a TypedReferenceCount object,
// which of course could be pretty much anything. To
// store a simple value like a double or a string, the
// EventParameter constructors transparently use the
// EventStoreValue template class, defined below.
// stores a pointer to a TypedWritableReferenceCount
// object, which of course could be pretty much
// anything. To store a simple value like a double or a
// string, the EventParameter constructors transparently
// use the EventStoreValue template class, defined
// below.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS EventParameter {
class EXPCL_PANDA EventParameter {
PUBLISHED:
INLINE EventParameter();
INLINE EventParameter(const TypedReferenceCount *ptr);
INLINE EventParameter(const TypedWritableReferenceCount *ptr);
INLINE EventParameter(int value);
INLINE EventParameter(double value);
INLINE EventParameter(const string &value);
@ -60,12 +63,12 @@ PUBLISHED:
INLINE bool is_string() const;
INLINE string get_string_value() const;
INLINE TypedReferenceCount *get_ptr() const;
INLINE TypedWritableReferenceCount *get_ptr() const;
void output(ostream &out) const;
private:
PT(TypedReferenceCount) _ptr;
PT(TypedWritableReferenceCount) _ptr;
};
INLINE ostream &operator << (ostream &out, const EventParameter &param);
@ -76,7 +79,7 @@ INLINE ostream &operator << (ostream &out, const EventParameter &param);
// which serves mainly to define the placeholder for the
// virtual output function.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS EventStoreValueBase : public TypedReferenceCount {
class EXPCL_PANDAEXPRESS EventStoreValueBase : public TypedWritableReferenceCount {
public:
virtual void output(ostream &out) const=0;
@ -89,9 +92,9 @@ public:
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "EventStoreValueBase",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
private:
@ -103,12 +106,15 @@ private:
// Description : A handy class object for storing simple values (like
// integers or strings) passed along with an Event.
// This is essentially just a wrapper around whatever
// data type you like, to make it a TypedReferenceCount
// object which can be passed along inside an
// EventParameter.
// data type you like, to make it a
// TypedWritableReferenceCount object which can be
// passed along inside an EventParameter.
////////////////////////////////////////////////////////////////////
template<class Type>
class EventStoreValue : public EventStoreValueBase {
private:
// This constructor is only for make_from_bam().
EventStoreValue() { }
public:
EventStoreValue(const Type &value) : _value(value) { }
@ -119,6 +125,14 @@ public:
Type _value;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
@ -141,9 +155,9 @@ private:
static TypeHandle _type_handle;
};
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<int>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<double>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue<std::string>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, EventStoreValue<int>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, EventStoreValue<double>);
EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, EventStoreValue<std::string>);
typedef EventStoreValue<int> EventStoreInt;
typedef EventStoreValue<double> EventStoreDouble;

View File

@ -1,4 +1,5 @@
#include "buttonEvent.cxx"
#include "buttonEventList.cxx"
#include "config_event.cxx"
#include "event.cxx"
#include "eventHandler.cxx"

View File

@ -456,3 +456,28 @@ operator < (const Datagram &other) const {
// One of the pointers is NULL, but not the other one.
return _data.size() < other._data.size();
}
INLINE void
generic_write_datagram(Datagram &dest, bool value) {
dest.add_bool(value);
}
INLINE void
generic_write_datagram(Datagram &dest, int value) {
dest.add_int32(value);
}
INLINE void
generic_write_datagram(Datagram &dest, float value) {
dest.add_float32(value);
}
INLINE void
generic_write_datagram(Datagram &dest, double value) {
dest.add_float64(value);
}
INLINE void
generic_write_datagram(Datagram &dest, const string &value) {
dest.add_string(value);
}

View File

@ -120,6 +120,23 @@ private:
static TypeHandle _type_handle;
};
// These generic functions are primarily for writing a value to a
// datagram from within a template in which the actual type of the
// value is not known. If you do know the type, it's preferable to
// use the explicit add_*() method from above instead.
INLINE void
generic_write_datagram(Datagram &dest, bool value);
INLINE void
generic_write_datagram(Datagram &dest, int value);
INLINE void
generic_write_datagram(Datagram &dest, float value);
INLINE void
generic_write_datagram(Datagram &dest, double value);
INLINE void
generic_write_datagram(Datagram &dest, const string &value);
#include "datagram.I"
#endif

View File

@ -482,3 +482,30 @@ INLINE size_t DatagramIterator::
get_current_index() const {
return _current_index;
}
INLINE void
generic_read_datagram(bool &result, DatagramIterator &source) {
result = source.get_bool();
}
INLINE void
generic_read_datagram(int &result, DatagramIterator &source) {
result = source.get_int32();
}
INLINE void
generic_read_datagram(float &result, DatagramIterator &source) {
result = source.get_float32();
}
INLINE void
generic_read_datagram(double &result, DatagramIterator &source) {
result = source.get_float64();
}
INLINE void
generic_read_datagram(string &result, DatagramIterator &source) {
result = source.get_string();
}

View File

@ -80,6 +80,22 @@ private:
size_t _current_index;
};
// These generic functions are primarily for reading a value from a
// datagram from within a template in which the actual type of the
// value is not known. If you do know the type, it's preferable to
// use the explicit get_*() method from above instead.
INLINE void
generic_read_datagram(bool &result, DatagramIterator &source);
INLINE void
generic_read_datagram(int &result, DatagramIterator &source);
INLINE void
generic_read_datagram(float &result, DatagramIterator &source);
INLINE void
generic_read_datagram(double &result, DatagramIterator &source);
INLINE void
generic_read_datagram(string &result, DatagramIterator &source);
#include "datagramIterator.I"
#endif

View File

@ -35,16 +35,24 @@ bool
_dcast_verify(TypeHandle want_handle, size_t want_size,
const TypedObject *ptr) {
if (get_verify_dcast()) {
if ((ptr == (const TypedObject *)NULL)
if (ptr == (const TypedObject *)NULL) {
// This is allowed these days. It used to be an error, but
// what the heck.
if (express_cat->is_debug()) {
express_cat->debug()
<< "Attempt to cast NULL pointer to "
<< want_handle << "\n";
}
return true;
}
#if defined(_DEBUG) && defined(_WIN32)
|| IsBadWritePtr((TypedObject *)ptr, want_size)
#endif
) {
if (IsBadWritePtr((TypedObject *)ptr, want_size)) {
express_cat->warning()
<< "Attempt to cast NULL or invalid pointer to "
<< "Attempt to cast invalid pointer to "
<< want_handle << "\n";
return false;
}
#endif
if (!ptr->is_of_type(want_handle)) {
express_cat->error()
<< "Attempt to cast pointer from " << ptr->get_type()

View File

@ -34,7 +34,7 @@
// pass around pointers to things which are both
// TypedObjects and ReferenceCounters.
//
// See Also TypeObject for detailed instructions.
// See also TypedObject for detailed instructions.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS TypedReferenceCount : public TypedObject, public ReferenceCount {
public:

View File

@ -5,7 +5,7 @@
#define TARGET framework
#define BUILDING_DLL BUILDING_FRAMEWORK
#define LOCAL_LIBS \
pgui pgraph putil collide chan text chancfg \
recorder pgui pgraph putil collide chan text chancfg \
pnmimage pnmimagetypes event
#define SOURCES \

View File

@ -41,3 +41,7 @@ const bool show_frame_rate_meter = config_framework.GetBool("show-frame-rate-met
const float win_background_r = config_framework.GetFloat("win-background-r", 0.41);
const float win_background_g = config_framework.GetFloat("win-background-g", 0.41);
const float win_background_b = config_framework.GetFloat("win-background-b", 0.41);
const string record_session = config_framework.GetString("record-session", "");
const string playback_session = config_framework.GetString("playback-session", "");

View File

@ -38,4 +38,7 @@ extern const float win_background_r;
extern const float win_background_g;
extern const float win_background_b;
extern const string record_session;
extern const string playback_session;
#endif

View File

@ -172,6 +172,41 @@ get_highlight() const {
return _highlight;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_recorder
// Access: Public
// Description: Returns the RecorderController that has been
// associated with the PandaFramework, if any, or NULL
// if none has (the normal case).
//
// If a RecorderController is associated, it will
// presumably be used for recording user input to a
// session file, or for playing back the user input from
// a previously-recorded session.
////////////////////////////////////////////////////////////////////
INLINE RecorderController *PandaFramework::
get_recorder() const {
return _recorder;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_recorder
// Access: Public
// Description: Assigns a RecorderController with the PandaFramework.
// This should be called before any windows are opened.
// The subsequently opened windows will register their
// user inputs with the recorder.
//
// If a RecorderController is associated, it will
// presumably be used for recording user input to a
// session file, or for playing back the user input from
// a previously-recorded session.
////////////////////////////////////////////////////////////////////
INLINE void PandaFramework::
set_recorder(RecorderController *recorder) {
_recorder = recorder;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::set_exit_flag
// Access: Public

View File

@ -52,6 +52,19 @@ PandaFramework() :
_highlight_wireframe.set_color(1.0f, 0.0f, 0.0f, 1.0f, 1);
_default_keys_enabled = false;
_exit_flag = false;
if (!playback_session.empty()) {
// If the config file so indicates, create a recorder and start it
// playing.
_recorder = new RecorderController;
_recorder->begin_playback(Filename::from_os_specific(playback_session));
} else if (!record_session.empty()) {
// If the config file so indicates, create a recorder and start it
// recording.
_recorder = new RecorderController;
_recorder->begin_record(Filename::from_os_specific(record_session));
}
}
////////////////////////////////////////////////////////////////////
@ -115,6 +128,8 @@ close_framework() {
_lighting_enabled = false;
_default_keys_enabled = false;
_exit_flag = false;
_recorder = NULL;
}
////////////////////////////////////////////////////////////////////
@ -603,8 +618,16 @@ do_frame() {
DataGraphTraverser dg_trav;
dg_trav.traverse(_data_root.node());
_event_handler.process_events();
if (_recorder != (RecorderController *)NULL) {
_recorder->record_frame();
}
_engine.render_frame();
if (_recorder != (RecorderController *)NULL) {
_recorder->play_frame();
}
return !_exit_flag;
}

View File

@ -28,6 +28,7 @@
#include "graphicsPipe.h"
#include "graphicsEngine.h"
#include "graphicsWindow.h"
#include "recorderController.h"
#include "pointerTo.h"
#include "pvector.h"
@ -99,6 +100,9 @@ public:
INLINE bool has_highlight() const;
INLINE const NodePath &get_highlight() const;
INLINE RecorderController *get_recorder() const;
INLINE void set_recorder(RecorderController *recorder);
void enable_default_keys();
virtual bool do_frame();
@ -177,6 +181,8 @@ private:
KeyDefinitions _key_definitions;
NodePath _help_text;
PT(RecorderController) _recorder;
};
#include "pandaFramework.I"

View File

@ -19,6 +19,7 @@
#include "windowFramework.h"
#include "pandaFramework.h"
#include "mouseAndKeyboard.h"
#include "mouseRecorder.h"
#include "buttonThrower.h"
#include "transform2sg.h"
#include "dSearchPath.h"
@ -292,6 +293,14 @@ get_mouse() {
MouseAndKeyboard *mouse_node =
new MouseAndKeyboard(_window, 0, "mouse");
_mouse = data_root.attach_new_node(mouse_node);
RecorderController *recorder = _panda_framework->get_recorder();
if (recorder != (RecorderController *)NULL) {
// If we're in recording or playback mode, associate a recorder.
MouseRecorder *mouse_recorder = new MouseRecorder("mouse");
_mouse = _mouse.attach_new_node(mouse_recorder);
recorder->add_recorder("mouse", mouse_recorder);
}
}
return _mouse;
}

View File

@ -29,7 +29,7 @@
#include "frameRateMeter.h"
#include "pointerTo.h"
#include "pvector.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
class PandaFramework;
class AmbientLight;
@ -42,7 +42,7 @@ class GraphicsPipe;
// Description : This encapsulates the data that is normally
// associated with a single window that we've opened.
////////////////////////////////////////////////////////////////////
class EXPCL_FRAMEWORK WindowFramework : public TypedReferenceCount {
class EXPCL_FRAMEWORK WindowFramework : public TypedWritableReferenceCount {
protected:
WindowFramework(PandaFramework *panda_framework);
public:
@ -146,9 +146,9 @@ public:
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "WindowFramework",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -208,5 +208,8 @@ ConfigureFn(config_gobj) {
GeomTrifan::register_with_read_factory();
GeomSphere::register_with_read_factory();
Material::register_with_read_factory();
OrthographicLens::register_with_read_factory();
MatrixLens::register_with_read_factory();
PerspectiveLens::register_with_read_factory();
Texture::register_with_read_factory();
}

View File

@ -1734,3 +1734,50 @@ sqr_dist_to_line(const LPoint3f &point, const LPoint3f &origin,
float leg = d.dot(norm);
return hyp_2 - leg * leg;
}
////////////////////////////////////////////////////////////////////
// Function: Lens::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void Lens::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritable::write_datagram(manager, dg);
dg.add_string(_change_event);
dg.add_uint8((int)_cs);
_film_size.write_datagram(dg);
_film_offset.write_datagram(dg);
dg.add_float32(_focal_length);
_fov.write_datagram(dg);
dg.add_float32(_aspect_ratio);
dg.add_float32(_near_distance);
dg.add_float32(_far_distance);
dg.add_uint16(_user_flags);
}
////////////////////////////////////////////////////////////////////
// Function: Lens::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new Lens.
////////////////////////////////////////////////////////////////////
void Lens::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritable::fillin(scan, manager);
_change_event = scan.get_string();
_cs = (CoordinateSystem)scan.get_uint8();
_film_size.read_datagram(scan);
_film_offset.read_datagram(scan);
_focal_length = scan.get_float32();
_fov.read_datagram(scan);
_aspect_ratio = scan.get_float32();
_near_distance = scan.get_float32();
_far_distance = scan.get_float32();
_user_flags = scan.get_uint16();
_comp_flags = 0;
}

View File

@ -21,7 +21,7 @@
#include "pandabase.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
#include "luse.h"
#include "geom.h"
#include "updateSeq.h"
@ -40,7 +40,7 @@ class BoundingVolume;
// also used in other contexts, however; for instance, a
// Spotlight is also defined using a lens.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Lens : public TypedReferenceCount {
class EXPCL_PANDA Lens : public TypedWritableReferenceCount {
public:
Lens();
Lens(const Lens &copy);
@ -244,6 +244,12 @@ protected:
static const float _default_fov;
public:
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
public:
virtual TypeHandle get_type() const {
return get_class_type();
@ -253,9 +259,9 @@ public:
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "Lens",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
private:

View File

@ -68,3 +68,34 @@ compute_projection_mat() {
adjust_comp_flags(CF_projection_mat_inv,
CF_projection_mat);
}
////////////////////////////////////////////////////////////////////
// Function: MatrixLens::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
void MatrixLens::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: MatrixLens::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *MatrixLens::
make_from_bam(const FactoryParams &params) {
MatrixLens *lens = new MatrixLens;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
lens->fillin(scan, manager);
return lens;
}

View File

@ -27,10 +27,10 @@
////////////////////////////////////////////////////////////////////
// Class : MatrixLens
// Description : A completely generic linear lens. This is provided
// for the benefit low-level code that wants to specify
// a perspective or orthographic frustum via an explicit
// projection matrix, but not mess around with fov's or
// focal lengths or any of that nonsense.
// for the benefit of low-level code that wants to
// specify a perspective or orthographic frustum via an
// explicit projection matrix, but not mess around with
// fov's or focal lengths or any of that nonsense.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA MatrixLens : public Lens {
PUBLISHED:
@ -56,6 +56,12 @@ protected:
private:
LMatrix4f _user_mat;
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -112,3 +112,34 @@ compute_projection_mat() {
adjust_comp_flags(CF_projection_mat_inv,
CF_projection_mat);
}
////////////////////////////////////////////////////////////////////
// Function: OrthographicLens::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
void OrthographicLens::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: OrthographicLens::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *OrthographicLens::
make_from_bam(const FactoryParams &params) {
OrthographicLens *lens = new OrthographicLens;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
lens->fillin(scan, manager);
return lens;
}

View File

@ -52,6 +52,12 @@ public:
protected:
virtual void compute_projection_mat();
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -150,3 +150,34 @@ float PerspectiveLens::
film_to_fov(float film_size, float focal_length, bool) const {
return rad_2_deg(catan(film_size * 0.5f / focal_length)) * 2.0f;
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveLens::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
void PerspectiveLens::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveLens::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *PerspectiveLens::
make_from_bam(const FactoryParams &params) {
PerspectiveLens *lens = new PerspectiveLens;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
lens->fillin(scan, manager);
return lens;
}

View File

@ -47,6 +47,12 @@ protected:
virtual float fov_to_focal_length(float fov, float film_size, bool horiz) const;
virtual float film_to_fov(float film_size, float focal_length, bool horiz) const;
public:
static void register_with_read_factory();
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
public:
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -99,3 +99,39 @@ operator * (const FLOATNAME(LPoint3) &v, const FLOATNAME(LMatrix4) &m) {
return m.xform_point(v);
}
////////////////////////////////////////////////////////////////////
// Function: generic_write_datagram
// Description: Writes the value to the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LMatrix3) &value) {
value.write_datagram(dest);
}
////////////////////////////////////////////////////////////////////
// Function: generic_read_datagram
// Description: Reads the value from the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LMatrix3) &result, DatagramIterator &source) {
result.read_datagram(source);
}
////////////////////////////////////////////////////////////////////
// Function: generic_write_datagram
// Description: Writes the value to the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LMatrix4) &value) {
value.write_datagram(dest);
}
////////////////////////////////////////////////////////////////////
// Function: generic_read_datagram
// Description: Reads the value from the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LMatrix4) &result, DatagramIterator &source) {
result.read_datagram(source);
}

View File

@ -41,6 +41,15 @@ operator * (const FLOATNAME(LVector3) &v, const FLOATNAME(LMatrix4) &m);
INLINE_LINMATH FLOATNAME(LPoint3)
operator * (const FLOATNAME(LPoint3) &v, const FLOATNAME(LMatrix4) &m);
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LMatrix3) &value);
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LMatrix3) &result, DatagramIterator &source);
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LMatrix4) &value);
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LMatrix4) &result, DatagramIterator &source);
END_PUBLISH
#include "lmat_ops_src.I"

View File

@ -71,3 +71,22 @@ normalize(const FLOATNAME(LVector2) &v) {
v1.normalize();
return v1;
}
////////////////////////////////////////////////////////////////////
// Function: generic_write_datagram
// Description: Writes the value to the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LVecBase2) &value) {
value.write_datagram(dest);
}
////////////////////////////////////////////////////////////////////
// Function: generic_read_datagram
// Description: Reads the value from the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LVecBase2) &result, DatagramIterator &source) {
result.read_datagram(source);
}

View File

@ -46,6 +46,11 @@ length(const FLOATNAME(LVector2) &a);
INLINE_LINMATH FLOATNAME(LVector2)
normalize(const FLOATNAME(LVector2) &v);
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LVecBase2) &value);
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LVecBase2) &result, DatagramIterator &source);
#include "lvec2_ops_src.I"

View File

@ -97,3 +97,21 @@ normalize(const FLOATNAME(LVector3) &v) {
v1.normalize();
return v1;
}
////////////////////////////////////////////////////////////////////
// Function: generic_write_datagram
// Description: Writes the value to the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LVecBase3) &value) {
value.write_datagram(dest);
}
////////////////////////////////////////////////////////////////////
// Function: generic_read_datagram
// Description: Reads the value from the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LVecBase3) &result, DatagramIterator &source) {
result.read_datagram(source);
}

View File

@ -54,4 +54,9 @@ length(const FLOATNAME(LVector3) &a);
INLINE_LINMATH FLOATNAME(LVector3)
normalize(const FLOATNAME(LVector3) &v);
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LVecBase3) &value);
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LVecBase3) &result, DatagramIterator &source);
#include "lvec3_ops_src.I"

View File

@ -75,3 +75,21 @@ normalize(const FLOATNAME(LVector4) &v) {
v1.normalize();
return v1;
}
////////////////////////////////////////////////////////////////////
// Function: generic_write_datagram
// Description: Writes the value to the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LVecBase4) &value) {
value.write_datagram(dest);
}
////////////////////////////////////////////////////////////////////
// Function: generic_read_datagram
// Description: Reads the value from the datagram.
////////////////////////////////////////////////////////////////////
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LVecBase4) &result, DatagramIterator &source) {
result.read_datagram(source);
}

View File

@ -47,5 +47,10 @@ length(const FLOATNAME(LVector4) &a);
INLINE_LINMATH FLOATNAME(LVector4)
normalize(const FLOATNAME(LVector4) &v);
INLINE_LINMATH void
generic_write_datagram(Datagram &dest, const FLOATNAME(LVecBase4) &value);
INLINE_LINMATH void
generic_read_datagram(FLOATNAME(LVecBase4) &result, DatagramIterator &source);
#include "lvec4_ops_src.I"

View File

@ -46,5 +46,9 @@ ConfigureFn(config_mathutil) {
EventStoreVec2::init_type("EventStoreVec2");
EventStoreVec3::init_type("EventStoreVec3");
EventStoreMat4::init_type("EventStoreMat4");
EventStoreVec2::register_with_read_factory();
EventStoreVec3::register_with_read_factory();
EventStoreMat4::register_with_read_factory();
}

View File

@ -54,7 +54,9 @@ PUBLISHED:
bool open_read(const Filename &bam_filename, bool report_errors = true);
bool open_read(istream &in, const string &bam_filename = "stream",
bool report_errors = true);
TypedWritable *read_object();
bool is_eof() const;
bool resolve();

View File

@ -226,7 +226,6 @@ init_libpgraph() {
PosHprScaleLerpFunctor::init_type();
ColorLerpFunctor::init_type();
ColorScaleLerpFunctor::init_type();
EventStoreTransform::init_type();
AlphaTestAttrib::register_with_read_factory();
AmbientLight::register_with_read_factory();

View File

@ -141,8 +141,7 @@ void LensNode::
write_datagram(BamWriter *manager, Datagram &dg) {
PandaNode::write_datagram(manager, dg);
// We should actually write out the lens. Easy to do, but not
// immediately pressing; I hope no one gets burned by the omission.
manager->write_pointer(dg, _lens);
}
////////////////////////////////////////////////////////////////////
@ -155,7 +154,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
int LensNode::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = PandaNode::complete_pointers(p_list, manager);
_lens = DCAST(Lens, p_list[pi++]);
return pi;
}

View File

@ -2046,6 +2046,27 @@ write_datagram(BamWriter *manager, Datagram &dg) {
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::write_recorder
// Access: Public
// Description: This method is provided for the benefit of classes
// (like MouseRecorder) that inherit from PandaMode and
// also RecorderBase. It's not virtual at this level
// since it doesn't need to be (it's called up from the
// derived class).
//
// This method acts very like write_datagram, but it
// writes the node as appropriate for writing a
// RecorderBase object as described in the beginning of
// a session file, meaning it doesn't need to write
// things such as children. It balances with
// fillin_recorder().
////////////////////////////////////////////////////////////////////
void PandaNode::
write_recorder(BamWriter *, Datagram &dg) {
dg.add_string(get_name());
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::make_from_bam
// Access: Protected, Static
@ -2082,3 +2103,18 @@ fillin(DatagramIterator &scan, BamReader *manager) {
manager->read_cdata(scan, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::fillin_recorder
// Access: Protected
// Description: This internal function is called by make_recorder (in
// classes derived from RecorderBase, such as
// MouseRecorder) to read in all of the relevant data
// from the session file. It balances with
// write_recorder().
////////////////////////////////////////////////////////////////////
void PandaNode::
fillin_recorder(DatagramIterator &scan, BamReader *) {
string name = scan.get_string();
set_name(name);
}

View File

@ -376,10 +376,12 @@ public:
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
void write_recorder(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
void fillin_recorder(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {

View File

@ -582,34 +582,3 @@ is_destructing() const {
return false;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreTransform::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE EventStoreTransform::
EventStoreTransform(const TransformState *value) :
_value(value)
{
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreTransform::set_value
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EventStoreTransform::
set_value(const TransformState *value) {
_value = value;
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreTransform::get_value
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE const TransformState *EventStoreTransform::
get_value() const {
return _value;
}

View File

@ -27,7 +27,6 @@
TransformState::States *TransformState::_states = NULL;
CPT(TransformState) TransformState::_identity_state;
TypeHandle TransformState::_type_handle;
TypeHandle EventStoreTransform::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: TransformState::Constructor
@ -1326,13 +1325,3 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_mat.read_datagram(scan);
}
}
////////////////////////////////////////////////////////////////////
// Function: EventStoreTransform::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void EventStoreTransform::
output(ostream &out) const {
out << *_value;
}

View File

@ -244,40 +244,6 @@ INLINE ostream &operator << (ostream &out, const TransformState &state) {
return out;
}
////////////////////////////////////////////////////////////////////
// Class : EventStoreTransform
// Description : This class is used to pass TransformState pointers as
// parameters to events, or as elements on a data graph.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA EventStoreTransform : public EventStoreValueBase {
public:
INLINE EventStoreTransform(const TransformState *value);
INLINE void set_value(const TransformState *value);
INLINE const TransformState *get_value() const;
virtual void output(ostream &out) const;
CPT(TransformState) _value;
public:
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
EventStoreValueBase::init_type();
register_type(_type_handle, "EventStoreTransform",
EventStoreValueBase::get_class_type());
}
private:
static TypeHandle _type_handle;
};
#include "transformState.I"
#endif

View File

@ -22,20 +22,20 @@
#include "pandabase.h"
#include "mouseWatcherParameter.h"
#include "typedReferenceCount.h"
#include "typedWritableReferenceCount.h"
////////////////////////////////////////////////////////////////////
// Class : PGMouseWatcherParameter
// Description : This specialization on MouseWatcherParameter allows
// us to tag on additional elements to events for the
// gui system, and also inherits from
// TypedReferenceCount so we can attach this thing to an
// TypedWritableReferenceCount so we can attach this thing to an
// event.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PGMouseWatcherParameter : public TypedReferenceCount, public MouseWatcherParameter {
// For now, this must inherit from TypedReferenceCount on the left,
// because MSVC++ wants to make that base class be the one at the
// front of the structure, not MouseWatcherParameter for some
class EXPCL_PANDA PGMouseWatcherParameter : public TypedWritableReferenceCount, public MouseWatcherParameter {
// For now, this must inherit from TypedWritableReferenceCount on
// the left, because MSVC++ wants to make that base class be the one
// at the front of the structure, not MouseWatcherParameter for some
// reason, and interrogate assumes that whichever base class is on
// the left will be at the front of the structure.
public:
@ -52,9 +52,9 @@ public:
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "PGMouseWatcherParameter",
TypedReferenceCount::get_class_type());
TypedWritableReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -1,6 +1,6 @@
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#define LOCAL_LIBS express event pandabase
#define LOCAL_LIBS express pandabase
#begin lib_target
#define TARGET putil
@ -10,8 +10,7 @@
#define SOURCES \
bam.h bamReader.I bamReader.N bamReader.h bamReaderParam.I \
bamReaderParam.h bamWriter.I bamWriter.h bitMask.I \
bitMask.h buttonEvent.I buttonEvent.h \
buttonEventList.I buttonEventList.h \
bitMask.h \
buttonHandle.I \
buttonHandle.h buttonRegistry.I buttonRegistry.h \
collideMask.h \
@ -53,8 +52,6 @@
#define INCLUDED_SOURCES \
bamReader.cxx bamReaderParam.cxx bamWriter.cxx bitMask.cxx \
buttonEvent.cxx \
buttonEventList.cxx \
buttonHandle.cxx buttonRegistry.cxx \
config_util.cxx configurable.cxx \
cycleData.cxx \
@ -83,9 +80,7 @@
#define INSTALL_HEADERS \
bam.h bamReader.I bamReader.h bamReaderParam.I bamReaderParam.h \
bamWriter.I bamWriter.h bitMask.I bitMask.h buttonEvent.I \
buttonEvent.h \
buttonEventList.I buttonEventList.h \
bamWriter.I bamWriter.h bitMask.I bitMask.h \
buttonHandle.I buttonHandle.h buttonRegistry.I \
buttonRegistry.h collideMask.h \
compareTo.I compareTo.h \
@ -112,7 +107,8 @@
pipelineCycler.h pipelineCycler.I \
pipelineCyclerBase.h pipelineCyclerBase.I \
pta_double.h \
pta_float.h pta_int.h pta_ushort.h string_utils.I \
pta_float.h pta_int.h pta_ushort.h \
string_utils.I \
string_utils.h timedCycle.I timedCycle.h typedWritable.I \
typedWritable.h typedWritableReferenceCount.I \
typedWritableReferenceCount.h updateSeq.I updateSeq.h \

View File

@ -83,10 +83,11 @@ get_current_minor_ver() const {
// Description: Returns the global WritableFactory for generating
// TypedWritable objects
////////////////////////////////////////////////////////////////////
INLINE WritableFactory* BamReader::
INLINE WritableFactory *BamReader::
get_factory() {
if (_factory == NullFactory)
if (_factory == (WritableFactory *)NULL) {
create_factory();
}
return _factory;
}

View File

@ -25,6 +25,8 @@
#include "config_util.h"
#include "pipelineCyclerBase.h"
TypeHandle BamReader::_remove_flag;
WritableFactory *BamReader::_factory = (WritableFactory*)0L;
BamReader *const BamReader::Null = (BamReader*)0L;
WritableFactory *const BamReader::NullFactory = (WritableFactory*)0L;
@ -48,6 +50,8 @@ BamReader(DatagramGenerator *generator)
_now_creating = _created_objs.end();
_reading_cycler = (PipelineCyclerBase *)NULL;
_pta_id = -1;
_long_object_id = false;
_long_pta_id = false;
}
@ -78,7 +82,7 @@ init() {
return false;
}
if (!_source->get_datagram(header)) {
if (!get_datagram(header)) {
bam_cat.error()
<< "Unable to read Bam header.\n";
return false;
@ -124,6 +128,43 @@ init() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::set_aux_data
// Access: Public
// Description: Associates an arbitrary pointer to the bam reader
// with the indicated name. The name is an arbitrary
// user-defined key to access the data later. This data
// is typically queried by objects reading themselves
// from the bam file; this is intended to provide some
// context information to objects in the bam file. Set
// the aux data to NULL to remove it.
////////////////////////////////////////////////////////////////////
void BamReader::
set_aux_data(const string &name, void *data) {
if (data == (void *)NULL) {
_aux_data.erase(name);
} else {
_aux_data[name] = data;
}
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_aux_data
// Access: Public
// Description: Returns the pointer previously associated with the
// bam reader by a previous call to set_aux_data(), or
// NULL if the data with the indicated key has not been
// set.
////////////////////////////////////////////////////////////////////
void *BamReader::
get_aux_data(const string &name) const {
AuxData::const_iterator di = _aux_data.find(name);
if (di != _aux_data.end()) {
return (*di).second;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_object
// Access: Public
@ -237,6 +278,7 @@ resolve() {
CreatedObjs::iterator ci = _created_objs.find(object_id);
nassertr(ci != _created_objs.end(), false);
CreatedObj &created_obj = (*ci).second;
TypedWritable *object_ptr = created_obj._ptr;
@ -425,7 +467,7 @@ read_pointer(DatagramIterator &scan) {
int requestor_id = (*_now_creating).first;
// Read the object ID, and associate it with the requesting object.
int object_id = scan.get_uint16();
int object_id = read_object_id(scan);
if (_reading_cycler == (PipelineCyclerBase *)NULL) {
// This is not being read within a read_cdata() call.
@ -471,7 +513,7 @@ read_pointers(DatagramIterator &scan, int count) {
////////////////////////////////////////////////////////////////////
void BamReader::
skip_pointer(DatagramIterator &scan) {
scan.get_uint16();
read_object_id(scan);
}
////////////////////////////////////////////////////////////////////
@ -597,7 +639,7 @@ finalize_now(TypedWritable *whom) {
void *BamReader::
get_pta(DatagramIterator &scan) {
nassertr(_pta_id == -1, (void *)NULL);
int id = scan.get_uint16();
int id = read_pta_id(scan);
if (id == 0) {
// As always, a 0 ID indicates a NULL pointer. The caller will
@ -641,12 +683,92 @@ register_pta(void *ptr) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::free_object_ids
// Access: Private
// Description: Handles a record that begins with the _remove_flag
// TypeHandle; this contains a list of object ID's that
// will no longer be used in this file and can safely be
// removed.
////////////////////////////////////////////////////////////////////
void BamReader::
free_object_ids(DatagramIterator &scan) {
// We have to fully complete any objects before we remove them.
// Might as well try to complete everything before we get started.
resolve();
while (scan.get_remaining_size() > 0) {
int object_id = read_object_id(scan);
CreatedObjs::iterator ci = _created_objs.find(object_id);
if (ci == _created_objs.end()) {
util_cat.warning()
<< "Bam file suggests eliminating object_id " << object_id
<< ", already gone.\n";
} else {
// Make sure the object was successfully completed.
ObjectPointers::iterator oi = _object_pointers.find(object_id);
if (oi != _object_pointers.end()) {
util_cat.warning()
<< "Unable to resolve object " << object_id
<< " before removing from table.\n";
}
_created_objs.erase(ci);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_object_id
// Access: Private
// Description: Reads an object id from the datagram.
////////////////////////////////////////////////////////////////////
int BamReader::
read_object_id(DatagramIterator &scan) {
int object_id;
if (_long_object_id) {
object_id = scan.get_uint32();
} else {
object_id = scan.get_uint16();
if (object_id == 0xffff) {
_long_object_id = true;
}
}
return object_id;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_pta_id
// Access: Private
// Description: Reads an pta id from the datagram.
////////////////////////////////////////////////////////////////////
int BamReader::
read_pta_id(DatagramIterator &scan) {
int pta_id;
if (_long_pta_id) {
pta_id = scan.get_uint32();
} else {
pta_id = scan.get_uint16();
if (pta_id == 0xffff) {
_long_pta_id = true;
}
}
return pta_id;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::p_read_object
// Access: Private
// Description: The private implementation of read_object(), this
// Description: The private implementation of read_object(); this
// reads an object from the file and returns its object
// ID.
////////////////////////////////////////////////////////////////////
@ -654,14 +776,9 @@ int BamReader::
p_read_object() {
Datagram packet;
if (_source->is_error()) {
return 0;
}
// First, read a datagram for the object.
if (!_source->get_datagram(packet)) {
if (!get_datagram(packet)) {
// When we run out of datagrams, we're at the end of the file.
if (bam_cat.is_debug()) {
bam_cat.debug()
<< "Reached end of bam source.\n";
@ -678,10 +795,24 @@ p_read_object() {
// object.
TypeHandle type = read_handle(scan);
int object_id = scan.get_uint16();
// There are two cases. Either this is a new object definition, or
// this is a reference to an object that was previously defined.
if (type == _remove_flag) {
// The _remove_flag TypeHandle is a special case; it begins a
// record that simply lists all of the object ID's that are no
// longer important to the file and may be released.
free_object_ids(scan);
// Now that we've freed all of the object id's indicate, read the
// next object id in the stream. It's easiest to do this by
// calling recursively.
return p_read_object();
}
int object_id = read_object_id(scan);
// There are two cases (not counting the special _remove_flag case,
// above). Either this is a new object definition, or this is a
// reference to an object that was previously defined.
// We use the TypeHandle to differentiate these two cases. By
// convention, we write a TypeHandle::none() to the Bam file when we
@ -697,7 +828,7 @@ p_read_object() {
if (type != TypeHandle::none()) {
// Now we are going to read and create a new object.
// Defined the parameters for passing to the object factory.
// Define the parameters for passing to the object factory.
FactoryParams fparams;
fparams.add_param(new BamReaderParam(scan, this));
@ -796,7 +927,6 @@ resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids) {
// in, we can't resolve this object--we can't do anything for a
// given object until we have *all* outstanding pointers for
// that object.
bool is_complete = true;
vector_typedWritable references;
@ -932,3 +1062,18 @@ finalize() {
fi = _finalize_list.begin();
}
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_datagram
// Access: Private
// Description: Reads a single datagram from the stream. Returns
// true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool BamReader::
get_datagram(Datagram &datagram) {
if (_source->is_error()) {
return false;
}
return _source->get_datagram(datagram);
}

View File

@ -29,6 +29,7 @@
#include "factory.h"
#include "vector_int.h"
#include "pset.h"
#include "pmap.h"
#include "dcast.h"
#include <algorithm>
@ -92,11 +93,14 @@ public:
static WritableFactory *const NullFactory;
// The primary interface for a caller.
BamReader(DatagramGenerator *generator);
~BamReader();
bool init();
void set_aux_data(const string &name, void *data);
void *get_aux_data(const string &name) const;
TypedWritable *read_object();
INLINE bool is_eof() const;
bool resolve();
@ -107,6 +111,10 @@ public:
INLINE int get_current_major_ver() const;
INLINE int get_current_minor_ver() const;
// This special TypeHandle is written to the bam file to indicate an
// object id is no longer needed.
static TypeHandle _remove_flag;
public:
// Functions to support classes that read themselves from the Bam.
@ -135,15 +143,23 @@ private:
INLINE static void create_factory();
private:
void free_object_ids(DatagramIterator &scan);
int read_object_id(DatagramIterator &scan);
int read_pta_id(DatagramIterator &scan);
int p_read_object();
bool resolve_object_pointers(TypedWritable *object, const vector_int &pointer_ids);
bool resolve_cycler_pointers(PipelineCyclerBase *cycler, const vector_int &pointer_ids);
void finalize();
bool get_datagram(Datagram &datagram);
private:
static WritableFactory *_factory;
DatagramGenerator *_source;
bool _long_object_id;
bool _long_pta_id;
// This maps the type index numbers encountered within the Bam file
// to actual TypeHandles.
@ -202,6 +218,10 @@ private:
typedef pset<TypeHandle> NewTypes;
static NewTypes _new_types;
// This is used in support of set_aux_data() and get_aux_data().
typedef pmap<string, void *> AuxData;
AuxData _aux_data;
int _file_major, _file_minor;
static const int _cur_major;
static const int _cur_minor;

View File

@ -25,6 +25,8 @@
#include "bamWriter.h"
#include "bamReader.h"
#include <algorithm>
////////////////////////////////////////////////////////////////////
// Function: BamWriter::Constructor
// Access: Public
@ -43,6 +45,16 @@ BamWriter(DatagramSink *sink) :
////////////////////////////////////////////////////////////////////
BamWriter::
~BamWriter() {
// Tell all the TypedWritables whose pointer we are still keeping to
// forget about us.
StateMap::iterator si;
for (si = _state_map.begin(); si != _state_map.end(); ++si) {
TypedWritable *object = (TypedWritable *)(*si).first;
TypedWritable::BamWriters::iterator wi =
find(object->_bam_writers.begin(), object->_bam_writers.end(), this);
nassertv(wi != object->_bam_writers.end());
object->_bam_writers.erase(wi);
}
}
////////////////////////////////////////////////////////////////////
@ -60,7 +72,9 @@ init() {
// Initialize the next object and PTA ID's. These start counting at
// 1, since 0 is reserved for NULL.
_next_object_id = 1;
_long_object_id = false;
_next_pta_id = 1;
_long_pta_id = false;
// Write out the current major and minor BAM file version numbers.
Datagram header;
@ -105,6 +119,24 @@ write_object(const TypedWritable *object) {
int object_id = enqueue_object(object);
nassertr(object_id != 0, false);
// If there are any freed objects to indicate, write them out now.
if (!_freed_object_ids.empty()) {
Datagram dg;
write_handle(dg, BamReader::_remove_flag);
FreedObjectIds::iterator fi;
for (fi = _freed_object_ids.begin(); fi != _freed_object_ids.end(); ++fi) {
write_object_id(dg, (*fi));
}
_freed_object_ids.clear();
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write data to output.\n";
return false;
}
}
// Now we write out all the objects in the queue, in order. The
// first one on the queue will, of course, be this object we just
// queued up, but each object we write may append more to the queue.
@ -151,7 +183,7 @@ write_object(const TypedWritable *object) {
}
write_handle(dg, type);
dg.add_uint16(object_id);
write_object_id(dg, object_id);
// We cast the const pointer to non-const so that we may call
// write_datagram() on it. Really, write_datagram() should be a
@ -170,12 +202,12 @@ write_object(const TypedWritable *object) {
// BamReader that this is a previously-written object.
write_handle(dg, TypeHandle::none());
dg.add_uint16(object_id);
write_object_id(dg, object_id);
}
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write datagram to file.\n";
<< "Unable to write data to output.\n";
return false;
}
}
@ -215,7 +247,7 @@ write_pointer(Datagram &packet, const TypedWritable *object) {
// If the pointer is NULL, we always simply write a zero for an
// object ID and leave it at that.
if (object == (const TypedWritable *)NULL) {
packet.add_uint16(0);
write_object_id(packet, 0);
} else {
StateMap::iterator si = _state_map.find(object);
@ -223,12 +255,12 @@ write_pointer(Datagram &packet, const TypedWritable *object) {
// We have not written this pointer out yet. This means we must
// queue the object definition up for later.
int object_id = enqueue_object(object);
packet.add_uint16(object_id);
write_object_id(packet, object_id);
} else {
// We have already assigned this pointer an ID; thus, we can
// simply write out the ID.
packet.add_uint16((*si).second._object_id);
write_object_id(packet, (*si).second._object_id);
}
}
}
@ -273,7 +305,7 @@ register_pta(Datagram &packet, const void *ptr) {
if (ptr == (const void *)NULL) {
// A zero for the PTA ID indicates a NULL pointer. This is a
// special case.
packet.add_uint16(0);
write_pta_id(packet, 0);
// We return false to indicate the user must now write out the
// "definition" of the NULL pointer. This is necessary because of
@ -292,14 +324,10 @@ register_pta(Datagram &packet, const void *ptr) {
int pta_id = _next_pta_id;
_next_pta_id++;
// Make sure our PTA ID will fit within the PN_uint16 we have
// allocated for it.
nassertr(pta_id <= 65535, 0);
bool inserted = _pta_map.insert(PTAMap::value_type(ptr, pta_id)).second;
nassertr(inserted, false);
packet.add_uint16(pta_id);
write_pta_id(packet, pta_id);
// Return false to indicate the caller must now write out the
// array definition.
@ -308,7 +336,7 @@ register_pta(Datagram &packet, const void *ptr) {
} else {
// We have encountered this pointer before.
int pta_id = (*pi).second;
packet.add_uint16(pta_id);
write_pta_id(packet, pta_id);
// Return true to indicate the caller need do nothing further.
return true;
@ -336,7 +364,7 @@ write_handle(Datagram &packet, TypeHandle type) {
int index = type.get_index();
// Also make sure the index number fits within a PN_uint16.
nassertv(index <= 65535);
nassertv(index <= 0xffff);
packet.add_uint16(index);
@ -361,6 +389,70 @@ write_handle(Datagram &packet, TypeHandle type) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::object_destructs
// Access: Private
// Description: This is called by the TypedWritable destructor. It
// should remove the pointer from any structures that
// keep a reference to it, and also write a flag to the
// bam file (if it is open) so that a reader will know
// the object id will no longer be used.
////////////////////////////////////////////////////////////////////
void BamWriter::
object_destructs(TypedWritable *object) {
StateMap::iterator si = _state_map.find(object);
if (si != _state_map.end()) {
// We ought to have written out the object by the time it
// destructs, or we're in trouble when we do write it out.
nassertv((*si).second._written);
int object_id = (*si).second._object_id;
_freed_object_ids.push_back(object_id);
_state_map.erase(si);
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_object_id
// Access: Private
// Description: Writes the indicated object id to the datagram.
////////////////////////////////////////////////////////////////////
void BamWriter::
write_object_id(Datagram &dg, int object_id) {
if (_long_object_id) {
dg.add_uint32(object_id);
} else {
dg.add_uint16(object_id);
// Once we fill up our uint16, we write all object id's
// thereafter with a uint32.
if (object_id == 0xffff) {
_long_object_id = true;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_pta_id
// Access: Private
// Description: Writes the indicated pta id to the datagram.
////////////////////////////////////////////////////////////////////
void BamWriter::
write_pta_id(Datagram &dg, int pta_id) {
if (_long_pta_id) {
dg.add_uint32(pta_id);
} else {
dg.add_uint16(pta_id);
// Once we fill up our uint16, we write all pta id's
// thereafter with a uint32.
if (pta_id == 0xffff) {
_long_pta_id = true;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::enqueue_object
// Access: Private
@ -392,28 +484,22 @@ enqueue_object(const TypedWritable *object) {
// We need to assign a unique index number to every object we write
// out. Has this object been assigned a number yet?
int object_id;
// bool already_written;
StateMap::iterator si = _state_map.find(object);
if (si == _state_map.end()) {
// No, it hasn't, so assign it the next number in sequence
// arbitrarily.
object_id = _next_object_id;
// already_written = false;
// Make sure our object ID will fit within the PN_uint16 we have
// allocated for it.
nassertr(object_id <= 65535, 0);
bool inserted =
_state_map.insert(StateMap::value_type(object, StoreState(_next_object_id))).second;
nassertr(inserted, false);
((TypedWritable *)object)->_bam_writers.push_back(this);
_next_object_id++;
} else {
// Yes, it has; get the object ID.
object_id = (*si).second._object_id;
// already_written = (*si).second._written;
}
_object_queue.push_back(object);

View File

@ -25,6 +25,9 @@
#include "typedWritable.h"
#include "datagramSink.h"
#include "pdeque.h"
#include "pset.h"
#include "pmap.h"
#include "vector_int.h"
struct PipelineCyclerBase;
@ -71,7 +74,7 @@ struct PipelineCyclerBase;
// See also BamFile, which defines a higher-level
// interface to read and write Bam files on disk.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA BamWriter{
class EXPCL_PANDA BamWriter {
public:
BamWriter(DatagramSink *sink);
~BamWriter();
@ -90,11 +93,12 @@ public:
bool register_pta(Datagram &packet, const void *ptr);
void write_handle(Datagram &packet, TypeHandle type);
private:
int enqueue_object(const TypedWritable *object);
void object_destructs(TypedWritable *object);
void write_object_id(Datagram &dg, int object_id);
void write_pta_id(Datagram &dg, int pta_id);
int enqueue_object(const TypedWritable *object);
// This is the set of all TypeHandles already written.
pset<int> _types_written;
@ -114,20 +118,30 @@ private:
// This is the next object ID that will be assigned to a new object.
int _next_object_id;
bool _long_object_id;
// This is the queue of objects that need to be written when the
// current object is finished.
typedef pdeque<const TypedWritable *> ObjectQueue;
ObjectQueue _object_queue;
// This is the set of object_id's that we won't be using any more;
// we'll encode this set into the bam stream so the BamReader will
// be able to clean up its internal structures.
typedef vector_int FreedObjectIds;
FreedObjectIds _freed_object_ids;
// These are used by register_pta() to unify multiple references to
// the same PointerToArray.
typedef pmap<const void *, int> PTAMap;
PTAMap _pta_map;
int _next_pta_id;
bool _long_pta_id;
// The destination to write all the output to.
DatagramSink *_target;
friend class TypedWritable;
};
#include "bamWriter.I"

View File

@ -1,45 +0,0 @@
// Filename: buttonEvent.cxx
// Created by: drose (01Mar00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "buttonEvent.h"
////////////////////////////////////////////////////////////////////
// Function: ButtonEvent::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEvent::
output(ostream &out) const {
switch (_type) {
case T_down:
out << "button " << _button << " down";
break;
case T_resume_down:
out << "button " << _button << " resume down";
break;
case T_up:
out << "button " << _button << " up";
break;
case T_keystroke:
out << "keystroke " << _keycode;
break;
}
}

View File

@ -1,74 +0,0 @@
// Filename: buttonEventList.cxx
// Created by: drose (12Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "buttonEventList.h"
#include "modifierButtons.h"
#include "indent.h"
TypeHandle ButtonEventList::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::update_mods
// Access: Public
// Description: Updates the indicated ModifierButtons object with all
// of the button up/down transitions indicated in the
// list.
////////////////////////////////////////////////////////////////////
void ButtonEventList::
update_mods(ModifierButtons &mods) const {
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
mods.add_event(*ei);
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEventList::
output(ostream &out) const {
if (_events.empty()) {
out << "(no buttons)";
} else {
Events::const_iterator ei;
ei = _events.begin();
out << "(" << (*ei);
++ei;
while (ei != _events.end()) {
out << " " << (*ei);
++ei;
}
out << ")";
}
}
////////////////////////////////////////////////////////////////////
// Function: ButtonEventList::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void ButtonEventList::
write(ostream &out, int indent_level) const {
indent(out, indent_level) << _events.size() << " events:\n";
Events::const_iterator ei;
for (ei = _events.begin(); ei != _events.end(); ++ei) {
indent(out, indent_level + 2) << (*ei) << "\n";
}
}

View File

@ -18,7 +18,6 @@
#include "config_util.h"
#include "bamReaderParam.h"
#include "buttonEventList.h"
#include "clockObject.h"
#include "configurable.h"
#include "datagram.h"
@ -43,7 +42,6 @@ NotifyCategoryDef(bam, util_cat);
ConfigureFn(config_util) {
BamReaderParam::init_type();
ButtonEventList::init_type();
Configurable::init_type();
Datagram::init_type();
FactoryParam::init_type();
@ -58,6 +56,8 @@ ConfigureFn(config_util) {
KeyboardButton::init_keyboard_buttons();
MouseButton::init_mouse_buttons();
register_type(BamReader::_remove_flag, "remove");
}

View File

@ -23,14 +23,9 @@
#include "config_util.h"
#include "config_express.h"
#include "virtualFileSystem.h"
#include "streamReader.h"
#include "datagramInputFile.h"
//#define SKYLER_TIMER 1
#ifdef SKYLER_TIMER //[
EXPCL_PANDAEXPRESS ProfileTimer Skyler_timer_file;
#endif //]
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::open
// Access: Public
@ -135,26 +130,22 @@ read_header(string &header, size_t num_bytes) {
////////////////////////////////////////////////////////////////////
bool DatagramInputFile::
get_datagram(Datagram &data) {
#ifdef SKYLER_TIMER //[
Skyler_timer_file.on();
#endif //]
nassertr(_in != (istream *)NULL, false);
_read_first_datagram = true;
// First, get the size of the upcoming datagram. We do this with
// the help of a second datagram.
char sizebuf[sizeof(PN_uint32)];
_in->read(sizebuf, sizeof(PN_uint32));
// First, get the size of the upcoming datagram.
StreamReader reader(_in, false);
PN_uint32 num_bytes = reader.get_uint32();
if (_in->fail() || _in->eof()) {
#ifdef SKYLER_TIMER //[
Skyler_timer_file.off("DatagramInputFile::get_datagram");
#endif //]
return false;
}
Datagram size(sizebuf, sizeof(PN_uint32));
DatagramIterator di(size);
PN_uint32 num_bytes = di.get_uint32();
if (num_bytes == 0) {
// A special case for a zero-length datagram: no need to try to
// read any data.
data.clear();
return true;
}
// Now, read the datagram itself.
char *buffer = new char[num_bytes];
@ -164,17 +155,12 @@ get_datagram(Datagram &data) {
if (_in->fail() || _in->eof()) {
_error = true;
delete[] buffer;
#ifdef SKYLER_TIMER //[
Skyler_timer_file.off("DatagramInputFile::get_datagram");
#endif //]
return false;
}
data = Datagram(buffer, num_bytes);
delete[] buffer;
#ifdef SKYLER_TIMER //[
Skyler_timer_file.off("DatagramInputFile::get_datagram");
#endif //]
return true;
}

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "datagramOutputFile.h"
#include "streamWriter.h"
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::open
@ -103,11 +104,9 @@ put_datagram(const Datagram &data) {
nassertr(_out != (ostream *)NULL, false);
_wrote_first_datagram = true;
// First, write the size of the upcoming datagram. We do this with
// the help of a second datagram.
Datagram size;
size.add_uint32(data.get_length());
_out->write((const char *)size.get_data(), size.get_length());
// First, write the size of the upcoming datagram.
StreamWriter writer(_out);
writer.add_uint32(data.get_length());
// Now, write the datagram itself.
_out->write((const char *)data.get_data(), data.get_length());

View File

@ -92,26 +92,6 @@ get_button(int index) const {
return _button_list[index];
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::add_event
// Access: Published
// Description: Calls button_down() or button_up(), as appropriate,
// according to the indicated ButtonEvent.
////////////////////////////////////////////////////////////////////
INLINE bool ModifierButtons::
add_event(const ButtonEvent &event) {
switch (event._type) {
case ButtonEvent::T_down:
return button_down(event._button);
case ButtonEvent::T_up:
return button_up(event._button);
default:
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: ModifierButtons::all_buttons_up
// Access: Published

View File

@ -23,7 +23,6 @@
#include "buttonHandle.h"
#include "pointerToArray.h"
#include "buttonEvent.h"
////////////////////////////////////////////////////////////////////
// Class : ModifierButtons
@ -53,7 +52,6 @@ PUBLISHED:
bool button_down(ButtonHandle button);
bool button_up(ButtonHandle button);
INLINE bool add_event(const ButtonEvent &event);
INLINE void all_buttons_up();
bool is_down(ButtonHandle button) const;

View File

@ -2,8 +2,6 @@
#include "bamReaderParam.cxx"
#include "bamWriter.cxx"
#include "bitMask.cxx"
#include "buttonEvent.cxx"
#include "buttonEventList.cxx"
#include "buttonHandle.cxx"
#include "buttonRegistry.cxx"
#include "config_util.cxx"

View File

@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////
#include "typedWritable.h"
#include "bamWriter.h"
TypeHandle TypedWritable::_type_handle;
TypedWritable* const TypedWritable::Null = (TypedWritable*)0L;
@ -26,7 +27,14 @@ TypedWritable* const TypedWritable::Null = (TypedWritable*)0L;
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
TypedWritable::~TypedWritable() {
TypedWritable::
~TypedWritable() {
// Remove the object pointer from the BamWriters that reference it.
BamWriters::iterator wi;
for (wi = _bam_writers.begin(); wi != _bam_writers.end(); ++wi) {
BamWriter *writer = (*wi);
writer->object_destructs(this);
}
}
////////////////////////////////////////////////////////////////////

View File

@ -21,6 +21,7 @@
#include "typedObject.h"
#include "vector_typedWritable.h"
#include "pvector.h"
class BamReader;
class BamWriter;
@ -32,7 +33,7 @@ class DatagramIterator;
// Description : Base class for objects that can be written to and
// read from Bam files.
//
// See Also TypeObject for detailed instructions.
// See also TypedObject for detailed instructions.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TypedWritable : public TypedObject {
@ -54,6 +55,13 @@ public:
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
private:
// We need to store a list of the BamWriter(s) that have a reference
// to this object, so that we can remove the object from those
// tables when it destructs.
typedef pvector<BamWriter *> BamWriters;
BamWriters _bam_writers;
PUBLISHED:
static TypeHandle get_class_type() {
return _type_handle;
@ -76,6 +84,8 @@ public:
private:
static TypeHandle _type_handle;
friend class BamWriter;
};
#include "typedWritable.I"

View File

@ -34,7 +34,7 @@
// pass around pointers to things which are both
// TypedWritables and ReferenceCounters.
//
// See Also TypeObject for detailed instructions.
// See also TypedObject for detailed instructions.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TypedWritableReferenceCount : public TypedWritable, public ReferenceCount {
public:
@ -42,9 +42,6 @@ public:
INLINE TypedWritableReferenceCount(const TypedWritableReferenceCount &copy);
INLINE void operator = (const TypedWritableReferenceCount &copy);
public:
virtual void write_datagram(BamWriter *, Datagram &) = 0;
public:
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -0,0 +1,38 @@
#define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
dtoolutil:c dtoolbase:c dtool:m
#define LOCAL_LIBS dgraph putil express pandabase
#begin lib_target
#define TARGET recorder
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
config_recorder.h \
mouseRecorder.h \
recorderBase.h recorderBase.I \
recorderController.h recorderController.I \
recorderFrame.h recorderFrame.I \
recorderHeader.h recorderHeader.I \
recorderTable.h recorderTable.I \
socketStreamRecorder.h socketStreamRecorder.I
#define INCLUDED_SOURCES \
config_recorder.cxx \
mouseRecorder.cxx \
recorderBase.cxx recorderController.cxx \
recorderFrame.cxx recorderHeader.cxx recorderTable.cxx \
socketStreamRecorder.cxx
#define INSTALL_HEADERS \
mouseRecorder.h \
recorderBase.h recorderBase.I \
recorderController.h recorderController.I \
recorderFrame.h recorderFrame.I \
recorderHeader.h recorderHeader.I \
recorderTable.h recorderTable.I \
socketStreamRecorder.h socketStreamRecorder.I
#define IGATESCAN all
#end lib_target

View File

@ -0,0 +1,47 @@
// Filename: config_recorder.cxx
// Created by: drose (28Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "config_recorder.h"
#include "mouseRecorder.h"
#include "recorderController.h"
#include "recorderFrame.h"
#include "recorderHeader.h"
#include "recorderTable.h"
#include "socketStreamRecorder.h"
#include "dconfig.h"
ConfigureDef(config_recorder);
NotifyCategoryDef(recorder, "");
ConfigureFn(config_recorder) {
MouseRecorder::init_type();
RecorderController::init_type();
RecorderFrame::init_type();
RecorderHeader::init_type();
RecorderTable::init_type();
ReferenceCount::init_type();
SocketStreamRecorder::init_type();
MouseRecorder::register_with_read_factory();
RecorderFrame::register_with_read_factory();
RecorderHeader::register_with_read_factory();
RecorderTable::register_with_read_factory();
SocketStreamRecorder::register_with_read_factory();
}

View File

@ -0,0 +1,29 @@
// Filename: config_recorder.h
// Created by: drose (28Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef CONFIG_RECORDER_H
#define CONFIG_RECORDER_H
#include "pandabase.h"
#include "notifyCategoryProxy.h"
#include "dconfig.h"
ConfigureDecl(config_recorder, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDecl(recorder, EXPCL_PANDA, EXPTP_PANDA);
#endif // CONFIG_RECORDER_H

View File

@ -0,0 +1,297 @@
// Filename: mouseRecorder.cxx
// Created by: drose (24Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "mouseRecorder.h"
#include "recorderController.h"
#include "dataNodeTransmit.h"
#include "bamReader.h"
#include "bamWriter.h"
TypeHandle MouseRecorder::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
MouseRecorder::
MouseRecorder(const string &name) :
DataNode(name)
{
_pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
_xy_input = define_input("xy", EventStoreVec2::get_class_type());
_button_events_input = define_input("button_events", ButtonEventList::get_class_type());
_pixel_xy_output = define_output("pixel_xy", EventStoreVec2::get_class_type());
_xy_output = define_output("xy", EventStoreVec2::get_class_type());
_button_events_output = define_output("button_events", ButtonEventList::get_class_type());
_live_button_events = new ButtonEventList;
_save_button_events = new ButtonEventList;
_pixel_xy = new EventStoreVec2(LPoint2f(0.0f, 0.0f));
_xy = new EventStoreVec2(LPoint2f(0.0f, 0.0f));
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
MouseRecorder::
~MouseRecorder() {
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::record_frame
// Access: Public, Virtual
// Description: Records the most recent data collected into the
// indicated datagram, and returns true if there is any
// interesting data worth recording, or false if the
// datagram is meaningless.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
record_frame(BamWriter *manager, Datagram &dg) {
nassertv(is_recording());
dg.add_bool(_has_mouse);
if (_has_mouse) {
_mouse_xy.write_datagram(dg);
_mouse_pixel_xy.write_datagram(dg);
}
_save_button_events->write_datagram(manager, dg);
_save_button_events->clear();
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::play_frame
// Access: Public, Virtual
// Description: Reloads the most recent data collected from the
// indicated datagram.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
play_frame(DatagramIterator &scan, BamReader *manager) {
nassertv(is_playing());
_has_mouse = scan.get_bool();
if (_has_mouse) {
_mouse_xy.read_datagram(scan);
_mouse_pixel_xy.read_datagram(scan);
}
ButtonEventList button_events;
button_events.fillin(scan, manager);
_save_button_events->add_events(button_events);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void MouseRecorder::
output(ostream &out) const {
DataNode::output(out);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::write
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void MouseRecorder::
write(ostream &out, int indent_level) const {
DataNode::write(out, indent_level);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::do_transmit_data
// Access: Protected, Virtual
// Description: The virtual implementation of transmit_data(). This
// function receives an array of input parameters and
// should generate an array of output parameters. The
// input parameters may be accessed with the index
// numbers returned by the define_input() calls that
// were made earlier (presumably in the constructor);
// likewise, the output parameters should be set with
// the index numbers returned by the define_output()
// calls.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
bool has_mouse = false;
LPoint2f mouse_xy;
LPoint2f mouse_pixel_xy;
_live_button_events->clear();
if (is_playing()) {
// If we're playing back data, copy in the data from a previous
// call to play_frame().
has_mouse = _has_mouse;
mouse_xy = _mouse_xy;
mouse_pixel_xy = _mouse_pixel_xy;
_live_button_events->add_events(*_save_button_events);
_save_button_events->clear();
} else {
// If we're not playing back data, query the data from the data
// graph
if (input.has_data(_xy_input)) {
// The mouse is within the window. Get the current mouse position.
const EventStoreVec2 *xy;
DCAST_INTO_V(xy, input.get_data(_xy_input).get_ptr());
mouse_xy = xy->get_value();
DCAST_INTO_V(xy, input.get_data(_pixel_xy_input).get_ptr());
mouse_pixel_xy = xy->get_value();
has_mouse = true;
}
// Look for button events.
if (input.has_data(_button_events_input)) {
const ButtonEventList *button_events;
DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
_live_button_events->add_events(*button_events);
}
}
// Now rebuild the output data for our children.
if (has_mouse) {
// Transmit the mouse position.
_pixel_xy->set_value(_mouse_pixel_xy);
_xy->set_value(_mouse_xy);
output.set_data(_xy_output, EventParameter(_xy));
output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
}
if (_live_button_events->get_num_events() != 0) {
output.set_data(_button_events_output, EventParameter(_live_button_events));
}
if (is_recording()) {
// Save data for the record.
_has_mouse = has_mouse;
_mouse_xy = mouse_xy;
_mouse_pixel_xy = mouse_pixel_xy;
_save_button_events->add_events(*_live_button_events);
}
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// Lens.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
RecorderController::get_factory()->register_factory(get_class_type(), make_recorder);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
write_datagram(BamWriter *manager, Datagram &dg) {
DataNode::write_datagram(manager, dg);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::write_recorder
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for encoding in the session file. This is very
// similar to write_datagram() for TypedWritable
// objects, but it is used specifically to write the
// Recorder object when generating the session file. In
// many cases, it will be the same as write_datagram().
////////////////////////////////////////////////////////////////////
void MouseRecorder::
write_recorder(BamWriter *manager, Datagram &dg) {
RecorderBase::write_recorder(manager, dg);
DataNode::write_recorder(manager, dg);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type Lens is encountered
// in the Bam file. It should create the Lens
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *MouseRecorder::
make_from_bam(const FactoryParams &params) {
MouseRecorder *node = new MouseRecorder("");
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
node->fillin(scan, manager);
return node;
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::make_recorder
// Access: Protected, Static
// Description: This is similar to make_from_bam(), but it is
// designed for loading the RecorderBase object from the
// session log created by a RecorderController.
////////////////////////////////////////////////////////////////////
RecorderBase *MouseRecorder::
make_recorder(const FactoryParams &params) {
MouseRecorder *node = new MouseRecorder("");
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
node->fillin_recorder(scan, manager);
return node;
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new MouseRecorder.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
fillin(DatagramIterator &scan, BamReader *manager) {
DataNode::fillin(scan, manager);
}
////////////////////////////////////////////////////////////////////
// Function: MouseRecorder::fillin_recorder
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new MouseRecorder.
////////////////////////////////////////////////////////////////////
void MouseRecorder::
fillin_recorder(DatagramIterator &scan, BamReader *manager) {
RecorderBase::fillin_recorder(scan, manager);
DataNode::fillin_recorder(scan, manager);
}

View File

@ -0,0 +1,112 @@
// Filename: mouseRecorder.h
// Created by: drose (25Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef MOUSERECORDER_H
#define MOUSERECORDER_H
#include "recorderBase.h"
#include "dataNode.h"
#include "dataNodeTransmit.h"
#include "linmath_events.h"
#include "buttonEventList.h"
class FactoryParams;
class BamReader;
class BamWriter;
////////////////////////////////////////////////////////////////////
// Class : MouseRecorder
// Description : This object records any data generated by a
// particular MouseAndKeyboard node on the datagraph for
// a session for eventual playback via a
// DataGraphPlayback (and a PlaybackController). To use
// it, make it a child of the node you wish to record.
// It also serves as a pass-through, so that additional
// child nodes may be parented directly to it.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA MouseRecorder : public DataNode, public RecorderBase {
PUBLISHED:
MouseRecorder(const string &name);
virtual ~MouseRecorder();
public:
virtual void record_frame(BamWriter *manager, Datagram &dg);
virtual void play_frame(DatagramIterator &scan, BamReader *manager);
public:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level = 0) const;
protected:
// Inherited from DataNode
virtual void do_transmit_data(const DataNodeTransmit &input,
DataNodeTransmit &output);
private:
// inputs
int _pixel_xy_input;
int _xy_input;
int _button_events_input;
// outputs
int _pixel_xy_output;
int _xy_output;
int _button_events_output;
bool _has_mouse;
LPoint2f _mouse_xy;
LPoint2f _mouse_pixel_xy;
PT(ButtonEventList) _live_button_events;
PT(ButtonEventList) _save_button_events;
PT(EventStoreVec2) _pixel_xy;
PT(EventStoreVec2) _xy;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual void write_recorder(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
static RecorderBase *make_recorder(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
void fillin_recorder(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
DataNode::init_type();
RecorderBase::init_type();
register_type(_type_handle, "MouseRecorder",
DataNode::get_class_type(),
RecorderBase::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#endif

View File

@ -0,0 +1,43 @@
// Filename: recorderBase.I
// Created by: drose (24Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::is_recording
// Access: Published
// Description: Returns true if this recorder is presently recording
// data for saving to a session file, false otherwise.
// If this is true, record_data() will be called from
// time to time.
////////////////////////////////////////////////////////////////////
INLINE bool RecorderBase::
is_recording() const {
return (_flags & F_recording) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::is_playing
// Access: Published
// Description: Returns true if this recorder is presently playing back
// data from session file, false otherwise. If this is
// true, play_data() will be called from time to time.
////////////////////////////////////////////////////////////////////
INLINE bool RecorderBase::
is_playing() const {
return (_flags & F_playing) != 0;
}

View File

@ -0,0 +1,89 @@
// Filename: recorderBase.cxx
// Created by: drose (24Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "recorderBase.h"
TypeHandle RecorderBase::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
RecorderBase::
RecorderBase() {
_flags = 0;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
RecorderBase::
~RecorderBase() {
nassertv(_flags == 0);
}
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::record_frame
// Access: Public, Virtual
// Description: Records the most recent data collected into the
// indicated datagram.
////////////////////////////////////////////////////////////////////
void RecorderBase::
record_frame(BamWriter *, Datagram &) {
}
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::play_frame
// Access: Public, Virtual
// Description: Reloads the most recent data collected from the
// indicated datagram.
////////////////////////////////////////////////////////////////////
void RecorderBase::
play_frame(DatagramIterator &scan, BamReader *manager) {
}
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::write_recorder
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for encoding in the session file. This is very
// similar to write_datagram() for TypedWritable
// objects, but it is used specifically to write the
// Recorder object when generating the session file. In
// many cases, it will be the same as write_datagram().
//
// This balances with fillin_recorder().
////////////////////////////////////////////////////////////////////
void RecorderBase::
write_recorder(BamWriter *, Datagram &) {
}
////////////////////////////////////////////////////////////////////
// Function: RecorderBase::fillin_recorder
// Access: Protected
// Description: This internal function is called by make_recorder (in
// derived classes) to read in all of the relevant data
// from the session file. It balances with
// write_recorder().
////////////////////////////////////////////////////////////////////
void RecorderBase::
fillin_recorder(DatagramIterator &, BamReader *) {
}

View File

@ -0,0 +1,102 @@
// Filename: recorderBase.h
// Created by: drose (25Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef RECORDERBASE_H
#define RECORDERBASE_H
#include "pandabase.h"
#include "referenceCount.h"
class BamReader;
class BamWriter;
class Datagram;
class DatagramIterator;
class TypedWritable;
////////////////////////////////////////////////////////////////////
// Class : RecorderBase
// Description : This is the base class to a number of objects that
// record particular kinds of user input (like a
// MouseRecorder) to use in conjunction with a
// RecorderController to record the user's inputs
// for a session.
//
// Note that RecorderBase does not actually inherit from
// TypedObject, even though it defines get_type(). The
// assumption is that the classes that derive from
// RecorderBase might also inherit independently from
// TypedObject.
//
// It also does not inherit from TypedWritable, but it
// defines a method called write_recorder() which is
// very similar to a TypedWritable's write_datagram().
// Classes that derive from RecorderBase and also
// inherit from TypedWritable may choose to remap
// write_recorder() to do exactly the same thing as
// write_datagram(), or they may choose to write
// something slightly different.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA RecorderBase : virtual public ReferenceCount {
protected:
RecorderBase();
PUBLISHED:
virtual ~RecorderBase();
INLINE bool is_recording() const;
INLINE bool is_playing() const;
public:
virtual void record_frame(BamWriter *manager, Datagram &dg);
virtual void play_frame(DatagramIterator &scan, BamReader *manager);
virtual void write_recorder(BamWriter *manager, Datagram &dg);
protected:
void fillin_recorder(DatagramIterator &scan, BamReader *manager);
private:
enum Flags {
F_recording = 0x0001,
F_playing = 0x0002,
};
short _flags;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ReferenceCount::init_type();
register_type(_type_handle, "RecorderBase",
ReferenceCount::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
private:
static TypeHandle _type_handle;
friend class RecorderController;
};
#include "recorderBase.I"
#endif

View File

@ -0,0 +1,294 @@
// Filename: recorderController.I
// Created by: drose (24Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_start_time
// Access: Published
// Description: Returns the time (and date) at which the current
// session was originally recorded (or, in recording
// mode, the time at which the current session began).
////////////////////////////////////////////////////////////////////
INLINE time_t RecorderController::
get_start_time() const {
return _header._start_time;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::set_random_seed
// Access: Published
// Description: Indicates an arbitrary number to be recorded in the
// session file as a random seed, should the application
// wish to take advantage of it. This must be set
// before begin_record() is called.
////////////////////////////////////////////////////////////////////
INLINE void RecorderController::
set_random_seed(int random_seed) {
_header._random_seed = random_seed;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_random_seed
// Access: Published
// Description: Returns the random seed that was set by a previous
// call to set_random_seed(), or the number read from
// the session file after begin_playback() has been
// called.
////////////////////////////////////////////////////////////////////
INLINE int RecorderController::
get_random_seed() const {
return _header._random_seed;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::is_recording
// Access: Published
// Description: Returns true if the controller has been opened for
// output, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
is_recording() const {
return (_writer != (BamWriter *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::is_playing
// Access: Published
// Description: Returns true if the controller has been opened for
// input, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
is_playing() const {
return (_reader != (BamReader *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::is_open
// Access: Published
// Description: Returns true if the controller has been opened for
// either input or output, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
is_open() const {
return is_recording() || is_playing();
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_filename
// Access: Published
// Description: Returns the filename that was passed to the most
// recent call to begin_record() or begin_playback().
////////////////////////////////////////////////////////////////////
INLINE const Filename &RecorderController::
get_filename() const {
return _filename;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::is_error
// Access: Published
// Description: Returns true if the controller has been opened for
// input or output output and there is an error on the
// stream, or false if the controller is closed or if
// there is no problem.
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
is_error() {
return _dout.is_error() || _din.is_error();
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_clock_offset
// Access: Published
// Description: Returns the delta offset between the actual frame
// time and the frame time written to the log. This is
// essentially the time at which the recording (or
// playback) started.
////////////////////////////////////////////////////////////////////
INLINE double RecorderController::
get_clock_offset() const {
return _clock_offset;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_frame_offset
// Access: Published
// Description: Returns the delta offset between the actual frame
// count and the frame count written to the log. This is
// essentially the frame number at which the recording
// (or playback) started.
////////////////////////////////////////////////////////////////////
INLINE int RecorderController::
get_frame_offset() const {
return _frame_offset;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::add_recorder
// Access: Published
// Description: Adds the named recorder to the set of recorders that
// are in use.
//
// If the controller is in recording mode, the named
// recorder will begin recording its status to the
// session file. If the controller is in playback mode
// and the name and type matches a recorder in the
// session file, the recorder will begin receiving data.
////////////////////////////////////////////////////////////////////
INLINE void RecorderController::
add_recorder(const string &name, RecorderBase *recorder) {
_user_table->add_recorder(name, recorder);
_user_table_modified = true;
// We can only add the state flag immediately if we are in recording
// mode. In playback mode, we're not sure yet whether the new
// recorder state will actually be playing (we won't know until we
// merge the tables in play_frame()).
if (is_recording()) {
recorder->_flags |= RecorderBase::F_recording;
}
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::has_recorder
// Access: Published
// Description: Returns true if the named recorder has been added to
// the table by a previous call to add_recorder(), false
// otherwise.
//
// If the controller is in playback mode, this will also
// return false for a recorder that was found in the
// session file but was never explicitly added via
// add_recorder(); see get_recorder().
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
has_recorder(const string &name) const {
return (_user_table->get_recorder(name) != (RecorderBase *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_recorder
// Access: Published
// Description: Returns the recorder with the indicated name, or NULL
// if there is no such recorder.
//
// If the controller is in playback mode, this may
// return the recorder matching the indicated name as
// read from the session file, even if it was never
// added to the table by the user. In this case,
// has_recorder() may return false, but get_recorder()
// will return a non-NULL value.
////////////////////////////////////////////////////////////////////
INLINE RecorderBase *RecorderController::
get_recorder(const string &name) const {
RecorderBase *recorder = _user_table->get_recorder(name);
if (is_playing() && recorder == (RecorderBase *)NULL) {
recorder = _active_table->get_recorder(name);
}
return recorder;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::remove_recorder
// Access: Published
// Description: Removes the named recorder from the table. Returns
// true if successful, false if there was no such
// recorder.
//
// If the controller is in recording mode, the named
// recorder will stop recording. If the controller is
// in playback mode, the named recorder will
// disassociate itself from the session file (but if the
// session file still has data for this name, a default
// recorder will take its place to decode the data from
// the session file).
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
remove_recorder(const string &name) {
// If we are playing or recording, immediately remove the state flag
// from the recorder. (When we are playing, the state flag will get
// removed automatically at the next call to play_frame(), but we
// might as well be aggressive and remove it now. When we are
// recording, we have to remove it now.)
if (is_recording() || is_playing()) {
RecorderBase *recorder = _user_table->get_recorder(name);
if (recorder != (RecorderBase *)NULL) {
recorder->_flags &= ~(RecorderBase::F_recording | RecorderBase::F_playing);
}
}
_user_table_modified = true;
return _user_table->remove_recorder(name);
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::set_frame_tie
// Access: Published
// Description: Sets the frame_tie flag.
//
// When this is true, sessions are played back
// frame-for-frame, based on the frame count of the
// recorded session. This gives the most accurate
// playback, but the playback rate will vary according
// to the frame rate of the playback machine.
//
// When this is false, sessions are played back at real
// time, based on the clock of the recorded session.
// This may introduce playback discrepencies if the
// frames do not fall at exactly the same times as they
// did in the original.
////////////////////////////////////////////////////////////////////
INLINE void RecorderController::
set_frame_tie(bool frame_tie) {
_frame_tie = frame_tie;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_frame_tie
// Access: Published
// Description: See set_frame_tie().
////////////////////////////////////////////////////////////////////
INLINE bool RecorderController::
get_frame_tie() const {
return _frame_tie;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::get_factory
// Access: Public, Static
// Description: Returns the global RecorderFactory for generating
// TypedWritable objects
////////////////////////////////////////////////////////////////////
INLINE RecorderController::RecorderFactory *RecorderController::
get_factory() {
if (_factory == (RecorderFactory *)NULL) {
create_factory();
}
return _factory;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::create_factory
// Access: Private, Static
// Description: Creates a new RecorderFactory for generating
// TypedWritable objects
////////////////////////////////////////////////////////////////////
INLINE void RecorderController::
create_factory() {
_factory = new RecorderFactory;
}

View File

@ -0,0 +1,370 @@
// Filename: recorderController.cxx
// Created by: drose (24Jan04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "recorderController.h"
#include "recorderFrame.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "config_recorder.h"
#include "bam.h"
TypeHandle RecorderController::_type_handle;
RecorderController::RecorderFactory *RecorderController::_factory = NULL;
////////////////////////////////////////////////////////////////////
// Function: RecorderController::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
RecorderController::
RecorderController() {
_clock_offset = 0.0;
_frame_offset = 0;
_writer = (BamWriter *)NULL;
_reader = (BamReader *)NULL;
_frame_tie = true;
_user_table = new RecorderTable;
_user_table_modified = false;
_file_table = NULL;
_active_table = NULL;
_eof = false;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
RecorderController::
~RecorderController() {
close();
delete _user_table;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::begin_record
// Access: Published
// Description: Begins recording data to the indicated filename. All
// of the recorders in use should already have been
// added.
////////////////////////////////////////////////////////////////////
bool RecorderController::
begin_record(const Filename &filename) {
close();
_filename = filename;
ClockObject *global_clock = ClockObject::get_global_clock();
_clock_offset = global_clock->get_frame_time();
_frame_offset = global_clock->get_frame_count();
time(&_header._start_time);
if (!_dout.open(_filename)) {
recorder_cat.error() << "Unable to open " << _filename << "\n";
return false;
}
if (!_dout.write_header(_bam_header)) {
recorder_cat.error() << "Unable to write to " << _filename << "\n";
return false;
}
_writer = new BamWriter(&_dout);
if (!_writer->init()) {
close();
return false;
}
// Write out the header information.
_writer->write_object(&_header);
_user_table_modified = true;
// Tell all of our recorders that they're live now.
RecorderTable::Recorders::iterator ri;
for (ri = _user_table->_recorders.begin();
ri != _user_table->_recorders.end();
++ri) {
RecorderBase *recorder = (*ri).second;
recorder->_flags |= RecorderBase::F_recording;
}
recorder_cat.info()
<< "Recording session to " << _filename << "\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::begin_playback
// Access: Published
// Description: Begins playing back data from the indicated filename.
// All of the recorders in use should already have been
// added, although this may define additional recorders
// if they are present in the file (these new recorders
// will not be used). This may also undefine recorders
// that were previously added but are not present in the
// file.
////////////////////////////////////////////////////////////////////
bool RecorderController::
begin_playback(const Filename &filename) {
close();
_filename = filename;
ClockObject *global_clock = ClockObject::get_global_clock();
_clock_offset = global_clock->get_frame_time();
_frame_offset = global_clock->get_frame_count();
if (!_din.open(_filename)) {
recorder_cat.error() << "Unable to open " << _filename << "\n";
return false;
}
string head;
if (!_din.read_header(head, _bam_header.size()) || head != _bam_header) {
recorder_cat.error() << "Unable to read " << _filename << "\n";
return false;
}
_reader = new BamReader(&_din);
if (!_reader->init()) {
close();
return false;
}
_user_table_modified = true;
_active_table = new RecorderTable;
_eof = false;
// Start out by reading the RecorderHeader.
TypedWritable *object = _reader->read_object();
if (object == (TypedWritable *)NULL ||
!object->is_of_type(RecorderHeader::get_class_type())) {
recorder_cat.error()
<< _filename << " does not contain a recorded session.\n";
close();
return false;
}
if (!_reader->resolve()) {
recorder_cat.warning()
<< "Unable to resolve header data.\n";
}
RecorderHeader *new_header = DCAST(RecorderHeader, object);
_header = (*new_header);
delete new_header;
// Now read the first frame.
_next_frame = read_frame();
if (_next_frame == (RecorderFrame *)NULL) {
recorder_cat.error()
<< _filename << " does not contain any frames.\n";
close();
return false;
}
recorder_cat.info()
<< "Playing back session from " << _filename << "\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::close
// Access: Published
// Description: Finishes recording data to the indicated filename.
////////////////////////////////////////////////////////////////////
void RecorderController::
close() {
if (_writer != (BamWriter *)NULL) {
delete _writer;
_writer = NULL;
// Tell all of our recorders that they're no longer recording.
RecorderTable::Recorders::iterator ri;
for (ri = _user_table->_recorders.begin();
ri != _user_table->_recorders.end();
++ri) {
RecorderBase *recorder = (*ri).second;
recorder->_flags &= ~RecorderBase::F_recording;
}
}
if (_reader != (BamReader *)NULL) {
delete _reader;
_reader = NULL;
// Tell all of our recorders that they're no longer playing.
RecorderTable::Recorders::iterator ri;
for (ri = _active_table->_recorders.begin();
ri != _active_table->_recorders.end();
++ri) {
RecorderBase *recorder = (*ri).second;
recorder->_flags &= ~RecorderBase::F_playing;
}
}
_dout.close();
_din.close();
if (_file_table != (RecorderTable *)NULL) {
delete _file_table;
_file_table = (RecorderTable *)NULL;
}
if (_active_table != (RecorderTable *)NULL) {
delete _active_table;
_active_table = (RecorderTable *)NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::record_frame
// Access: Published
// Description: Gets the next frame of data from all of the active
// recorders and adds it to the output file.
////////////////////////////////////////////////////////////////////
void RecorderController::
record_frame() {
if (is_recording()) {
ClockObject *global_clock = ClockObject::get_global_clock();
double now = global_clock->get_frame_time() - _clock_offset;
int frame = global_clock->get_frame_count() - _frame_offset;
RecorderFrame data(now, frame, _user_table_modified, _user_table);
_user_table_modified = false;
_writer->write_object(&data);
}
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::play_frame
// Access: Published
// Description: Gets the next frame of data from all of the active
// recorders and adds it to the output file.
////////////////////////////////////////////////////////////////////
void RecorderController::
play_frame() {
if (is_playing()) {
if (_eof) {
close();
return;
}
ClockObject *global_clock = ClockObject::get_global_clock();
double now = global_clock->get_frame_time() - _clock_offset;
int frame = global_clock->get_frame_count() - _frame_offset;
while (_next_frame != (RecorderFrame *)NULL) {
if (_frame_tie) {
if (frame < _next_frame->_frame) {
// We haven't reached the next frame yet.
return;
}
// Insist that the clock runs at the same rate as it did in
// the previous session.
//global_clock->set_frame_time(_next_frame->_timestamp + _clock_offset);
//global_clock->set_real_time(_next_frame->_timestamp + _clock_offset);
// Hmm, that's crummy. Just keep the clock offset up-to-date.
_clock_offset = global_clock->get_frame_time() - _next_frame->_timestamp;
} else {
if (now < _next_frame->_timestamp) {
// We haven't reached the next frame yet.
return;
}
// Keep our frame_offset up-to-date.
_frame_offset = global_clock->get_frame_count() - _next_frame->_frame;
}
if (_next_frame->_table_changed && _file_table != _next_frame->_table) {
delete _file_table;
_file_table = _next_frame->_table;
}
if (_next_frame->_table_changed || _user_table_modified) {
// We're about to change the active table. Temporarily
// disable the playing flag on the currently-active recorders.
RecorderTable::Recorders::iterator ri;
for (ri = _active_table->_recorders.begin();
ri != _active_table->_recorders.end();
++ri) {
RecorderBase *recorder = (*ri).second;
recorder->_flags &= ~RecorderBase::F_playing;
}
delete _active_table;
_active_table = new RecorderTable(*_file_table);
_active_table->merge_from(*_user_table);
_user_table_modified = false;
// Now reenable the playing flag on the newly-active
// recorders.
for (ri = _active_table->_recorders.begin();
ri != _active_table->_recorders.end();
++ri) {
RecorderBase *recorder = (*ri).second;
recorder->_flags |= RecorderBase::F_playing;
}
}
_next_frame->_table = _active_table;
_next_frame->play_frame(_reader);
delete _next_frame;
_next_frame = read_frame();
}
if (_reader->is_eof()) {
recorder_cat.info()
<< "End of recorded session.\n";
} else {
recorder_cat.error()
<< "Unable to read datagram from recorded session.\n";
}
_eof = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: RecorderController::read_frame
// Access: Private
// Description: Loads the next frame data from the playback session
// file. Returns the frame data pointer on success, or
// NULL on failure.
////////////////////////////////////////////////////////////////////
RecorderFrame *RecorderController::
read_frame() {
TypedWritable *object = _reader->read_object();
if (object == (TypedWritable *)NULL ||
!object->is_of_type(RecorderFrame::get_class_type())) {
return NULL;
}
if (!_reader->resolve()) {
recorder_cat.warning()
<< "Unable to resolve frame data.\n";
}
return DCAST(RecorderFrame, object);
}

Some files were not shown because too many files have changed in this diff Show More