diff --git a/direct/src/distributed/ClientRepository.py b/direct/src/distributed/ClientRepository.py index a5860528ac..9d7ee16ad2 100644 --- a/direct/src/distributed/ClientRepository.py +++ b/direct/src/distributed/ClientRepository.py @@ -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={} diff --git a/direct/src/distributed/ConnectionRepository.py b/direct/src/distributed/ConnectionRepository.py index 2583e017de..c7d652fe96 100644 --- a/direct/src/distributed/ConnectionRepository.py +++ b/direct/src/distributed/ConnectionRepository.py @@ -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) diff --git a/direct/src/showbase/EventManager.py b/direct/src/showbase/EventManager.py index 6de77db0c4..f7f29a8414 100644 --- a/direct/src/showbase/EventManager.py +++ b/direct/src/showbase/EventManager.py @@ -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): diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index f33c330fd5..f97063562d 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -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 diff --git a/panda/metalibs/panda/Sources.pp b/panda/metalibs/panda/Sources.pp index 3eb5a145b9..d3947aceca 100644 --- a/panda/metalibs/panda/Sources.pp +++ b/panda/metalibs/panda/Sources.pp @@ -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 diff --git a/panda/metalibs/pandaexpress/Sources.pp b/panda/metalibs/pandaexpress/Sources.pp index 0611100bed..e25df91137 100644 --- a/panda/metalibs/pandaexpress/Sources.pp +++ b/panda/metalibs/pandaexpress/Sources.pp @@ -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 diff --git a/panda/src/collide/collisionEntry.h b/panda/src/collide/collisionEntry.h index 57110f3d2f..3e844b406f 100644 --- a/panda/src/collide/collisionEntry.h +++ b/panda/src/collide/collisionEntry.h @@ -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 ©); @@ -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(); diff --git a/panda/src/device/trackerNode.cxx b/panda/src/device/trackerNode.cxx index 4dfbb41b19..2c52d3a26c 100644 --- a/panda/src/device/trackerNode.cxx +++ b/panda/src/device/trackerNode.cxx @@ -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)); } } diff --git a/panda/src/device/trackerNode.h b/panda/src/device/trackerNode.h index edb93e09dd..4fe08d9fbc 100644 --- a/panda/src/device/trackerNode.h +++ b/panda/src/device/trackerNode.h @@ -63,7 +63,7 @@ private: // outputs int _transform_output; - PT(EventStoreTransform) _transform; + CPT(TransformState) _transform; private: PT(ClientTrackerDevice) _tracker; diff --git a/panda/src/dgraph/config_dgraph.cxx b/panda/src/dgraph/config_dgraph.cxx index 12f9876e72..1961f0ef47 100644 --- a/panda/src/dgraph/config_dgraph.cxx +++ b/panda/src/dgraph/config_dgraph.cxx @@ -18,12 +18,16 @@ #include "config_dgraph.h" #include "dataNode.h" +#include "dataNodeTransmit.h" -#include +#include "dconfig.h" Configure(config_dgraph); NotifyCategoryDef(dgraph, ""); ConfigureFn(config_dgraph) { DataNode::init_type(); + DataNodeTransmit::init_type(); + + DataNodeTransmit::register_with_read_factory(); } diff --git a/panda/src/dgraph/dataNode.cxx b/panda/src/dgraph/dataNode.cxx index 4cf7af6eb6..b7fb7ca1b1 100644 --- a/panda/src/dgraph/dataNode.cxx +++ b/panda/src/dgraph/dataNode.cxx @@ -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); +} diff --git a/panda/src/dgraph/dataNode.h b/panda/src/dgraph/dataNode.h index bdacddae2f..f2a5f5d94e 100644 --- a/panda/src/dgraph/dataNode.h +++ b/panda/src/dgraph/dataNode.h @@ -119,6 +119,12 @@ private: typedef pvector 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; diff --git a/panda/src/dgraph/dataNodeTransmit.I b/panda/src/dgraph/dataNodeTransmit.I index 0acfce3327..276c85b991 100644 --- a/panda/src/dgraph/dataNodeTransmit.I +++ b/panda/src/dgraph/dataNodeTransmit.I @@ -47,15 +47,6 @@ operator = (const DataNodeTransmit ©) { _data = copy._data; } -//////////////////////////////////////////////////////////////////// -// Function: DataNodeTransmit::Destructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE DataNodeTransmit:: -~DataNodeTransmit() { -} - //////////////////////////////////////////////////////////////////// // Function: DataNodeTransmit::reserve // Access: Public diff --git a/panda/src/dgraph/dataNodeTransmit.cxx b/panda/src/dgraph/dataNodeTransmit.cxx index 593e0af942..257a50a77a 100644 --- a/panda/src/dgraph/dataNodeTransmit.cxx +++ b/panda/src/dgraph/dataNodeTransmit.cxx @@ -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 ¶m = (*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 ¶ms) { + 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()); + } +} diff --git a/panda/src/dgraph/dataNodeTransmit.h b/panda/src/dgraph/dataNodeTransmit.h index df557b55e2..2c9e672f39 100644 --- a/panda/src/dgraph/dataNodeTransmit.h +++ b/panda/src/dgraph/dataNodeTransmit.h @@ -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 ©); INLINE void operator = (const DataNodeTransmit ©); - INLINE ~DataNodeTransmit(); + virtual ~DataNodeTransmit(); INLINE void reserve(int num_wires); @@ -47,6 +53,33 @@ private: typedef pvector 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 ¶ms); + 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" diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index a4b8202a06..aceefd27eb 100644 --- a/panda/src/display/graphicsWindow.h +++ b/panda/src/display/graphicsWindow.h @@ -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(); diff --git a/panda/src/downloader/Sources.pp b/panda/src/downloader/Sources.pp index ee8346d9f7..427f28a741 100644 --- a/panda/src/downloader/Sources.pp +++ b/panda/src/downloader/Sources.pp @@ -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 diff --git a/panda/src/event/Sources.pp b/panda/src/event/Sources.pp index aea09e94a9..b5d6c354c3 100644 --- a/panda/src/event/Sources.pp +++ b/panda/src/event/Sources.pp @@ -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 diff --git a/panda/src/putil/buttonEvent.I b/panda/src/event/buttonEvent.I similarity index 87% rename from panda/src/putil/buttonEvent.I rename to panda/src/event/buttonEvent.I index 4ace4d2fbc..40d0792d07 100644 --- a/panda/src/putil/buttonEvent.I +++ b/panda/src/event/buttonEvent.I @@ -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; + } +} diff --git a/panda/src/event/buttonEvent.cxx b/panda/src/event/buttonEvent.cxx new file mode 100644 index 0000000000..0f7271ae28 --- /dev/null +++ b/panda/src/event/buttonEvent.cxx @@ -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; + } +} diff --git a/panda/src/putil/buttonEvent.h b/panda/src/event/buttonEvent.h similarity index 94% rename from panda/src/putil/buttonEvent.h rename to panda/src/event/buttonEvent.h index be34b3d0c9..936ebc5b7e 100644 --- a/panda/src/putil/buttonEvent.h +++ b/panda/src/event/buttonEvent.h @@ -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; diff --git a/panda/src/putil/buttonEventList.I b/panda/src/event/buttonEventList.I similarity index 100% rename from panda/src/putil/buttonEventList.I rename to panda/src/event/buttonEventList.I diff --git a/panda/src/event/buttonEventList.cxx b/panda/src/event/buttonEventList.cxx new file mode 100644 index 0000000000..c8fafe119f --- /dev/null +++ b/panda/src/event/buttonEventList.cxx @@ -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 ¶ms) { + 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); + } +} diff --git a/panda/src/putil/buttonEventList.h b/panda/src/event/buttonEventList.h similarity index 87% rename from panda/src/putil/buttonEventList.h rename to panda/src/event/buttonEventList.h index 462334f14e..53fa130bf8 100644 --- a/panda/src/putil/buttonEventList.h +++ b/panda/src/event/buttonEventList.h @@ -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 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 ¶ms); + +public: + void fillin(DatagramIterator &scan, BamReader *manager); public: static TypeHandle get_class_type() { diff --git a/panda/src/event/config_event.cxx b/panda/src/event/config_event.cxx index 30825e36ad..26f3cf8584 100644 --- a/panda/src/event/config_event.cxx +++ b/panda/src/event/config_event.cxx @@ -17,21 +17,28 @@ //////////////////////////////////////////////////////////////////// #include "config_event.h" +#include "buttonEventList.h" #include "event.h" #include "eventHandler.h" #include "eventParameter.h" -#include +#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(); } diff --git a/panda/src/event/config_event.h b/panda/src/event/config_event.h index bc55224c3c..e2136f9651 100644 --- a/panda/src/event/config_event.h +++ b/panda/src/event/config_event.h @@ -21,7 +21,7 @@ #include "pandabase.h" -#include +#include "notifyCategoryProxy.h" NotifyCategoryDecl(event, EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS); diff --git a/panda/src/event/event.h b/panda/src/event/event.h index 3d0849b92d..83285604ad 100644 --- a/panda/src/event/event.h +++ b/panda/src/event/event.h @@ -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 ©); diff --git a/panda/src/event/eventHandler.I b/panda/src/event/eventHandler.I index ebd70d334e..fe7383f34c 100755 --- a/panda/src/event/eventHandler.I +++ b/panda/src/event/eventHandler.I @@ -1,5 +1,5 @@ -// Filename: eventHandler.h -// Created by: drose (08Feb99) +// Filename: eventHandler.I +// Created by: skyler (27Jan04) // //////////////////////////////////////////////////////////////////// // diff --git a/panda/src/event/eventParameter.I b/panda/src/event/eventParameter.I index 26da0d4756..23f30865bf 100644 --- a/panda/src/event/eventParameter.I +++ b/panda/src/event/eventParameter.I @@ -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:: 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 +void EventStoreValue:: +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 +void EventStoreValue:: +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 +TypedWritable *EventStoreValue:: +make_from_bam(const FactoryParams ¶ms) { + EventStoreValue *esv = new EventStoreValue; + 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 +void EventStoreValue:: +fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + generic_read_datagram(_value, scan); +} diff --git a/panda/src/event/eventParameter.cxx b/panda/src/event/eventParameter.cxx index 37f21289d8..37b8ca1f28 100644 --- a/panda/src/event/eventParameter.cxx +++ b/panda/src/event/eventParameter.cxx @@ -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())) { diff --git a/panda/src/event/eventParameter.h b/panda/src/event/eventParameter.h index 90a408431c..ecfaa5b4b7 100644 --- a/panda/src/event/eventParameter.h +++ b/panda/src/event/eventParameter.h @@ -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 ¶m); @@ -76,7 +79,7 @@ INLINE ostream &operator << (ostream &out, const EventParameter ¶m); // 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 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 ¶ms); + 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); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); -EXPORT_TEMPLATE_CLASS(EXPCL_PANDAEXPRESS, EXPTP_PANDAEXPRESS, EventStoreValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, EventStoreValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, EventStoreValue); +EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, EventStoreValue); typedef EventStoreValue EventStoreInt; typedef EventStoreValue EventStoreDouble; diff --git a/panda/src/event/event_composite1.cxx b/panda/src/event/event_composite1.cxx index b22e9eeadc..8ef954128a 100644 --- a/panda/src/event/event_composite1.cxx +++ b/panda/src/event/event_composite1.cxx @@ -1,4 +1,5 @@ - +#include "buttonEvent.cxx" +#include "buttonEventList.cxx" #include "config_event.cxx" #include "event.cxx" #include "eventHandler.cxx" diff --git a/panda/src/express/datagram.I b/panda/src/express/datagram.I index f473bcd844..d78443ae04 100644 --- a/panda/src/express/datagram.I +++ b/panda/src/express/datagram.I @@ -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); +} diff --git a/panda/src/express/datagram.h b/panda/src/express/datagram.h index 31faa43adf..2383db6143 100644 --- a/panda/src/express/datagram.h +++ b/panda/src/express/datagram.h @@ -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 diff --git a/panda/src/express/datagramIterator.I b/panda/src/express/datagramIterator.I index ab18228261..787047c816 100644 --- a/panda/src/express/datagramIterator.I +++ b/panda/src/express/datagramIterator.I @@ -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(); +} + + diff --git a/panda/src/express/datagramIterator.h b/panda/src/express/datagramIterator.h index 9a58dffc52..50066be9cf 100644 --- a/panda/src/express/datagramIterator.h +++ b/panda/src/express/datagramIterator.h @@ -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 diff --git a/panda/src/express/dcast.cxx b/panda/src/express/dcast.cxx index 2fb3682eb9..397aeab506 100644 --- a/panda/src/express/dcast.cxx +++ b/panda/src/express/dcast.cxx @@ -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() diff --git a/panda/src/express/typedReferenceCount.h b/panda/src/express/typedReferenceCount.h index 3f4ff99e0c..e7e4a2f51a 100644 --- a/panda/src/express/typedReferenceCount.h +++ b/panda/src/express/typedReferenceCount.h @@ -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: diff --git a/panda/src/framework/Sources.pp b/panda/src/framework/Sources.pp index d37d6b281b..30942f3bf7 100644 --- a/panda/src/framework/Sources.pp +++ b/panda/src/framework/Sources.pp @@ -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 \ diff --git a/panda/src/framework/config_framework.cxx b/panda/src/framework/config_framework.cxx index 813f7ed1ee..e1fecb475c 100644 --- a/panda/src/framework/config_framework.cxx +++ b/panda/src/framework/config_framework.cxx @@ -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", ""); + diff --git a/panda/src/framework/config_framework.h b/panda/src/framework/config_framework.h index 06f3287fa9..f339d347dd 100644 --- a/panda/src/framework/config_framework.h +++ b/panda/src/framework/config_framework.h @@ -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 diff --git a/panda/src/framework/pandaFramework.I b/panda/src/framework/pandaFramework.I index 96054c8ffc..2857c4b384 100644 --- a/panda/src/framework/pandaFramework.I +++ b/panda/src/framework/pandaFramework.I @@ -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 diff --git a/panda/src/framework/pandaFramework.cxx b/panda/src/framework/pandaFramework.cxx index e324c90ab9..80c47b2b0f 100644 --- a/panda/src/framework/pandaFramework.cxx +++ b/panda/src/framework/pandaFramework.cxx @@ -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; } diff --git a/panda/src/framework/pandaFramework.h b/panda/src/framework/pandaFramework.h index c95accc1d4..4d968a37c1 100644 --- a/panda/src/framework/pandaFramework.h +++ b/panda/src/framework/pandaFramework.h @@ -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" diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index a551070a01..5f3521ae26 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -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; } diff --git a/panda/src/framework/windowFramework.h b/panda/src/framework/windowFramework.h index e1ccd01bfa..9b2b176658 100644 --- a/panda/src/framework/windowFramework.h +++ b/panda/src/framework/windowFramework.h @@ -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(); diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 08b8dcafb9..320c260041 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -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(); } diff --git a/panda/src/gobj/lens.cxx b/panda/src/gobj/lens.cxx index f77f726458..ba20a293ad 100644 --- a/panda/src/gobj/lens.cxx +++ b/panda/src/gobj/lens.cxx @@ -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; +} diff --git a/panda/src/gobj/lens.h b/panda/src/gobj/lens.h index baee6f03d6..b7ef204d03 100644 --- a/panda/src/gobj/lens.h +++ b/panda/src/gobj/lens.h @@ -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 ©); @@ -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: diff --git a/panda/src/gobj/matrixLens.cxx b/panda/src/gobj/matrixLens.cxx index 2b5bbc9abc..a6fda582b1 100644 --- a/panda/src/gobj/matrixLens.cxx +++ b/panda/src/gobj/matrixLens.cxx @@ -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 ¶ms) { + MatrixLens *lens = new MatrixLens; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + lens->fillin(scan, manager); + + return lens; +} diff --git a/panda/src/gobj/matrixLens.h b/panda/src/gobj/matrixLens.h index ef595fd6e5..1f048abb6f 100644 --- a/panda/src/gobj/matrixLens.h +++ b/panda/src/gobj/matrixLens.h @@ -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 ¶ms); + public: virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/gobj/orthographicLens.cxx b/panda/src/gobj/orthographicLens.cxx index ada28bce4c..48630d7269 100644 --- a/panda/src/gobj/orthographicLens.cxx +++ b/panda/src/gobj/orthographicLens.cxx @@ -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 ¶ms) { + OrthographicLens *lens = new OrthographicLens; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + lens->fillin(scan, manager); + + return lens; +} diff --git a/panda/src/gobj/orthographicLens.h b/panda/src/gobj/orthographicLens.h index 2d3873ba5b..6489531eac 100644 --- a/panda/src/gobj/orthographicLens.h +++ b/panda/src/gobj/orthographicLens.h @@ -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 ¶ms); + public: virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/gobj/perspectiveLens.cxx b/panda/src/gobj/perspectiveLens.cxx index 92d071996f..4bf5ec3a54 100644 --- a/panda/src/gobj/perspectiveLens.cxx +++ b/panda/src/gobj/perspectiveLens.cxx @@ -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 ¶ms) { + PerspectiveLens *lens = new PerspectiveLens; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + lens->fillin(scan, manager); + + return lens; +} diff --git a/panda/src/gobj/perspectiveLens.h b/panda/src/gobj/perspectiveLens.h index d25e718019..e4fbc3f631 100644 --- a/panda/src/gobj/perspectiveLens.h +++ b/panda/src/gobj/perspectiveLens.h @@ -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 ¶ms); + public: virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/linmath/lmat_ops_src.I b/panda/src/linmath/lmat_ops_src.I index c14d748492..b930d472b9 100644 --- a/panda/src/linmath/lmat_ops_src.I +++ b/panda/src/linmath/lmat_ops_src.I @@ -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); +} diff --git a/panda/src/linmath/lmat_ops_src.h b/panda/src/linmath/lmat_ops_src.h index f247242fc2..c753ad1ea0 100644 --- a/panda/src/linmath/lmat_ops_src.h +++ b/panda/src/linmath/lmat_ops_src.h @@ -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" diff --git a/panda/src/linmath/lvec2_ops_src.I b/panda/src/linmath/lvec2_ops_src.I index 9848f5d631..00681fbbea 100644 --- a/panda/src/linmath/lvec2_ops_src.I +++ b/panda/src/linmath/lvec2_ops_src.I @@ -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); +} diff --git a/panda/src/linmath/lvec2_ops_src.h b/panda/src/linmath/lvec2_ops_src.h index 7a2d0b4abb..97243fceab 100644 --- a/panda/src/linmath/lvec2_ops_src.h +++ b/panda/src/linmath/lvec2_ops_src.h @@ -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" diff --git a/panda/src/linmath/lvec3_ops_src.I b/panda/src/linmath/lvec3_ops_src.I index e5cd182351..ecdc69268f 100644 --- a/panda/src/linmath/lvec3_ops_src.I +++ b/panda/src/linmath/lvec3_ops_src.I @@ -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); +} diff --git a/panda/src/linmath/lvec3_ops_src.h b/panda/src/linmath/lvec3_ops_src.h index 9eafe4eed8..550cd99f4a 100644 --- a/panda/src/linmath/lvec3_ops_src.h +++ b/panda/src/linmath/lvec3_ops_src.h @@ -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" diff --git a/panda/src/linmath/lvec4_ops_src.I b/panda/src/linmath/lvec4_ops_src.I index 14a18b0614..c89bd51a2e 100644 --- a/panda/src/linmath/lvec4_ops_src.I +++ b/panda/src/linmath/lvec4_ops_src.I @@ -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); +} diff --git a/panda/src/linmath/lvec4_ops_src.h b/panda/src/linmath/lvec4_ops_src.h index 8f970ead3c..181d792b4c 100644 --- a/panda/src/linmath/lvec4_ops_src.h +++ b/panda/src/linmath/lvec4_ops_src.h @@ -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" diff --git a/panda/src/mathutil/config_mathutil.cxx b/panda/src/mathutil/config_mathutil.cxx index 7ac8e7d78c..25cfca6f4c 100644 --- a/panda/src/mathutil/config_mathutil.cxx +++ b/panda/src/mathutil/config_mathutil.cxx @@ -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(); } diff --git a/panda/src/pgraph/bamFile.h b/panda/src/pgraph/bamFile.h index 2f0097741e..51fd816a31 100644 --- a/panda/src/pgraph/bamFile.h +++ b/panda/src/pgraph/bamFile.h @@ -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(); diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index ce698b8dbf..e61ee20cf7 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -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(); diff --git a/panda/src/pgraph/lensNode.cxx b/panda/src/pgraph/lensNode.cxx index bf73597fb9..dc16f3dfca 100644 --- a/panda/src/pgraph/lensNode.cxx +++ b/panda/src/pgraph/lensNode.cxx @@ -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; } diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index caa8eb5fc7..79827b746e 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -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); +} diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 66b39be532..f7e9f50c54 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -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 ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); + void fillin_recorder(DatagramIterator &scan, BamReader *manager); public: static TypeHandle get_class_type() { diff --git a/panda/src/pgraph/transformState.I b/panda/src/pgraph/transformState.I index 36d6d6f8ce..46c7c3e1df 100644 --- a/panda/src/pgraph/transformState.I +++ b/panda/src/pgraph/transformState.I @@ -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; -} diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 7ae969415b..6917b854d1 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -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; -} diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 728534a416..90ca2a6488 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -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 diff --git a/panda/src/pgui/pgMouseWatcherParameter.h b/panda/src/pgui/pgMouseWatcherParameter.h index 29ec3461f3..029af5a561 100644 --- a/panda/src/pgui/pgMouseWatcherParameter.h +++ b/panda/src/pgui/pgMouseWatcherParameter.h @@ -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(); diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index b0b49ba783..122403dc78 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -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 \ diff --git a/panda/src/putil/bamReader.I b/panda/src/putil/bamReader.I index 2ce277f4a3..22ac151896 100644 --- a/panda/src/putil/bamReader.I +++ b/panda/src/putil/bamReader.I @@ -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; } diff --git a/panda/src/putil/bamReader.cxx b/panda/src/putil/bamReader.cxx index 27392fe761..5dc3365535 100644 --- a/panda/src/putil/bamReader.cxx +++ b/panda/src/putil/bamReader.cxx @@ -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); +} diff --git a/panda/src/putil/bamReader.h b/panda/src/putil/bamReader.h index 08fd6e69d9..6227c7653f 100644 --- a/panda/src/putil/bamReader.h +++ b/panda/src/putil/bamReader.h @@ -29,6 +29,7 @@ #include "factory.h" #include "vector_int.h" #include "pset.h" +#include "pmap.h" #include "dcast.h" #include @@ -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 NewTypes; static NewTypes _new_types; + // This is used in support of set_aux_data() and get_aux_data(). + typedef pmap AuxData; + AuxData _aux_data; + int _file_major, _file_minor; static const int _cur_major; static const int _cur_minor; diff --git a/panda/src/putil/bamWriter.cxx b/panda/src/putil/bamWriter.cxx index 2d8220d1c0..d50088f249 100644 --- a/panda/src/putil/bamWriter.cxx +++ b/panda/src/putil/bamWriter.cxx @@ -25,6 +25,8 @@ #include "bamWriter.h" #include "bamReader.h" +#include + //////////////////////////////////////////////////////////////////// // 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); diff --git a/panda/src/putil/bamWriter.h b/panda/src/putil/bamWriter.h index 12acc7dabc..004eafe3b7 100644 --- a/panda/src/putil/bamWriter.h +++ b/panda/src/putil/bamWriter.h @@ -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 _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 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 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" diff --git a/panda/src/putil/buttonEvent.cxx b/panda/src/putil/buttonEvent.cxx deleted file mode 100644 index 7a77957776..0000000000 --- a/panda/src/putil/buttonEvent.cxx +++ /dev/null @@ -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; - } -} diff --git a/panda/src/putil/buttonEventList.cxx b/panda/src/putil/buttonEventList.cxx deleted file mode 100644 index c5b65c0206..0000000000 --- a/panda/src/putil/buttonEventList.cxx +++ /dev/null @@ -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"; - } -} diff --git a/panda/src/putil/config_util.cxx b/panda/src/putil/config_util.cxx index 37147bbb80..25deeea32d 100644 --- a/panda/src/putil/config_util.cxx +++ b/panda/src/putil/config_util.cxx @@ -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"); } diff --git a/panda/src/putil/datagramInputFile.cxx b/panda/src/putil/datagramInputFile.cxx index fccc269f34..e1826a5fca 100644 --- a/panda/src/putil/datagramInputFile.cxx +++ b/panda/src/putil/datagramInputFile.cxx @@ -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; } diff --git a/panda/src/putil/datagramOutputFile.cxx b/panda/src/putil/datagramOutputFile.cxx index cc2d05c2da..0266776022 100644 --- a/panda/src/putil/datagramOutputFile.cxx +++ b/panda/src/putil/datagramOutputFile.cxx @@ -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()); diff --git a/panda/src/putil/modifierButtons.I b/panda/src/putil/modifierButtons.I index 4bac3d2e7c..7bcadc5509 100644 --- a/panda/src/putil/modifierButtons.I +++ b/panda/src/putil/modifierButtons.I @@ -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 diff --git a/panda/src/putil/modifierButtons.h b/panda/src/putil/modifierButtons.h index 47441d81f0..c31d6c24ad 100644 --- a/panda/src/putil/modifierButtons.h +++ b/panda/src/putil/modifierButtons.h @@ -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; diff --git a/panda/src/putil/putil_composite1.cxx b/panda/src/putil/putil_composite1.cxx index 8ebd1b180b..95219654b1 100644 --- a/panda/src/putil/putil_composite1.cxx +++ b/panda/src/putil/putil_composite1.cxx @@ -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" diff --git a/panda/src/putil/typedWritable.cxx b/panda/src/putil/typedWritable.cxx index c0ca3c2471..46dc80d10a 100644 --- a/panda/src/putil/typedWritable.cxx +++ b/panda/src/putil/typedWritable.cxx @@ -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); + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/typedWritable.h b/panda/src/putil/typedWritable.h index 2f6c376cd0..94ab34cb8f 100644 --- a/panda/src/putil/typedWritable.h +++ b/panda/src/putil/typedWritable.h @@ -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 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" diff --git a/panda/src/putil/typedWritableReferenceCount.h b/panda/src/putil/typedWritableReferenceCount.h index 5e95ad56c0..a571d2e858 100644 --- a/panda/src/putil/typedWritableReferenceCount.h +++ b/panda/src/putil/typedWritableReferenceCount.h @@ -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 ©); INLINE void operator = (const TypedWritableReferenceCount ©); -public: - virtual void write_datagram(BamWriter *, Datagram &) = 0; - public: virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/recorder/Sources.pp b/panda/src/recorder/Sources.pp new file mode 100644 index 0000000000..7217bf08e1 --- /dev/null +++ b/panda/src/recorder/Sources.pp @@ -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 diff --git a/panda/src/recorder/config_recorder.cxx b/panda/src/recorder/config_recorder.cxx new file mode 100644 index 0000000000..6fb5311966 --- /dev/null +++ b/panda/src/recorder/config_recorder.cxx @@ -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(); +} diff --git a/panda/src/recorder/config_recorder.h b/panda/src/recorder/config_recorder.h new file mode 100644 index 0000000000..8fad7d2ee2 --- /dev/null +++ b/panda/src/recorder/config_recorder.h @@ -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 diff --git a/panda/src/recorder/mouseRecorder.cxx b/panda/src/recorder/mouseRecorder.cxx new file mode 100644 index 0000000000..f099fb489a --- /dev/null +++ b/panda/src/recorder/mouseRecorder.cxx @@ -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 ¶ms) { + 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 ¶ms) { + 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); +} diff --git a/panda/src/recorder/mouseRecorder.h b/panda/src/recorder/mouseRecorder.h new file mode 100644 index 0000000000..089cf6ba54 --- /dev/null +++ b/panda/src/recorder/mouseRecorder.h @@ -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 ¶ms); + static RecorderBase *make_recorder(const FactoryParams ¶ms); + 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 + diff --git a/panda/src/recorder/recorderBase.I b/panda/src/recorder/recorderBase.I new file mode 100644 index 0000000000..cd2eb760d7 --- /dev/null +++ b/panda/src/recorder/recorderBase.I @@ -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; +} diff --git a/panda/src/recorder/recorderBase.cxx b/panda/src/recorder/recorderBase.cxx new file mode 100644 index 0000000000..4d7fdb3fed --- /dev/null +++ b/panda/src/recorder/recorderBase.cxx @@ -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 *) { +} diff --git a/panda/src/recorder/recorderBase.h b/panda/src/recorder/recorderBase.h new file mode 100644 index 0000000000..8b4ded4760 --- /dev/null +++ b/panda/src/recorder/recorderBase.h @@ -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 + diff --git a/panda/src/recorder/recorderController.I b/panda/src/recorder/recorderController.I new file mode 100644 index 0000000000..d09afe87bb --- /dev/null +++ b/panda/src/recorder/recorderController.I @@ -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; +} diff --git a/panda/src/recorder/recorderController.cxx b/panda/src/recorder/recorderController.cxx new file mode 100644 index 0000000000..a89fe4cace --- /dev/null +++ b/panda/src/recorder/recorderController.cxx @@ -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); +} diff --git a/panda/src/recorder/recorderController.h b/panda/src/recorder/recorderController.h new file mode 100644 index 0000000000..5d17bffdfa --- /dev/null +++ b/panda/src/recorder/recorderController.h @@ -0,0 +1,136 @@ +// Filename: recorderController.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 RECORDERCONTROLLER_H +#define RECORDERCONTROLLER_H + +#include "pandabase.h" +#include "datagramOutputFile.h" +#include "datagramInputFile.h" +#include "recorderTable.h" +#include "recorderHeader.h" +#include "typedReferenceCount.h" +#include "factory.h" + +class RecorderBase; +class RecorderFrame; + +//////////////////////////////////////////////////////////////////// +// Class : RecorderController +// Description : This object manages the process of recording the +// user's runtime inputs to a bam file so that the +// session can be recreated later. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RecorderController : public TypedReferenceCount { +PUBLISHED: + RecorderController(); + ~RecorderController(); + + bool begin_record(const Filename &filename); + bool begin_playback(const Filename &filename); + void close(); + + INLINE time_t get_start_time() const; + + INLINE void set_random_seed(int random_seed); + INLINE int get_random_seed() const; + + INLINE bool is_recording() const; + INLINE bool is_playing() const; + INLINE bool is_open() const; + INLINE const Filename &get_filename() const; + + INLINE bool is_error(); + INLINE double get_clock_offset() const; + INLINE int get_frame_offset() const; + + INLINE void add_recorder(const string &name, RecorderBase *recorder); + INLINE bool has_recorder(const string &name) const; + INLINE RecorderBase *get_recorder(const string &name) const; + INLINE bool remove_recorder(const string &name); + + INLINE void set_frame_tie(bool frame_tie); + INLINE bool get_frame_tie() const; + + void record_frame(); + void play_frame(); + +public: + typedef Factory RecorderFactory; + + INLINE static RecorderFactory *get_factory(); + +private: + INLINE static void create_factory(); + RecorderFrame *read_frame(); + +private: + RecorderHeader _header; + double _clock_offset; + int _frame_offset; + + Filename _filename; + DatagramOutputFile _dout; + DatagramInputFile _din; + BamWriter *_writer; + BamReader *_reader; + bool _frame_tie; + + // _user_table is directly modified by the user. + RecorderTable *_user_table; + bool _user_table_modified; + + // In playback mode, _file_table represents the table as read + // directly from the session file, with default recorders in each + // slot. + RecorderTable *_file_table; + + // In playback mode, _active_table is the result of the merge of + // _file_table and _user_table, with a default recorder or a + // user-specified recorder in each active slot. + RecorderTable *_active_table; + + RecorderFrame *_next_frame; + bool _eof; + + static RecorderFactory *_factory; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedReferenceCount::init_type(); + register_type(_type_handle, "RecorderController", + TypedReferenceCount::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; + + friend class RecorderFrame; +}; + +#include "recorderController.I" + +#endif + diff --git a/panda/src/recorder/recorderFrame.I b/panda/src/recorder/recorderFrame.I new file mode 100644 index 0000000000..e2bef32805 --- /dev/null +++ b/panda/src/recorder/recorderFrame.I @@ -0,0 +1,51 @@ +// Filename: recorderFrame.I +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderFrame:: +RecorderFrame() { +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderFrame:: +RecorderFrame(double timestamp, int frame, + bool table_changed, RecorderTable *table) : + _timestamp(timestamp), + _frame(frame), + _table_changed(table_changed), + _table(table) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderFrame:: +~RecorderFrame() { +} diff --git a/panda/src/recorder/recorderFrame.cxx b/panda/src/recorder/recorderFrame.cxx new file mode 100644 index 0000000000..2d4c64c6b4 --- /dev/null +++ b/panda/src/recorder/recorderFrame.cxx @@ -0,0 +1,172 @@ +// Filename: recorderFrame.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 "recorderFrame.h" +#include "recorderTable.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "config_recorder.h" + +TypeHandle RecorderFrame::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::play_frame +// Access: Public +// Description: Once the raw data has been read in from the session +// file, and the table has been decoded, decode the raw +// data and call play_frame on each recorder. +//////////////////////////////////////////////////////////////////// +void RecorderFrame:: +play_frame(BamReader *manager) { + DatagramIterator scan(_data, _data_pos); + + RecorderTable::Recorders::iterator ri; + for (ri = _table->_recorders.begin(); + ri != _table->_recorders.end(); + ++ri) { + RecorderBase *recorder = (*ri).second; + recorder->play_frame(scan, manager); + } + + // We expect to use up all of the data in the datagram. + nassertv(scan.get_remaining_size() == 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// Lens. +//////////////////////////////////////////////////////////////////// +void RecorderFrame:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void RecorderFrame:: +write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + dg.add_float64(_timestamp); + dg.add_uint32(_frame); + + // Write the table out if it has changed. + dg.add_bool(_table_changed); + if (_table_changed) { + // As a kludge, we create a new table pointer to write out. + // Otherwise, the pointer won't change and it may not write out + // the changes. Later, we need to add a facility to the bam + // writer to detect when a TypedWritable has changed and should be + // rewritten. + _local_table = *_table; + manager->write_pointer(dg, &_local_table); + } + + RecorderTable::Recorders::iterator ri; + for (ri = _table->_recorders.begin(); + ri != _table->_recorders.end(); + ++ri) { + RecorderBase *recorder = (*ri).second; + recorder->record_frame(manager, dg); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::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. +// +// This is the callback function that is made by the +// BamReader at some later point, after all of the +// required pointers have been filled in. It is +// necessary because there might be forward references +// in a bam file; when we call read_pointer() in +// fillin(), the object may not have been read from the +// file yet, so we do not have a pointer available at +// that time. Thus, instead of returning a pointer, +// read_pointer() simply reserves a later callback. +// This function provides that callback. The calling +// object is responsible for keeping track of the number +// of times it called read_pointer() and extracting the +// same number of pointers out of the supplied vector, +// and storing them appropriately within the object. +//////////////////////////////////////////////////////////////////// +int RecorderFrame:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = TypedWritable::complete_pointers(p_list, manager); + + if (_table_changed) { + _table = DCAST(RecorderTable, p_list[pi++]); + } + + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::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 *RecorderFrame:: +make_from_bam(const FactoryParams ¶ms) { + RecorderFrame *frame = new RecorderFrame; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + frame->fillin(scan, manager); + + return frame; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderFrame::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 RecorderFrame. +//////////////////////////////////////////////////////////////////// +void RecorderFrame:: +fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + + _timestamp = scan.get_float64(); + _frame = scan.get_uint32(); + _table_changed = scan.get_bool(); + _table = (RecorderTable *)NULL; + if (_table_changed) { + manager->read_pointer(scan); + } + + // We can't decode the data in the frame until we have (a) gotten + // back the table pointer, or (b) been told who our owning + // RecorderController is. So we'll just save the raw data for now + // and come back to it. + _data = scan.get_datagram(); + _data_pos = scan.get_current_index(); +} diff --git a/panda/src/recorder/recorderFrame.h b/panda/src/recorder/recorderFrame.h new file mode 100644 index 0000000000..d90ee946e8 --- /dev/null +++ b/panda/src/recorder/recorderFrame.h @@ -0,0 +1,88 @@ +// Filename: recorderFrame.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 RECORDERFRAME_H +#define RECORDERFRAME_H + +#include "pandabase.h" +#include "recorderBase.h" +#include "typedWritable.h" +#include "recorderTable.h" + +class BamWriter; +class BamReader; +class FactoryParams; + +//////////////////////////////////////////////////////////////////// +// Class : RecorderFrame +// Description : This object represents one frame of data in the +// recorded session file. One of these is repeatedly +// created and destructed in recording and playback, +// respectively. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RecorderFrame : public TypedWritable { +public: + INLINE RecorderFrame(); + INLINE RecorderFrame(double timestamp, int frame, + bool table_changed, RecorderTable *table); + INLINE ~RecorderFrame(); + + void play_frame(BamReader *manager); + + double _timestamp; + int _frame; + bool _table_changed; + RecorderTable *_table; + + Datagram _data; + size_t _data_pos; + +private: + RecorderTable _local_table; + +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 ¶ms); + 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, "RecorderFrame", + 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 "recorderFrame.I" + +#endif + diff --git a/panda/src/recorder/recorderHeader.I b/panda/src/recorder/recorderHeader.I new file mode 100644 index 0000000000..2b418ea293 --- /dev/null +++ b/panda/src/recorder/recorderHeader.I @@ -0,0 +1,61 @@ +// Filename: recorderHeader.I +// Created by: drose (29Jan04) +// +//////////////////////////////////////////////////////////////////// +// +// 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: RecorderHeader::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderHeader:: +RecorderHeader() { + time(&_start_time); + _random_seed = (int)_start_time; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderHeader:: +RecorderHeader(const RecorderHeader ©) : + _start_time(copy._start_time), + _random_seed(copy._random_seed) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void RecorderHeader:: +operator = (const RecorderHeader ©) { + _start_time = copy._start_time; + _random_seed = copy._random_seed; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderHeader:: +~RecorderHeader() { +} diff --git a/panda/src/recorder/recorderHeader.cxx b/panda/src/recorder/recorderHeader.cxx new file mode 100644 index 0000000000..dc00e770d8 --- /dev/null +++ b/panda/src/recorder/recorderHeader.cxx @@ -0,0 +1,90 @@ +// Filename: recorderHeader.cxx +// Created by: drose (29Jan04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "recorderHeader.h" +#include "recorderTable.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "config_recorder.h" + +TypeHandle RecorderHeader::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// Lens. +//////////////////////////////////////////////////////////////////// +void RecorderHeader:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void RecorderHeader:: +write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + + // One day this will need to be upgraded to a uint64, but probably + // not before 2106. (In 2038, Unix time will overflow a signed + // 32-bit number, but this is an unsigned number and will still be + // good until 2106.) + dg.add_uint32(_start_time); + + dg.add_int32(_random_seed); +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::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 *RecorderHeader:: +make_from_bam(const FactoryParams ¶ms) { + RecorderHeader *header = new RecorderHeader; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + header->fillin(scan, manager); + + return header; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderHeader::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 RecorderHeader. +//////////////////////////////////////////////////////////////////// +void RecorderHeader:: +fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + + _start_time = scan.get_uint32(); + _random_seed = scan.get_int32(); +} diff --git a/panda/src/recorder/recorderHeader.h b/panda/src/recorder/recorderHeader.h new file mode 100644 index 0000000000..312c29ee40 --- /dev/null +++ b/panda/src/recorder/recorderHeader.h @@ -0,0 +1,76 @@ +// Filename: recorderHeader.h +// Created by: drose (29Jan04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 RECORDERHEADER_H +#define RECORDERHEADER_H + +#include "pandabase.h" +#include "recorderBase.h" +#include "typedWritable.h" + +#include + +class BamWriter; +class BamReader; +class FactoryParams; + +//////////////////////////////////////////////////////////////////// +// Class : RecorderHeader +// Description : This object contains the header information written +// out at the beginning of a recorded session file. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RecorderHeader : public TypedWritable { +public: + INLINE RecorderHeader(); + INLINE RecorderHeader(const RecorderHeader ©); + INLINE void operator = (const RecorderHeader ©); + INLINE ~RecorderHeader(); + + time_t _start_time; + int _random_seed; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + 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, "RecorderHeader", + 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 "recorderHeader.I" + +#endif + diff --git a/panda/src/recorder/recorderTable.I b/panda/src/recorder/recorderTable.I new file mode 100644 index 0000000000..837446cb3d --- /dev/null +++ b/panda/src/recorder/recorderTable.I @@ -0,0 +1,60 @@ +// Filename: recorderTable.I +// Created by: drose (27Jan04) +// +//////////////////////////////////////////////////////////////////// +// +// 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: RecorderTable::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderTable:: +RecorderTable() { + _error = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderTable:: +RecorderTable(const RecorderTable ©) : + _recorders(copy._recorders), + _error(copy._error) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE void RecorderTable:: +operator = (const RecorderTable ©) { + _recorders = copy._recorders; + _error = copy._error; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RecorderTable:: +~RecorderTable() { +} diff --git a/panda/src/recorder/recorderTable.cxx b/panda/src/recorder/recorderTable.cxx new file mode 100644 index 0000000000..1a22f653bd --- /dev/null +++ b/panda/src/recorder/recorderTable.cxx @@ -0,0 +1,222 @@ +// Filename: recorderTable.cxx +// Created by: drose (27Jan04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "recorderTable.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "config_recorder.h" +#include "indent.h" + +TypeHandle RecorderTable::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::merge_from +// Access: Public +// Description: Combines the data in the current table (presumably +// just read from disk, and matching exactly with the +// disk data) with the data in the indicated table, +// specified by the user (which may not exactly match +// the disk data). +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +merge_from(const RecorderTable &other) { + Recorders::const_iterator ori; + for (ori = other._recorders.begin(); ori != other._recorders.end(); ++ori) { + const string &name = (*ori).first; + RecorderBase *recorder = (*ori).second; + + Recorders::iterator ri = _recorders.find(name); + if (ri == _recorders.end()) { + // This may not be an error, since maybe the data isn't here + // yet, but it'll be along later. + recorder_cat.debug() + << "No data for " << name << " in session.\n"; + + } else if ((*ri).second->get_type() == recorder->get_type()) { + // If we already had a recorder by that name with the same type, + // throw it away (otherwise, keep the one we had before). + (*ri).second = recorder; + + } else { + recorder_cat.warning() + << "Keeping recorder " << name << " of type " + << (*ri).second->get_type() << " instead of recorder of type " + << recorder->get_type() << "\n"; + } + } + + // Now report any recorders in the session file that weren't + // specified by the user. + Recorders::const_iterator ri; + for (ri = _recorders.begin(); ri != _recorders.end(); ++ri) { + const string &name = (*ri).first; + ori = other._recorders.find(name); + if (ori == other._recorders.end()) { + recorder_cat.warning() + << "Ignoring " << name << " in session.\n"; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::add_recorder +// Access: Published +// Description: Adds the named recorder to the set of recorders. +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +add_recorder(const string &name, RecorderBase *recorder) { + _recorders[name] = recorder; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::get_recorder +// Access: Published +// Description: Returns the recorder with the indicated name, or NULL +// if there is no such recorder. +//////////////////////////////////////////////////////////////////// +RecorderBase *RecorderTable:: +get_recorder(const string &name) const { + Recorders::const_iterator ri = _recorders.find(name); + if (ri != _recorders.end()) { + return (*ri).second; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::remove_recorder +// Access: Published +// Description: Removes the named recorder from the table. Returns +// true if successful, false if there was no such +// recorder. +//////////////////////////////////////////////////////////////////// +bool RecorderTable:: +remove_recorder(const string &name) { + Recorders::iterator ri = _recorders.find(name); + if (ri != _recorders.end()) { + _recorders.erase(ri); + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::write +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +write(ostream &out, int indent_level) const { + indent(out, indent_level) + << "RecorderTable:\n"; + + Recorders::const_iterator ri; + for (ri = _recorders.begin(); ri != _recorders.end(); ++ri) { + const string &name = (*ri).first; + RecorderBase *recorder = (*ri).second; + indent(out, indent_level + 2) + << name << " : " << recorder->get_type() << "\n"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// Lens. +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + + dg.add_uint16(_recorders.size()); + Recorders::const_iterator ri; + for (ri = _recorders.begin(); ri != _recorders.end(); ++ri) { + const string &name = (*ri).first; + RecorderBase *recorder = (*ri).second; + dg.add_string(name); + manager->write_handle(dg, recorder->get_type()); + recorder->write_recorder(manager, dg); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::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 *RecorderTable:: +make_from_bam(const FactoryParams ¶ms) { + RecorderTable *table = new RecorderTable; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + table->fillin(scan, manager); + + return table; +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::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 RecorderTable. +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + + int num_recorders = scan.get_uint16(); + for (int i = 0; i < num_recorders; i++) { + string name = scan.get_string(); + TypeHandle type = manager->read_handle(scan); + + // Use the Factory to create a new recorder of the indicated type. + FactoryParams fparams; + fparams.add_param(new BamReaderParam(scan, manager)); + + PT(RecorderBase) recorder = + RecorderController::get_factory()->make_instance_more_general(type, fparams); + if (recorder == (RecorderBase *)NULL) { + recorder_cat.error() + << "Unable to create Recorder of type " << type << "\n"; + _error = true; + + } else { + bool inserted = + _recorders.insert(Recorders::value_type(name, recorder)).second; + nassertv(inserted); + } + } +} diff --git a/panda/src/recorder/recorderTable.h b/panda/src/recorder/recorderTable.h new file mode 100644 index 0000000000..63d64197c8 --- /dev/null +++ b/panda/src/recorder/recorderTable.h @@ -0,0 +1,89 @@ +// Filename: recorderTable.h +// Created by: drose (27Jan04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 RECORDERTABLE_H +#define RECORDERTABLE_H + +#include "pandabase.h" +#include "recorderBase.h" +#include "pointerTo.h" +#include "pmap.h" +#include "typedWritable.h" + +class BamWriter; +class BamReader; +class FactoryParams; + +//////////////////////////////////////////////////////////////////// +// Class : RecorderTable +// Description : This object is used by the RecorderController to +// write (and read) a record of the set of recorders in +// use to the bam file. Do not attempt to use it +// directly. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA RecorderTable : public TypedWritable { +public: + INLINE RecorderTable(); + INLINE RecorderTable(const RecorderTable ©); + INLINE void operator = (const RecorderTable ©); + INLINE ~RecorderTable(); + + void merge_from(const RecorderTable &other); + + void add_recorder(const string &name, RecorderBase *recorder); + RecorderBase *get_recorder(const string &name) const; + bool remove_recorder(const string &name); + + void write(ostream &out, int indent_level) const; + + + typedef pmap Recorders; + Recorders _recorders; + + bool _error; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + 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, "RecorderTable", + 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 "recorderTable.I" + +#endif + diff --git a/panda/src/recorder/recorder_composite1.cxx b/panda/src/recorder/recorder_composite1.cxx new file mode 100644 index 0000000000..aa1ca29ce3 --- /dev/null +++ b/panda/src/recorder/recorder_composite1.cxx @@ -0,0 +1,4 @@ +#include "config_recorder.cxx" +#include "mouseRecorder.cxx" +#include "recorderFrame.cxx" +#include "recorderHeader.cxx" diff --git a/panda/src/recorder/recorder_composite2.cxx b/panda/src/recorder/recorder_composite2.cxx new file mode 100644 index 0000000000..268104bbfa --- /dev/null +++ b/panda/src/recorder/recorder_composite2.cxx @@ -0,0 +1,4 @@ +#include "recorderBase.cxx" +#include "recorderController.cxx" +#include "recorderTable.cxx" +#include "socketStreamRecorder.cxx" diff --git a/panda/src/recorder/socketStreamRecorder.I b/panda/src/recorder/socketStreamRecorder.I new file mode 100644 index 0000000000..1c8fcc33fd --- /dev/null +++ b/panda/src/recorder/socketStreamRecorder.I @@ -0,0 +1,171 @@ +// Filename: socketStreamRecorder.I +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SocketStreamRecorder:: +SocketStreamRecorder() : + _stream(NULL), + _owns_stream(false), + _closed(true) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SocketStreamRecorder:: +SocketStreamRecorder(SocketStream *stream, bool owns_stream) : + _stream(stream), + _owns_stream(owns_stream), + _closed(false) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE SocketStreamRecorder:: +~SocketStreamRecorder() { + if (_owns_stream) { + delete _stream; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::send_datagram +// Access: Public +// Description: See SocketStream::send_datagram(). +//////////////////////////////////////////////////////////////////// +bool SocketStreamRecorder:: +send_datagram(const Datagram &dg) { + if (_stream != (SocketStream *)NULL) { + return _stream->send_datagram(dg); + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::is_closed +// Access: Published +// Description: See SocketStream::is_closed(). +//////////////////////////////////////////////////////////////////// +INLINE bool SocketStreamRecorder:: +is_closed() { + if (_stream != (SocketStream *)NULL) { + return _stream->is_closed(); + } + return is_playing() && _closed; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::close +// Access: Published +// Description: See SocketStream::close(). +//////////////////////////////////////////////////////////////////// +INLINE void SocketStreamRecorder:: +close() { + if (_stream != (SocketStream *)NULL) { + _stream->close(); + } + _closed = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::set_collect_tcp +// Access: Published +// Description: See SocketStream::set_collect_tcp(). +//////////////////////////////////////////////////////////////////// +INLINE void SocketStreamRecorder:: +set_collect_tcp(bool collect_tcp) { + if (_stream != (SocketStream *)NULL) { + _stream->set_collect_tcp(collect_tcp); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::get_collect_tcp +// Access: Published +// Description: See SocketStream::get_collect_tcp(). +//////////////////////////////////////////////////////////////////// +INLINE bool SocketStreamRecorder:: +get_collect_tcp() const { + if (_stream != (SocketStream *)NULL) { + return _stream->get_collect_tcp(); + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::set_collect_tcp_interval +// Access: Published +// Description: See SocketStream::set_collect_tcp_interval(). +//////////////////////////////////////////////////////////////////// +INLINE void SocketStreamRecorder:: +set_collect_tcp_interval(double interval) { + if (_stream != (SocketStream *)NULL) { + _stream->set_collect_tcp_interval(interval); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::get_collect_tcp_interval +// Access: Published +// Description: See SocketStream::get_collect_tcp_interval(). +//////////////////////////////////////////////////////////////////// +INLINE double SocketStreamRecorder:: +get_collect_tcp_interval() const { + if (_stream != (SocketStream *)NULL) { + return _stream->get_collect_tcp_interval(); + } + return 0.0; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::consider_flush +// Access: Published +// Description: See SocketStream::consider_flush() +//////////////////////////////////////////////////////////////////// +INLINE bool SocketStreamRecorder:: +consider_flush() { + if (_stream != (SocketStream *)NULL) { + return _stream->consider_flush(); + } + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::flush +// Access: Published +// Description: See SocketStream::flush() +//////////////////////////////////////////////////////////////////// +INLINE bool SocketStreamRecorder:: +flush() { + if (_stream != (SocketStream *)NULL) { + return _stream->flush(); + } + return true; +} diff --git a/panda/src/recorder/socketStreamRecorder.cxx b/panda/src/recorder/socketStreamRecorder.cxx new file mode 100644 index 0000000000..181b176181 --- /dev/null +++ b/panda/src/recorder/socketStreamRecorder.cxx @@ -0,0 +1,162 @@ +// Filename: socketStreamRecorder.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 "socketStreamRecorder.h" +#include "recorderController.h" +#include "bamReader.h" +#include "bamWriter.h" + +#ifdef HAVE_SSL + +TypeHandle SocketStreamRecorder::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::receive_datagram +// Access: Public +// Description: Receives a datagram over the socket by expecting a +// little-endian 16-bit byte count as a prefix. If the +// socket stream is non-blocking, may return false if +// the data is not available; otherwise, returns false +// only if the socket closes. +//////////////////////////////////////////////////////////////////// +bool SocketStreamRecorder:: +receive_datagram(Datagram &dg) { + if (is_playing()) { + // If we're playing back data, the datagrams come only from the + // queue, not from the live connection. + if (!_data.empty()) { + dg = _data.front(); + _data.pop_front(); + return true; + } + + return false; + + } else { + // If we're not in playback mode, forward the request to the + // connection. + bool got_data = false; + if (_stream != (SocketStream *)NULL) { + got_data = _stream->receive_datagram(dg); + } + + if (got_data && is_recording()) { + // If we're in recording mode, save the data. + _data.push_back(dg); + } + + return got_data; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::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 SocketStreamRecorder:: +record_frame(BamWriter *manager, Datagram &dg) { + nassertv(is_recording()); + dg.add_bool(_closed); + dg.add_uint16(_data.size()); + for (Data::iterator di = _data.begin(); di != _data.end(); ++di) { + dg.add_string((*di).get_message()); + } + _data.clear(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::play_frame +// Access: Public, Virtual +// Description: Reloads the most recent data collected from the +// indicated datagram. +//////////////////////////////////////////////////////////////////// +void SocketStreamRecorder:: +play_frame(DatagramIterator &scan, BamReader *manager) { + nassertv(is_playing()); + _closed = scan.get_bool(); + + int num_packets = scan.get_uint16(); + for (int i = 0; i < num_packets; i++) { + string packet = scan.get_string(); + _data.push_back(Datagram(packet)); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// Lens. +//////////////////////////////////////////////////////////////////// +void SocketStreamRecorder:: +register_with_read_factory() { + RecorderController::get_factory()->register_factory(get_class_type(), make_recorder); +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::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 SocketStreamRecorder:: +write_recorder(BamWriter *manager, Datagram &dg) { + RecorderBase::write_recorder(manager, dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::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 *SocketStreamRecorder:: +make_recorder(const FactoryParams ¶ms) { + SocketStreamRecorder *node = new SocketStreamRecorder; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + node->fillin_recorder(scan, manager); + + return node; +} + +//////////////////////////////////////////////////////////////////// +// Function: SocketStreamRecorder::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 SocketStreamRecorder. +//////////////////////////////////////////////////////////////////// +void SocketStreamRecorder:: +fillin_recorder(DatagramIterator &scan, BamReader *manager) { + RecorderBase::fillin_recorder(scan, manager); +} + +#endif // HAVE_SSL diff --git a/panda/src/recorder/socketStreamRecorder.h b/panda/src/recorder/socketStreamRecorder.h new file mode 100644 index 0000000000..427ad0a0d7 --- /dev/null +++ b/panda/src/recorder/socketStreamRecorder.h @@ -0,0 +1,109 @@ +// Filename: socketStreamRecorder.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 SOCKETSTREAMRECORDER_H +#define SOCKETSTREAMRECORDER_H + +#include "pandabase.h" +#include "socketStream.h" +#include "pdeque.h" + +class BamReader; +class BamWriter; +class FactoryParams; + +// At the present, this module is not compiled if OpenSSL is not +// available, since in that case socketStream.h is not compiled +// either. + +#ifdef HAVE_SSL + +//////////////////////////////////////////////////////////////////// +// Class : SocketStreamRecorder +// Description : Records any data received from the indicated socket +// stream. On playback, it will act as if the incoming +// data is coming over the wire again even if an actual +// connection is not available. +// +// Outbound data will not be recorded, but will be sent +// straight through to the socket if it is connected, or +// silently ignored if it is not. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA SocketStreamRecorder : public RecorderBase { +PUBLISHED: + INLINE SocketStreamRecorder(); + INLINE SocketStreamRecorder(SocketStream *stream, bool owns_stream); + INLINE ~SocketStreamRecorder(); + + bool receive_datagram(Datagram &dg); + INLINE bool send_datagram(const Datagram &dg); + + INLINE bool is_closed(); + INLINE void close(); + + INLINE void set_collect_tcp(bool collect_tcp); + INLINE bool get_collect_tcp() const; + INLINE void set_collect_tcp_interval(double interval); + INLINE double get_collect_tcp_interval() const; + + INLINE bool consider_flush(); + INLINE bool flush(); + +public: + virtual void record_frame(BamWriter *manager, Datagram &dg); + virtual void play_frame(DatagramIterator &scan, BamReader *manager); + +private: + SocketStream *_stream; + bool _owns_stream; + + typedef pdeque Data; + Data _data; + bool _closed; + +public: + static void register_with_read_factory(); + virtual void write_recorder(BamWriter *manager, Datagram &dg); + +protected: + static RecorderBase *make_recorder(const FactoryParams ¶ms); + void fillin_recorder(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + RecorderBase::init_type(); + register_type(_type_handle, "SocketStreamRecorder", + 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; +}; + +#include "socketStreamRecorder.I" + +#endif // HAVE_SSL + +#endif // SOCKETSTREAMRECORDER_H diff --git a/panda/src/tform/config_tform.cxx b/panda/src/tform/config_tform.cxx index 39de4bab42..a343b1a381 100644 --- a/panda/src/tform/config_tform.cxx +++ b/panda/src/tform/config_tform.cxx @@ -26,7 +26,7 @@ #include "trackball.h" #include "transform2sg.h" -#include +#include "dconfig.h" Configure(config_tform); NotifyCategoryDef(tform, ""); diff --git a/panda/src/tform/driveInterface.cxx b/panda/src/tform/driveInterface.cxx index 3b1aa28c72..6f9a85b4f9 100644 --- a/panda/src/tform/driveInterface.cxx +++ b/panda/src/tform/driveInterface.cxx @@ -109,10 +109,10 @@ DriveInterface(const string &name) : _xy_input = define_input("xy", EventStoreVec2::get_class_type()); _button_events_input = define_input("button_events", ButtonEventList::get_class_type()); - _transform_output = define_output("transform", EventStoreTransform::get_class_type()); + _transform_output = define_output("transform", TransformState::get_class_type()); _velocity_output = define_output("velocity", EventStoreVec3::get_class_type()); - _transform = new EventStoreTransform(TransformState::make_identity()); + _transform = TransformState::make_identity(); _velocity = new EventStoreVec3(LVector3f::zero()); _forward_speed = drive_forward_speed; @@ -219,7 +219,7 @@ get_mat() { //////////////////////////////////////////////////////////////////// void DriveInterface:: force_dgraph() { - _transform->set_value(TransformState::make_pos_hpr(_xyz, _hpr)); + _transform = TransformState::make_pos_hpr(_xyz, _hpr); _velocity->set_value(_vel); DataNodeTransmit output; @@ -429,13 +429,13 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { // We only trap button down events if (a) the mouse is in the // window, and (b) we aren't set to ignore the mouse. if (got_mouse && !_ignore_mouse) { - _mods.add_event(be); + be.update_mods(_mods); } } else { // However, we always trap button up events, so we don't get // confused and believe a button is still being held down when // it is not. - _mods.add_event(be); + be.update_mods(_mods); } if (be._button == KeyboardButton::up()) { @@ -452,7 +452,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { } apply(x, y, _mods.is_any_down()); - _transform->set_value(TransformState::make_pos_hpr(_xyz, _hpr)); + _transform = TransformState::make_pos_hpr(_xyz, _hpr); _velocity->set_value(_vel); output.set_data(_transform_output, EventParameter(_transform)); output.set_data(_velocity_output, EventParameter(_velocity)); diff --git a/panda/src/tform/driveInterface.h b/panda/src/tform/driveInterface.h index e397fd725f..f583d26f4e 100644 --- a/panda/src/tform/driveInterface.h +++ b/panda/src/tform/driveInterface.h @@ -172,7 +172,7 @@ private: int _transform_output; int _velocity_output; - PT(EventStoreTransform) _transform; + CPT(TransformState) _transform; PT(EventStoreVec3) _velocity; // This is the smallest meaningful value we can set on the hpr via diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index 0719a78388..a8b12c80ff 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/panda/src/tform/mouseWatcher.cxx @@ -895,7 +895,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { int num_events = button_events->get_num_events(); for (int i = 0; i < num_events; i++) { const ButtonEvent &be = button_events->get_event(i); - _mods.add_event(be); + be.update_mods(_mods); switch (be._type) { case ButtonEvent::T_down: diff --git a/panda/src/tform/mouseWatcherRegion.h b/panda/src/tform/mouseWatcherRegion.h index a384a8fd4e..52f6cfe783 100644 --- a/panda/src/tform/mouseWatcherRegion.h +++ b/panda/src/tform/mouseWatcherRegion.h @@ -22,7 +22,7 @@ #include "pandabase.h" #include "namable.h" -#include "typedReferenceCount.h" +#include "typedWritableReferenceCount.h" #include "luse.h" #include "buttonHandle.h" #include "modifierButtons.h" @@ -34,7 +34,7 @@ class MouseWatcherParameter; // Description : This is the class that defines a rectangular region // on the screen for the MouseWatcher. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA MouseWatcherRegion : public TypedReferenceCount, public Namable { +class EXPCL_PANDA MouseWatcherRegion : public TypedWritableReferenceCount, public Namable { PUBLISHED: INLINE MouseWatcherRegion(const string &name, float left, float right, float bottom, float top); @@ -98,10 +98,10 @@ public: return _type_handle; } static void init_type() { - TypedReferenceCount::init_type(); + TypedWritableReferenceCount::init_type(); Namable::init_type(); register_type(_type_handle, "MouseWatcherRegion", - TypedReferenceCount::get_class_type(), + TypedWritableReferenceCount::get_class_type(), Namable::get_class_type()); } virtual TypeHandle get_type() const { diff --git a/panda/src/tform/tform_composite1.cxx b/panda/src/tform/tform_composite1.cxx index 36f27f3384..ff5fd652ab 100644 --- a/panda/src/tform/tform_composite1.cxx +++ b/panda/src/tform/tform_composite1.cxx @@ -1,4 +1,3 @@ - #include "buttonThrower.cxx" #include "config_tform.cxx" #include "driveInterface.cxx" diff --git a/panda/src/tform/trackball.cxx b/panda/src/tform/trackball.cxx index f346f0292d..e90588565e 100644 --- a/panda/src/tform/trackball.cxx +++ b/panda/src/tform/trackball.cxx @@ -43,9 +43,9 @@ Trackball(const string &name) : _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type()); _button_events_input = define_input("button_events", ButtonEventList::get_class_type()); - _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(); _rotscale = 0.3f; _fwdscale = 0.3f; @@ -570,6 +570,6 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) { } // Now send our matrix down the pipe. - _transform->set_value(TransformState::make_mat(_mat)); + _transform = TransformState::make_mat(_mat); output.set_data(_transform_output, EventParameter(_transform)); } diff --git a/panda/src/tform/trackball.h b/panda/src/tform/trackball.h index 80b87d00cd..75e1ef9f94 100644 --- a/panda/src/tform/trackball.h +++ b/panda/src/tform/trackball.h @@ -135,7 +135,7 @@ private: // outputs int _transform_output; - PT(EventStoreTransform) _transform; + CPT(TransformState) _transform; public: static TypeHandle get_class_type() { diff --git a/panda/src/tform/transform2sg.cxx b/panda/src/tform/transform2sg.cxx index f2e8f27533..881db922f7 100644 --- a/panda/src/tform/transform2sg.cxx +++ b/panda/src/tform/transform2sg.cxx @@ -31,7 +31,7 @@ Transform2SG:: Transform2SG(const string &name) : DataNode(name) { - _transform_input = define_input("transform", EventStoreTransform::get_class_type()); + _transform_input = define_input("transform", TransformState::get_class_type()); _node = NULL; } @@ -74,11 +74,10 @@ get_node() const { void Transform2SG:: do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &) { if (input.has_data(_transform_input)) { - const EventStoreTransform *transform; + const TransformState *transform; DCAST_INTO_V(transform, input.get_data(_transform_input).get_ptr()); - CPT(TransformState) ts = transform->get_value(); if (_node != (PandaNode *)NULL) { - _node->set_transform(ts); + _node->set_transform(transform); } } }