From 0a64bdb33bd0ff21446f102342d2a2160193ec3f Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 24 Jan 2015 12:52:40 +0100 Subject: [PATCH] Fix MouseRecorder & let PandaNode inherit from TypedWritableReferenceCount --- dtool/src/dtoolbase/dtoolbase_cc.h | 15 +- panda/src/bullet/bulletContactCallbacks.h | 9 +- panda/src/pgraph/light.h | 12 +- panda/src/pgraph/pandaNode.cxx | 14 +- panda/src/pgraph/pandaNode.h | 6 +- panda/src/recorder/mouseRecorder.cxx | 16 +- panda/src/recorder/mouseRecorder.h | 6 +- panda/src/recorder/recorderBase.h | 16 +- panda/src/recorder/recorderController.cxx | 54 +-- panda/src/recorder/recorderFrame.cxx | 19 +- panda/src/recorder/recorderTable.I | 63 ++- panda/src/recorder/recorderTable.cxx | 98 +++-- panda/src/recorder/recorderTable.h | 21 +- panda/src/recorder/socketStreamRecorder.h | 6 +- panda/src/tform/Sources.pp | 16 +- panda/src/tform/config_tform.cxx | 2 + panda/src/tform/mouseWatcher.cxx | 114 +++--- panda/src/tform/mouseWatcher.h | 22 +- panda/src/tform/mouseWatcherBase.cxx | 443 ++++++++++++++++++++++ panda/src/tform/mouseWatcherBase.h | 113 ++++++ panda/src/tform/mouseWatcherGroup.cxx | 427 --------------------- panda/src/tform/mouseWatcherGroup.h | 79 +--- panda/src/tform/p3tform_composite2.cxx | 1 + 23 files changed, 854 insertions(+), 718 deletions(-) create mode 100644 panda/src/tform/mouseWatcherBase.cxx create mode 100644 panda/src/tform/mouseWatcherBase.h diff --git a/dtool/src/dtoolbase/dtoolbase_cc.h b/dtool/src/dtoolbase/dtoolbase_cc.h index ad5caaa327..31c4fa0514 100644 --- a/dtool/src/dtoolbase/dtoolbase_cc.h +++ b/dtool/src/dtoolbase/dtoolbase_cc.h @@ -35,6 +35,8 @@ using namespace std; #define TYPENAME typename #define CONSTEXPR #define NOEXCEPT noexcept +#define FINAL +#define OVERRIDE #define EXPORT_TEMPLATE_CLASS(expcl, exptp, classname) @@ -121,6 +123,7 @@ typedef ios::seekdir ios_seekdir; #define INLINE inline #endif +// Determine the availability of C++11 features. #if defined(__has_extension) // Clang magic. # if __has_extension(cxx_constexpr) # define CONSTEXPR constexpr @@ -135,20 +138,30 @@ typedef ios::seekdir ios_seekdir; # if __has_extension(cxx_rvalue_references) && (__cplusplus >= 201103L) # define USE_MOVE_SEMANTICS # endif +# if __has_extension(cxx_override_control) +# define FINAL final +# define OVERRIDE override +# endif #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) && (__cplusplus >= 201103L) // noexcept was introduced in GCC 4.6, constexpr in GCC 4.7, rvalue refs in // GCC 4.3. However, GCC only started defining __cplusplus properly in 4.7. # define CONSTEXPR constexpr # define NOEXCEPT noexcept # define USE_MOVE_SEMANTICS +# define FINAL final +# define OVERRIDE override #elif defined(_MSC_VER) && _MSC_VER >= 1600 -// MSVC 2010 has move semantics. +// MSVC 2010 has move semantics. Not much else. # define CONSTEXPR INLINE # define NOEXCEPT throw() # define USE_MOVE_SEMANTICS +# define FINAL +# define OVERRIDE #else # define CONSTEXPR INLINE # define NOEXCEPT +# define FINAL +# define OVERRIDE #endif #if defined(WIN32_VC) && !defined(LINK_ALL_STATIC) && defined(EXPORT_TEMPLATES) diff --git a/panda/src/bullet/bulletContactCallbacks.h b/panda/src/bullet/bulletContactCallbacks.h index e0c3a31b57..0f6150c965 100644 --- a/panda/src/bullet/bulletContactCallbacks.h +++ b/panda/src/bullet/bulletContactCallbacks.h @@ -25,7 +25,6 @@ #include "event.h" #include "eventQueue.h" #include "eventParameter.h" -#include "eventStorePandaNode.h" #include "pandaNode.h" struct UserPersitentData { @@ -77,8 +76,8 @@ contact_added_callback(btManifoldPoint &cp, if (bullet_enable_contact_events) { Event *event = new Event("bullet-contact-added"); - event->add_parameter(EventParameter(new EventStorePandaNode(node0))); - event->add_parameter(EventParameter(new EventStorePandaNode(node1))); + event->add_parameter(EventParameter(node0)); + event->add_parameter(EventParameter(node1)); EventQueue::get_global_event_queue()->queue_event(event); } @@ -137,8 +136,8 @@ contact_destroyed_callback(void *userPersistentData) { if (bullet_enable_contact_events) { Event *event = new Event("bullet-contact-destroyed"); - event->add_parameter(EventParameter(new EventStorePandaNode(data->node0))); - event->add_parameter(EventParameter(new EventStorePandaNode(data->node1))); + event->add_parameter(EventParameter(data->node0)); + event->add_parameter(EventParameter(data->node1)); EventQueue::get_global_event_queue()->queue_event(event); } diff --git a/panda/src/pgraph/light.h b/panda/src/pgraph/light.h index 074f3a2f46..50b5ff487c 100644 --- a/panda/src/pgraph/light.h +++ b/panda/src/pgraph/light.h @@ -39,11 +39,7 @@ class GraphicsStateGuardianBase; // arbitrary point to define the coordinate system of // effect. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PGRAPH Light : virtual public ReferenceCount { - // We inherit from ReferenceCount instead of TypedReferenceCount so - // that LightNode does not inherit from TypedObject twice. Note - // that we also inherit virtually from ReferenceCount for the same - // reason. +class EXPCL_PANDA_PGRAPH Light { PUBLISHED: INLINE Light(); INLINE Light(const Light ©); @@ -66,7 +62,7 @@ public: int light_id)=0; virtual bool get_vector_to_light(LVector3 &result, - const LPoint3 &from_object_point, + const LPoint3 &from_object_point, const LMatrix4 &to_object_space); GeomNode *get_viz(); @@ -76,7 +72,7 @@ public: protected: virtual void fill_viz_geom(GeomNode *viz_geom); INLINE void mark_viz_stale(); - + // This enumerated class defines the relative class priority of // different kinds of lights. This hierarchy is only used to // resolve multiple lights of the same priority specified by @@ -135,7 +131,7 @@ public: virtual TypeHandle get_type() const { return get_class_type(); } - + private: static TypeHandle _type_handle; }; diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index ac32a6c341..d4c683f7ad 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -142,8 +142,7 @@ PandaNode:: //////////////////////////////////////////////////////////////////// PandaNode:: PandaNode(const PandaNode ©) : - ReferenceCount(copy), - TypedWritable(copy), + TypedWritableReferenceCount(copy), Namable(copy), _paths_lock("PandaNode::_paths_lock"), _dirty_prev_transform(false) @@ -209,17 +208,6 @@ operator = (const PandaNode ©) { nassertv(false); } -//////////////////////////////////////////////////////////////////// -// Function: PandaNode::as_reference_count -// Access: Public, Virtual -// Description: Returns the pointer cast to a ReferenceCount pointer, -// if it is in fact of that type. -//////////////////////////////////////////////////////////////////// -ReferenceCount *PandaNode:: -as_reference_count() { - return this; -} - //////////////////////////////////////////////////////////////////// // Function: PandaNode::dupe_for_flatten // Access: Public, Virtual diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 6a184a7123..0a1c60d491 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -69,9 +69,8 @@ class GraphicsStateGuardianBase; // is the base class of all specialized nodes, and also // serves as a generic node with no special properties. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PGRAPH PandaNode : public TypedWritable, public Namable, - public LinkedListNode, - virtual public ReferenceCount { +class EXPCL_PANDA_PGRAPH PandaNode : public TypedWritableReferenceCount, + public Namable, public LinkedListNode { PUBLISHED: PandaNode(const string &name); virtual ~PandaNode(); @@ -84,7 +83,6 @@ private: void operator = (const PandaNode ©); public: - virtual ReferenceCount *as_reference_count(); virtual PandaNode *dupe_for_flatten() const; virtual bool safe_to_flatten() const; diff --git a/panda/src/recorder/mouseRecorder.cxx b/panda/src/recorder/mouseRecorder.cxx index a71031409c..ec1475fbde 100644 --- a/panda/src/recorder/mouseRecorder.cxx +++ b/panda/src/recorder/mouseRecorder.cxx @@ -26,14 +26,16 @@ TypeHandle MouseRecorder::_type_handle; // Description: //////////////////////////////////////////////////////////////////// MouseRecorder:: -MouseRecorder(const string &name) : - DataNode(name) +MouseRecorder(const string &name) : + DataNode(name) { _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type()); + _pixel_size_input = define_input("pixel_size", 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()); + _pixel_size_output = define_output("pixel_size", EventStoreVec2::get_class_type()); _xy_output = define_output("xy", EventStoreVec2::get_class_type()); _button_events_output = define_output("button_events", ButtonEventList::get_class_type()); @@ -127,7 +129,7 @@ write(ostream &out, int indent_level) const { // calls. //////////////////////////////////////////////////////////////////// void MouseRecorder:: -do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, +do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, DataNodeTransmit &output) { bool has_mouse = false; LPoint2 mouse_xy; @@ -157,7 +159,7 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, mouse_pixel_xy = xy->get_value(); has_mouse = true; } - + // Look for button events. if (input.has_data(_button_events_input)) { const ButtonEventList *button_events; @@ -165,7 +167,7 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, _live_button_events->add_events(*button_events); } } - + // Now rebuild the output data for our children. if (has_mouse) { @@ -187,8 +189,10 @@ do_transmit_data(DataGraphTraverser *, const DataNodeTransmit &input, _mouse_pixel_xy = mouse_pixel_xy; _save_button_events->add_events(*_live_button_events); } -} + // We always pass the pixel_size data through. + output.set_data(_pixel_size_output, input.get_data(_pixel_size_input)); +} //////////////////////////////////////////////////////////////////// // Function: MouseRecorder::register_with_read_factory diff --git a/panda/src/recorder/mouseRecorder.h b/panda/src/recorder/mouseRecorder.h index 9e95405d27..503d8eb8cd 100644 --- a/panda/src/recorder/mouseRecorder.h +++ b/panda/src/recorder/mouseRecorder.h @@ -57,11 +57,13 @@ protected: private: // inputs int _pixel_xy_input; + int _pixel_size_input; int _xy_input; int _button_events_input; // outputs int _pixel_xy_output; + int _pixel_size_output; int _xy_output; int _button_events_output; @@ -79,6 +81,9 @@ public: virtual void write_datagram(BamWriter *manager, Datagram &dg); virtual void write_recorder(BamWriter *manager, Datagram &dg); + INLINE virtual void ref() const FINAL { ReferenceCount::ref(); }; + INLINE virtual bool unref() const FINAL { return ReferenceCount::unref(); }; + protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); static RecorderBase *make_recorder(const FactoryParams ¶ms); @@ -106,4 +111,3 @@ private: }; #endif - diff --git a/panda/src/recorder/recorderBase.h b/panda/src/recorder/recorderBase.h index 43df358776..922f751a65 100644 --- a/panda/src/recorder/recorderBase.h +++ b/panda/src/recorder/recorderBase.h @@ -46,8 +46,13 @@ class TypedWritable; // write_recorder() to do exactly the same thing as // write_datagram(), or they may choose to write // something slightly different. +// +// Most types of recorders should derive from Recorder, +// as it derives from ReferenceCount, except for +// MouseRecorder, which would otherwise doubly inherit +// from ReferenceCount. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_RECORDER RecorderBase : virtual public ReferenceCount { +class EXPCL_PANDA_RECORDER RecorderBase { protected: RecorderBase(); @@ -63,6 +68,11 @@ public: virtual void write_recorder(BamWriter *manager, Datagram &dg); + // We can't let RecorderBase inherit from ReferenceCount, so we + // define these so we can still manage the reference count. + virtual void ref() const=0; + virtual bool unref() const=0; + protected: void fillin_recorder(DatagramIterator &scan, BamReader *manager); @@ -72,7 +82,7 @@ private: F_playing = 0x0002, }; short _flags; - + public: static TypeHandle get_class_type() { return _type_handle; @@ -90,9 +100,9 @@ private: static TypeHandle _type_handle; friend class RecorderController; + friend class RecorderTable; }; #include "recorderBase.I" #endif - diff --git a/panda/src/recorder/recorderController.cxx b/panda/src/recorder/recorderController.cxx index 0495bf0ef2..712fe1c5ac 100644 --- a/panda/src/recorder/recorderController.cxx +++ b/panda/src/recorder/recorderController.cxx @@ -93,17 +93,11 @@ begin_record(const Filename &filename) { _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; - } + _user_table->set_flags(RecorderBase::F_recording); - recorder_cat.info() + recorder_cat.info() << "Recording session to " << _filename << "\n"; - + return true; } @@ -150,7 +144,7 @@ begin_playback(const Filename &filename) { // Start out by reading the RecorderHeader. TypedWritable *object = _reader->read_object(); - if (object == (TypedWritable *)NULL || + if (object == (TypedWritable *)NULL || !object->is_of_type(RecorderHeader::get_class_type())) { recorder_cat.error() << _filename << " does not contain a recorded session.\n"; @@ -176,7 +170,7 @@ begin_playback(const Filename &filename) { return false; } - recorder_cat.info() + recorder_cat.info() << "Playing back session from " << _filename << "\n"; return true; @@ -194,26 +188,14 @@ close() { _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; - } + _user_table->clear_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; - } + _active_table->clear_flags(RecorderBase::F_playing); } _dout.close(); _din.close(); @@ -244,7 +226,7 @@ record_frame() { RecorderFrame data(now, frame, _user_table_modified, _user_table); _user_table_modified = false; - + _writer->write_object(&data); } } @@ -300,27 +282,15 @@ play_frame() { 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; - } - + _active_table->clear_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; - } + _active_table->set_flags(RecorderBase::F_playing); } _next_frame->_table = _active_table; @@ -353,7 +323,7 @@ RecorderFrame *RecorderController:: read_frame() { TypedWritable *object = _reader->read_object(); - if (object == (TypedWritable *)NULL || + if (object == (TypedWritable *)NULL || !object->is_of_type(RecorderFrame::get_class_type())) { return NULL; } diff --git a/panda/src/recorder/recorderFrame.cxx b/panda/src/recorder/recorderFrame.cxx index 35697d0852..f2b95cae2b 100644 --- a/panda/src/recorder/recorderFrame.cxx +++ b/panda/src/recorder/recorderFrame.cxx @@ -30,14 +30,7 @@ TypeHandle RecorderFrame::_type_handle; 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); - } + _table->play_frame(scan, manager); // We expect to use up all of the data in the datagram. nassertv(scan.get_remaining_size() == 0); @@ -77,14 +70,8 @@ write_datagram(BamWriter *manager, Datagram &dg) { _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); - } + + _table->record_frame(manager, dg); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/recorder/recorderTable.I b/panda/src/recorder/recorderTable.I index e14812213b..95c364f26f 100644 --- a/panda/src/recorder/recorderTable.I +++ b/panda/src/recorder/recorderTable.I @@ -29,10 +29,8 @@ RecorderTable() { // Description: //////////////////////////////////////////////////////////////////// INLINE RecorderTable:: -RecorderTable(const RecorderTable ©) : - _recorders(copy._recorders), - _error(copy._error) -{ +RecorderTable(const RecorderTable ©) { + *this = copy; } //////////////////////////////////////////////////////////////////// @@ -44,13 +42,62 @@ INLINE void RecorderTable:: operator = (const RecorderTable ©) { _recorders = copy._recorders; _error = copy._error; + + Recorders::iterator ri; + for (ri = _recorders.begin(); ri != _recorders.end(); ++ri) { + ri->second->ref(); + } } //////////////////////////////////////////////////////////////////// -// Function: RecorderTable::Destructor +// Function: RecorderTable::add_recorder // Access: Published -// Description: +// Description: Adds the named recorder to the set of recorders. //////////////////////////////////////////////////////////////////// -INLINE RecorderTable:: -~RecorderTable() { +INLINE void RecorderTable:: +add_recorder(const string &name, RecorderBase *recorder) { + nassertv(recorder != (RecorderBase *)NULL); + recorder->ref(); + + std::pair result = + _recorders.insert(Recorders::value_type(name, recorder)); + + if (!result.second) { + // Take out the previous one first. + unref_delete(result.first->second); + result.first->second = recorder; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::get_recorder +// Access: Published +// Description: Returns the recorder with the indicated name, or NULL +// if there is no such recorder. +//////////////////////////////////////////////////////////////////// +INLINE 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. +//////////////////////////////////////////////////////////////////// +INLINE bool RecorderTable:: +remove_recorder(const string &name) { + Recorders::iterator ri = _recorders.find(name); + if (ri != _recorders.end()) { + unref_delete(ri->second); + _recorders.erase(ri); + return true; + } + return false; } diff --git a/panda/src/recorder/recorderTable.cxx b/panda/src/recorder/recorderTable.cxx index ee58ec4734..25b74c42e8 100644 --- a/panda/src/recorder/recorderTable.cxx +++ b/panda/src/recorder/recorderTable.cxx @@ -21,6 +21,19 @@ TypeHandle RecorderTable::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +RecorderTable:: +~RecorderTable() { + Recorders::iterator ri; + for (ri = _recorders.begin(); ri != _recorders.end(); ++ri) { + unref_delete(ri->second); + } +} + //////////////////////////////////////////////////////////////////// // Function: RecorderTable::merge_from // Access: Public @@ -47,12 +60,16 @@ merge_from(const RecorderTable &other) { } 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; + if ((*ri).second != recorder) { + recorder->ref(); + unref_delete((*ri).second); + (*ri).second = recorder; + } } else { recorder_cat.warning() - << "Keeping recorder " << name << " of type " - << (*ri).second->get_type() << " instead of recorder of type " + << "Keeping recorder " << name << " of type " + << (*ri).second->get_type() << " instead of recorder of type " << recorder->get_type() << "\n"; } } @@ -71,51 +88,73 @@ merge_from(const RecorderTable &other) { } //////////////////////////////////////////////////////////////////// -// Function: RecorderTable::add_recorder +// Function: RecorderTable::record_frame // Access: Published -// Description: Adds the named recorder to the set of recorders. +// Description: Calls record_frame on all recorders. //////////////////////////////////////////////////////////////////// void RecorderTable:: -add_recorder(const string &name, RecorderBase *recorder) { - _recorders[name] = recorder; +record_frame(BamWriter *manager, Datagram &dg) { + Recorders::iterator ri; + for (ri = _recorders.begin(); + ri != _recorders.end(); + ++ri) { + RecorderBase *recorder = (*ri).second; + recorder->record_frame(manager, dg); + } } //////////////////////////////////////////////////////////////////// -// Function: RecorderTable::get_recorder +// Function: RecorderTable::play_frame // Access: Published -// Description: Returns the recorder with the indicated name, or NULL -// if there is no such recorder. +// Description: Calls play_frame on all recorders. //////////////////////////////////////////////////////////////////// -RecorderBase *RecorderTable:: -get_recorder(const string &name) const { - Recorders::const_iterator ri = _recorders.find(name); - if (ri != _recorders.end()) { - return (*ri).second; +void RecorderTable:: +play_frame(DatagramIterator &scan, BamReader *manager) { + Recorders::iterator ri; + for (ri = _recorders.begin(); + ri != _recorders.end(); + ++ri) { + RecorderBase *recorder = (*ri).second; + recorder->play_frame(scan, manager); } - return NULL; } //////////////////////////////////////////////////////////////////// -// Function: RecorderTable::remove_recorder +// Function: RecorderTable::set_flags // Access: Published -// Description: Removes the named recorder from the table. Returns -// true if successful, false if there was no such -// recorder. +// Description: Sets the given flags on all recorders. //////////////////////////////////////////////////////////////////// -bool RecorderTable:: -remove_recorder(const string &name) { - Recorders::iterator ri = _recorders.find(name); - if (ri != _recorders.end()) { - _recorders.erase(ri); - return true; +void RecorderTable:: +set_flags(short flags) { + Recorders::iterator ri; + for (ri = _recorders.begin(); + ri != _recorders.end(); + ++ri) { + RecorderBase *recorder = (*ri).second; + recorder->_flags |= flags; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RecorderTable::clear_flags +// Access: Published +// Description: Clears the given flags on all recorders. +//////////////////////////////////////////////////////////////////// +void RecorderTable:: +clear_flags(short flags) { + Recorders::iterator ri; + for (ri = _recorders.begin(); + ri != _recorders.end(); + ++ri) { + RecorderBase *recorder = (*ri).second; + recorder->_flags &= ~flags; } - return false; } //////////////////////////////////////////////////////////////////// // Function: RecorderTable::write // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// void RecorderTable:: write(ostream &out, int indent_level) const { @@ -203,7 +242,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { FactoryParams fparams; fparams.add_param(new BamReaderParam(scan, manager)); - PT(RecorderBase) recorder = + RecorderBase *recorder = RecorderController::get_factory()->make_instance_more_general(type, fparams); if (recorder == (RecorderBase *)NULL) { recorder_cat.error() @@ -211,6 +250,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { _error = true; } else { + recorder->ref(); 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 index 50de33e199..f742717406 100644 --- a/panda/src/recorder/recorderTable.h +++ b/panda/src/recorder/recorderTable.h @@ -37,18 +37,25 @@ public: INLINE RecorderTable(); INLINE RecorderTable(const RecorderTable ©); INLINE void operator = (const RecorderTable ©); - INLINE ~RecorderTable(); + ~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); + INLINE void add_recorder(const string &name, RecorderBase *recorder); + INLINE RecorderBase *get_recorder(const string &name) const; + INLINE bool remove_recorder(const string &name); + + void record_frame(BamWriter *manager, Datagram &dg); + void play_frame(DatagramIterator &scan, BamReader *manager); + void set_flags(short flags); + void clear_flags(short flags); void write(ostream &out, int indent_level) const; - - typedef pmap Recorders; + // RecorderBase itself doesn't inherit from ReferenceCount, so + // we can't put a PT() around it. Instead, we manage the reference + // count using calls to ref() and unref(). + typedef pmap Recorders; Recorders _recorders; bool _error; @@ -60,7 +67,7 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/recorder/socketStreamRecorder.h b/panda/src/recorder/socketStreamRecorder.h index b7df26475d..1ad7af2b4e 100644 --- a/panda/src/recorder/socketStreamRecorder.h +++ b/panda/src/recorder/socketStreamRecorder.h @@ -42,7 +42,8 @@ class DatagramIterator; // straight through to the socket if it is connected, or // silently ignored if it is not. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_RECORDER SocketStreamRecorder : public RecorderBase { +class EXPCL_PANDA_RECORDER SocketStreamRecorder : public RecorderBase, + public ReferenceCount { PUBLISHED: INLINE SocketStreamRecorder(); INLINE SocketStreamRecorder(SocketStream *stream, bool owns_stream); @@ -78,6 +79,9 @@ public: static void register_with_read_factory(); virtual void write_recorder(BamWriter *manager, Datagram &dg); + INLINE virtual void ref() const FINAL { ReferenceCount::ref(); }; + INLINE virtual bool unref() const FINAL { return ReferenceCount::unref(); }; + protected: static RecorderBase *make_recorder(const FactoryParams ¶ms); void fillin_recorder(DatagramIterator &scan, BamReader *manager); diff --git a/panda/src/tform/Sources.pp b/panda/src/tform/Sources.pp index 4758570edc..d57c054cc2 100644 --- a/panda/src/tform/Sources.pp +++ b/panda/src/tform/Sources.pp @@ -7,7 +7,7 @@ p3grutil p3dgraph p3pgraph p3linmath p3display p3event p3putil p3gobj p3gsgbase \ p3mathutil p3device - #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx + #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx #define SOURCES \ buttonThrower.I buttonThrower.h \ @@ -16,12 +16,12 @@ mouseInterfaceNode.I mouseInterfaceNode.h \ mouseSubregion.I mouseSubregion.h \ mouseWatcher.I mouseWatcher.h \ - mouseWatcherGroup.h \ + mouseWatcherBase.h mouseWatcherGroup.h \ mouseWatcherParameter.I mouseWatcherParameter.h \ mouseWatcherRegion.I mouseWatcherRegion.h \ trackball.h \ - transform2sg.h - + transform2sg.h + #define INCLUDED_SOURCES \ buttonThrower.cxx \ config_tform.cxx \ @@ -29,10 +29,12 @@ mouseInterfaceNode.cxx \ mouseSubregion.cxx \ mouseWatcher.cxx \ + mouseWatcherBase.cxx \ mouseWatcherGroup.cxx \ - mouseWatcherParameter.cxx mouseWatcherRegion.cxx \ + mouseWatcherParameter.cxx + mouseWatcherRegion.cxx \ trackball.cxx \ - transform2sg.cxx + transform2sg.cxx #define INSTALL_HEADERS \ buttonThrower.I buttonThrower.h \ @@ -40,7 +42,7 @@ mouseInterfaceNode.I mouseInterfaceNode.h \ mouseSubregion.I mouseSubregion.h \ mouseWatcher.I mouseWatcher.h \ - mouseWatcherGroup.h \ + mouseWatcherBase.h mouseWatcherGroup.h \ mouseWatcherParameter.I mouseWatcherParameter.h \ mouseWatcherRegion.I mouseWatcherRegion.h \ trackball.h \ diff --git a/panda/src/tform/config_tform.cxx b/panda/src/tform/config_tform.cxx index fbe2e3b988..b5bcaf7ae0 100644 --- a/panda/src/tform/config_tform.cxx +++ b/panda/src/tform/config_tform.cxx @@ -18,6 +18,7 @@ #include "buttonThrower.h" #include "mouseSubregion.h" #include "mouseWatcher.h" +#include "mouseWatcherBase.h" #include "mouseWatcherGroup.h" #include "mouseWatcherRegion.h" #include "trackball.h" @@ -67,6 +68,7 @@ ConfigureFn(config_tform) { MouseInterfaceNode::init_type(); MouseSubregion::init_type(); MouseWatcher::init_type(); + MouseWatcherBase::init_type(); MouseWatcherGroup::init_type(); MouseWatcherRegion::init_type(); Trackball::init_type(); diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index f0b5f9d34e..8bc19ca2d7 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/panda/src/tform/mouseWatcher.cxx @@ -44,7 +44,7 @@ TypeHandle MouseWatcher::_type_handle; // Description: //////////////////////////////////////////////////////////////////// MouseWatcher:: -MouseWatcher(const string &name) : +MouseWatcher(const string &name) : DataNode(name) { _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type()); @@ -73,24 +73,24 @@ MouseWatcher(const string &name) : _button_down_display_region = (DisplayRegion *)NULL; _frame.set(-1.0f, 1.0f, -1.0f, 1.0f); - + _inactivity_timeout = inactivity_timeout; _has_inactivity_timeout = !IS_NEARLY_ZERO(_inactivity_timeout); - + _num_trail_recent = 0; _trail_log_duration = 0.0; _trail_log = new PointerEventList(); - + _inactivity_timeout_event = "inactivity_timeout"; _last_activity = 0.0; _inactivity_state = IS_active; - + // When this flag is true, the mouse pointer is allowed to be // "entered" into multiple regions simultaneously; when false, it // will only be "within" multiple regions, but "entered" into the // topmost of those. _enter_multiple = false; - + // When this flag is true, moving the pointer into a region is // enough to click it. The click is simulated with mouse button // one. @@ -128,7 +128,7 @@ remove_region(MouseWatcherRegion *region) { _preferred_button_down_region = (MouseWatcherRegion *)NULL; } - return MouseWatcherGroup::do_remove_region(region); + return MouseWatcherBase::do_remove_region(region); } //////////////////////////////////////////////////////////////////// @@ -156,7 +156,7 @@ get_over_region(const LPoint2 &pos) const { // regions the MouseWatcher will monitor each frame. // // Since the MouseWatcher itself inherits from -// MouseWatcherGroup, this operation is normally not +// MouseWatcherBase, this operation is normally not // necessary--you can simply add the Regions you care // about one at a time. Adding a complete group is // useful when you may want to explicitly remove the @@ -171,7 +171,7 @@ add_group(MouseWatcherGroup *group) { // See if the group is in the set/vector already PT(MouseWatcherGroup) pt = group; - Groups::const_iterator gi = + Groups::const_iterator gi = find(_groups.begin(), _groups.end(), pt); if (gi != _groups.end()) { // Already in the set, return false @@ -228,7 +228,7 @@ remove_group(MouseWatcherGroup *group) { // See if the group is in the set/vector PT(MouseWatcherGroup) pt = group; - Groups::iterator gi = + Groups::iterator gi = find(_groups.begin(), _groups.end(), pt); if (gi != _groups.end()) { // Found it, now erase it @@ -270,7 +270,7 @@ replace_group(MouseWatcherGroup *old_group, MouseWatcherGroup *new_group) { #ifndef NDEBUG if (!_show_regions_render2d.is_empty()) { old_group->do_hide_regions(); - new_group->do_show_regions(_show_regions_render2d, _show_regions_bin_name, + new_group->do_show_regions(_show_regions_render2d, _show_regions_bin_name, _show_regions_draw_order); } #endif // NDEBUG @@ -327,7 +327,7 @@ replace_group(MouseWatcherGroup *old_group, MouseWatcherGroup *new_group) { // Add the new group, if it's not already there. PT(MouseWatcherGroup) pt = new_group; - Groups::iterator gi = + Groups::iterator gi = find(_groups.begin(), _groups.end(), pt); if (gi == _groups.end()) { _groups.push_back(new_group); @@ -338,7 +338,7 @@ replace_group(MouseWatcherGroup *old_group, MouseWatcherGroup *new_group) { new_group->do_update_regions(); } #endif // NDEBUG - + // Remove the old group, if it is already there. pt = old_group; gi = find(_groups.begin(), _groups.end(), pt); @@ -476,17 +476,17 @@ update_trail_node() { if (_trail_log->get_num_events() < 2) { return; } - + PT(GeomVertexData) data = new GeomVertexData ("mouseTrailSegs", GeomVertexFormat::get_v3(), Geom::UH_static); - + GeomVertexWriter vertex(data, InternalName::get_vertex()); - + PT(GeomLinestrips) lines = new GeomLinestrips(Geom::UH_static); - + double xscale = 2.0 / _pixel_size->get_value().get_x(); double yscale = 2.0 / _pixel_size->get_value().get_y(); - + for (int i=0; i<(int)_trail_log->get_num_events(); i++) { double x = (_trail_log->get_xpos(i) * xscale) - 1.0; double y = (_trail_log->get_ypos(i) * yscale) - 1.0; @@ -565,7 +565,7 @@ void MouseWatcher:: write(ostream &out, int indent_level) const { indent(out, indent_level) << "MouseWatcher " << get_name() << ":\n"; - MouseWatcherGroup::write(out, indent_level + 2); + MouseWatcherBase::write(out, indent_level + 2); LightMutexHolder holder(_lock); if (!_groups.empty()) { @@ -620,11 +620,11 @@ get_over_regions(MouseWatcher::Regions ®ions, const LPoint2 &pos) const { for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) { MouseWatcherRegion *region = (*ri); const LVecBase4 &frame = region->get_frame(); - + if (region->get_active() && mx >= frame[0] && mx <= frame[1] && my >= frame[2] && my <= frame[3]) { - + regions.push_back(region); } } @@ -750,9 +750,9 @@ set_current_regions(MouseWatcher::Regions ®ions) { // Determine which is the "preferred region", if any. This is the // topmost region that the mouse cursor is over, and the one that // we are considered "entered" into. - MouseWatcherRegion *new_preferred_region = + MouseWatcherRegion *new_preferred_region = get_preferred_region(_current_regions); - + if (_button_down && new_preferred_region != _preferred_button_down_region) { // If the button's being held down, we're only allowed to select // the preferred button down region. @@ -786,9 +786,9 @@ clear_current_regions() { MouseWatcherParameter param; param.set_modifier_buttons(_mods); param.set_mouse(_mouse); - + Regions::const_iterator old_ri = _current_regions.begin(); - + while (old_ri != _current_regions.end()) { // Here's a region we don't have any more. MouseWatcherRegion *old_region = (*old_ri); @@ -796,7 +796,7 @@ clear_current_regions() { throw_event_pattern(_leave_pattern, old_region, ButtonHandle::none()); ++old_ri; } - + _current_regions.clear(); if (_preferred_region != (MouseWatcherRegion *)NULL) { @@ -815,9 +815,9 @@ clear_current_regions() { // assumes the lock is already held. //////////////////////////////////////////////////////////////////// void MouseWatcher:: -do_show_regions(const NodePath &render2d, const string &bin_name, +do_show_regions(const NodePath &render2d, const string &bin_name, int draw_order) { - MouseWatcherGroup::do_show_regions(render2d, bin_name, draw_order); + MouseWatcherBase::do_show_regions(render2d, bin_name, draw_order); _show_regions_render2d = render2d; _show_regions_bin_name = bin_name; _show_regions_draw_order = draw_order; @@ -839,7 +839,7 @@ do_show_regions(const NodePath &render2d, const string &bin_name, //////////////////////////////////////////////////////////////////// void MouseWatcher:: do_hide_regions() { - MouseWatcherGroup::do_hide_regions(); + MouseWatcherBase::do_hide_regions(); _show_regions_render2d = NodePath(); _show_regions_bin_name = string(); _show_regions_draw_order = 0; @@ -1027,7 +1027,7 @@ press(ButtonHandle button, bool keyrepeat) { if (MouseButton::is_mouse_button(button)) { // Mouse buttons are inextricably linked to the mouse position. - + if (!_button_down) { _preferred_button_down_region = _preferred_region; } @@ -1043,7 +1043,7 @@ press(ButtonHandle button, bool keyrepeat) { _preferred_button_down_region, button); } } - + } else { // It's a keyboard button; therefore, send the event to every // region that wants keyboard buttons, regardless of the mouse @@ -1084,7 +1084,7 @@ release(ButtonHandle button) { if (MouseButton::is_mouse_button(button)) { // Button up. Send the up event associated with the region(s) we // were over when the button went down. - + // There is some danger of losing button-up events here. If // more than one button goes down together, we won't detect // both of the button-up events properly. @@ -1097,7 +1097,7 @@ release(ButtonHandle button) { _button_down = false; _preferred_button_down_region = (MouseWatcherRegion *)NULL; - + } else { // It's a keyboard button; therefore, send the event to every // region that wants keyboard buttons, regardless of the mouse @@ -1105,7 +1105,7 @@ release(ButtonHandle button) { if (_preferred_region != (MouseWatcherRegion *)NULL) { _preferred_region->release(param); } - + param.set_outside(true); global_keyboard_release(param); } @@ -1166,7 +1166,7 @@ keystroke(int keycode) { // highlighted in the IME. //////////////////////////////////////////////////////////////////// void MouseWatcher:: -candidate(const wstring &candidate_string, size_t highlight_start, +candidate(const wstring &candidate_string, size_t highlight_start, size_t highlight_end, size_t cursor_pos) { nassertv(_lock.debug_is_locked()); @@ -1275,7 +1275,7 @@ global_keyboard_release(const MouseWatcherParameter ¶m) { //////////////////////////////////////////////////////////////////// // Function: MouseWatcher::enter_region // Access: Protected -// Description: Called internally to indicate the mouse pointer is +// Description: Called internally to indicate the mouse pointer is // favoring the indicated region. //////////////////////////////////////////////////////////////////// void MouseWatcher:: @@ -1326,7 +1326,7 @@ set_no_mouse() { _geometry->set_overall_hidden(true); } } - + _has_mouse = false; clear_current_regions(); } @@ -1350,11 +1350,11 @@ set_mouse(const LVecBase2 &xy, const LVecBase2 &pixel_xy) { _geometry->set_overall_hidden(false); } } - + _has_mouse = true; _mouse = xy; _mouse_pixel = pixel_xy; - + Regions regions; get_over_regions(regions, _mouse); set_current_regions(regions); @@ -1366,7 +1366,7 @@ set_mouse(const LVecBase2 &xy, const LVecBase2 &pixel_xy) { // Description: If we send any keyboard events to a region that has // the SF_other_button suppress flag set, that means we // should not send the keyboard event along the data -// graph. +// graph. // // This method is called as each keyboard event is sent // to a region; it should update the internal @@ -1436,7 +1436,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, // The mouse is outside the display region, even though it's // within the window. This is considered not having a mouse. set_no_mouse(); - + // This also means we should suppress mouse button events below us. _internal_suppress |= MouseWatcherRegion::SF_mouse_button; } @@ -1469,7 +1469,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, if (_num_trail_recent > _trail_log->get_num_events()) { _num_trail_recent = _trail_log->get_num_events(); } - + // If the mouse is over a particular region, or still considered // owned by a region because of a recent button-down event, that // region determines whether we suppress events below us. @@ -1561,7 +1561,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, if (_has_inactivity_timeout) { if (activity) { note_activity(); - + } else { double now = ClockObject::get_global_clock()->get_frame_time(); double elapsed = now - _last_activity; @@ -1575,10 +1575,10 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, case IS_inactive: break; - + case IS_active_to_inactive: break; - + case IS_inactive_to_active: _inactivity_state = IS_inactive; break; @@ -1591,7 +1591,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, case IS_active: case IS_inactive: break; - + case IS_active_to_inactive: // "Release" all of the currently-held buttons. if (tform_cat.is_debug()) { @@ -1610,7 +1610,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, _inactivity_state = IS_inactive; throw_event(_inactivity_timeout_event); break; - + case IS_inactive_to_active: // "Press" all of the buttons we "released" before. { @@ -1643,20 +1643,20 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, for (int i = 0; i < num_events; i++) { const ButtonEvent &be = new_button_events.get_event(i); bool suppress = true; - - if (be._type != ButtonEvent::T_keystroke && + + if (be._type != ButtonEvent::T_keystroke && MouseButton::is_mouse_button(be._button)) { suppress = ((suppress_buttons & MouseWatcherRegion::SF_mouse_button) != 0); } else { suppress = ((suppress_buttons & MouseWatcherRegion::SF_other_button) != 0); } - + if (!suppress || be._type == ButtonEvent::T_up) { // Don't suppress this button event; pass it through. _button_events->add_event(be); } } - + if (_button_events->get_num_events() != 0) { output.set_data(_button_events_output, EventParameter(_button_events)); } @@ -1673,7 +1673,7 @@ do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input, // leaves f and p unchanged, and returns false. //////////////////////////////////////////////////////////////////// bool MouseWatcher:: -constrain_display_region(DisplayRegion *display_region, +constrain_display_region(DisplayRegion *display_region, LVecBase2 &f, LVecBase2 &p, Thread *current_thread) { if (!_button_down) { @@ -1700,7 +1700,7 @@ constrain_display_region(DisplayRegion *display_region, DisplayRegionPipelineReader dr_reader(display_region, current_thread); PN_stdfloat left, right, bottom, top; dr_reader.get_dimensions(left, right, bottom, top); - + // Need to translate this into DisplayRegion [0, 1] space PN_stdfloat x = (f[0] + 1.0f) / 2.0f; PN_stdfloat y = (f[1] + 1.0f) / 2.0f; @@ -1715,18 +1715,18 @@ constrain_display_region(DisplayRegion *display_region, if (_button_down) { _button_down_display_region = display_region; } - + // Scale in DR space PN_stdfloat xp = (x - left) / (right - left); // Translate back into [-1, 1] space PN_stdfloat xpp = (xp * 2.0f) - 1.0f; - + PN_stdfloat yp = (y - bottom) / (top - bottom); PN_stdfloat ypp = (yp * 2.0f) - 1.0f; - + int xo, yo, w, h; dr_reader.get_region_pixels_i(xo, yo, w, h); - + f.set(xpp, ypp); p.set(p[0] - xo, p[1] - yo); return true; diff --git a/panda/src/tform/mouseWatcher.h b/panda/src/tform/mouseWatcher.h index 447114498f..c5e8c145e1 100644 --- a/panda/src/tform/mouseWatcher.h +++ b/panda/src/tform/mouseWatcher.h @@ -61,11 +61,11 @@ class DisplayRegion; // it took to get there. This information is mainly useful // for gesture-recognition code. To use trail logging, // you need to enable the generation of pointer events -// in the GraphicsWindowInputDevice and set the trail +// in the GraphicsWindowInputDevice and set the trail // log duration in the MouseWatcher. Otherwise, the // trail log will be empty. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_TFORM MouseWatcher : public DataNode, public MouseWatcherGroup { +class EXPCL_PANDA_TFORM MouseWatcher : public DataNode, public MouseWatcherBase { PUBLISHED: MouseWatcher(const string &name = ""); ~MouseWatcher(); @@ -143,14 +143,14 @@ PUBLISHED: INLINE void set_inactivity_timeout_event(const string &event); INLINE const string &get_inactivity_timeout_event() const; - + INLINE CPT(PointerEventList) get_trail_log() const; INLINE int num_trail_recent() const; void set_trail_log_duration(double duration); PT(GeomNode) get_trail_node(); void clear_trail_node(); INLINE void clear_trail_log(); - + void note_activity(); public: @@ -179,7 +179,7 @@ protected: MouseWatcherRegion *region); static bool has_region_in(const Regions ®ions, MouseWatcherRegion *region); - + void throw_event_pattern(const string &pattern, const MouseWatcherRegion *region, const ButtonHandle &button); @@ -188,9 +188,9 @@ protected: void press(ButtonHandle button, bool keyrepeat); void release(ButtonHandle button); void keystroke(int keycode); - void candidate(const wstring &candidate, size_t highlight_start, + void candidate(const wstring &candidate, size_t highlight_start, size_t highlight_end, size_t cursor_pos); - + void global_keyboard_press(const MouseWatcherParameter ¶m); void global_keyboard_release(const MouseWatcherParameter ¶m); @@ -207,10 +207,10 @@ private: void discard_excess_trail_log(); void update_trail_node(); - bool constrain_display_region(DisplayRegion *display_region, + bool constrain_display_region(DisplayRegion *display_region, LVecBase2 &f, LVecBase2 &p, Thread *current_thread); - + private: // This wants to be a set, but because you cannot export sets across // dlls in windows, we will make it a vector instead @@ -230,7 +230,7 @@ private: int _num_trail_recent; double _trail_log_duration; PT(GeomNode) _trail_node; - + Regions _current_regions; PT(MouseWatcherRegion) _preferred_region; PT(MouseWatcherRegion) _preferred_button_down_region; @@ -248,7 +248,7 @@ private: string _without_pattern; PT(PandaNode) _geometry; - + EventHandler *_eh; ModifierButtons _mods; DisplayRegion *_display_region; diff --git a/panda/src/tform/mouseWatcherBase.cxx b/panda/src/tform/mouseWatcherBase.cxx new file mode 100644 index 0000000000..6a5a92aa4c --- /dev/null +++ b/panda/src/tform/mouseWatcherBase.cxx @@ -0,0 +1,443 @@ +// Filename: mouseWatcherBase.cxx +// Created by: rdb (13Jan14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "mouseWatcherBase.h" +#include "lineSegs.h" +#include "indent.h" +#include "lightMutexHolder.h" + +TypeHandle MouseWatcherBase::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MouseWatcherBase:: +MouseWatcherBase() : + _lock("MouseWatcherBase") +{ + _sorted = true; +#ifndef NDEBUG + _show_regions = false; + _color.set(0.4, 0.6f, 1.0f, 1.0f); +#endif // NDEBUG +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +MouseWatcherBase:: +~MouseWatcherBase() { +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::add_region +// Access: Published +// Description: Adds the indicated region to the set of regions in +// the group. It is an error to add the same region to +// the set more than once. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +add_region(MouseWatcherRegion *region) { + PT(MouseWatcherRegion) pt = region; + + LightMutexHolder holder(_lock); + + // We will only bother to check for duplicates in the region list if + // we are building a development Panda. The overhead for doing this + // may be too high if we have many regions. +#ifdef _DEBUG + // See if the region is in the set/vector already + Regions::const_iterator ri = + find(_regions.begin(), _regions.end(), pt); + nassertv(ri == _regions.end()); +#endif // _DEBUG + +#ifndef NDEBUG + // Also add it to the vizzes if we have them. + if (_show_regions) { + nassertv(_vizzes.size() == _regions.size()); + _vizzes.push_back(make_viz_region(pt)); + } +#endif // NDEBUG + + _regions.push_back(pt); + _sorted = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::has_region +// Access: Published +// Description: Returns true if the indicated region has already been +// added to the MouseWatcherBase, false otherwise. +//////////////////////////////////////////////////////////////////// +bool MouseWatcherBase:: +has_region(MouseWatcherRegion *region) const { + LightMutexHolder holder(_lock); + + PT(MouseWatcherRegion) ptr = region; + + if (_sorted) { + // If the vector is already sorted, we can do this the quick way. + Regions::const_iterator ri = lower_bound(_regions.begin(), _regions.end(), ptr); + return (ri != _regions.end() && (*ri) == ptr); + } + + // If the vector isn't sorted, do a linear scan. + Regions::const_iterator ri = find(_regions.begin(), _regions.end(), ptr); + return (ri != _regions.end()); +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::remove_region +// Access: Published +// Description: Removes the indicated region from the group. +// Returns true if it was successfully removed, or false +// if it wasn't there in the first place. +//////////////////////////////////////////////////////////////////// +bool MouseWatcherBase:: +remove_region(MouseWatcherRegion *region) { + LightMutexHolder holder(_lock); + return do_remove_region(region); +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::find_region +// Access: Published +// Description: Returns a pointer to the first region found with the +// indicated name. If multiple regions share the same +// name, the one that is returned is indeterminate. +//////////////////////////////////////////////////////////////////// +MouseWatcherRegion *MouseWatcherBase:: +find_region(const string &name) const { + LightMutexHolder holder(_lock); + + Regions::const_iterator ri; + for (ri = _regions.begin(); ri != _regions.end(); ++ri) { + MouseWatcherRegion *region = (*ri); + if (region->get_name() == name) { + return region; + } + } + + return (MouseWatcherRegion *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::clear_regions +// Access: Published +// Description: Removes all the regions from the group. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +clear_regions() { + LightMutexHolder holder(_lock); + + _regions.clear(); + _sorted = true; + +#ifndef NDEBUG + if (_show_regions) { + _show_regions_root.node()->remove_all_children(); + _vizzes.clear(); + } +#endif // NDEBUG +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::sort_regions +// Access: Published +// Description: Sorts all the regions in this group into pointer +// order. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +sort_regions() { + LightMutexHolder holder(_lock); + do_sort_regions(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::is_sorted +// Access: Published +// Description: Returns true if the group has already been sorted, +// false otherwise. +//////////////////////////////////////////////////////////////////// +bool MouseWatcherBase:: +is_sorted() const { + LightMutexHolder holder(_lock); + + return _sorted; +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::get_num_regions +// Access: Published +// Description: Returns the number of regions in the group. +//////////////////////////////////////////////////////////////////// +int MouseWatcherBase:: +get_num_regions() const { + LightMutexHolder holder(_lock); + + return _regions.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::get_region +// Access: Published +// Description: Returns the nth region of the group; returns NULL if +// there is no nth region. Note that this is not +// thread-safe; another thread might have removed the +// nth region before you called this method. +//////////////////////////////////////////////////////////////////// +MouseWatcherRegion *MouseWatcherBase:: +get_region(int n) const { + LightMutexHolder holder(_lock); + if (n >= 0 && n < (int)_regions.size()) { + return _regions[n]; + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::output +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +output(ostream &out) const { + out << "MouseWatcherBase (" << _regions.size() << " regions)"; +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::write +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +write(ostream &out, int indent_level) const { + LightMutexHolder holder(_lock); + + Regions::const_iterator ri; + for (ri = _regions.begin(); ri != _regions.end(); ++ri) { + MouseWatcherRegion *region = (*ri); + region->write(out, indent_level); + } +} + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::show_regions +// Access: Published +// Description: Enables the visualization of all of the regions +// handled by this MouseWatcherBase. The supplied +// NodePath should be the root of the 2-d scene graph +// for the window. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +show_regions(const NodePath &render2d, const string &bin_name, int draw_order) { + LightMutexHolder holder(_lock); + do_show_regions(render2d, bin_name, draw_order); +} +#endif // NDEBUG + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::set_color +// Access: Published +// Description: Specifies the color used to draw the region +// rectangles for the regions visualized by +// show_regions(). +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +set_color(const LColor &color) { + LightMutexHolder holder(_lock); + + _color = color; + do_update_regions(); +} +#endif // NDEBUG + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::hide_regions +// Access: Published +// Description: Stops the visualization created by a previous call to +// show_regions(). +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +hide_regions() { + LightMutexHolder holder(_lock); + do_hide_regions(); +} +#endif // NDEBUG + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::update_regions +// Access: Published +// Description: Refreshes the visualization created by +// show_regions(). +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +update_regions() { + LightMutexHolder holder(_lock); + do_update_regions(); +} +#endif // NDEBUG + + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::do_sort_regions +// Access: Protected +// Description: Sorts all the regions in this group into pointer +// order. Assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +do_sort_regions() { + if (!_sorted) { + sort(_regions.begin(), _regions.end()); + _sorted = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::do_remove_region +// Access: Protected +// Description: The internal implementation of remove_region(); +// assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +bool MouseWatcherBase:: +do_remove_region(MouseWatcherRegion *region) { + // See if the region is in the vector. + PT(MouseWatcherRegion) ptr = region; + Regions::iterator ri; + + if (_sorted) { + // Faster, binary search + ri = lower_bound(_regions.begin(), _regions.end(), ptr); + } else { + // Unsorted, so use slower linear scan + ri = find(_regions.begin(), _regions.end(), ptr); + } + + if (ri != _regions.end() && (*ri) == ptr) { + // Found it, now erase it +#ifndef NDEBUG + // Also remove it from the vizzes. + if (_show_regions) { + nassertr(_vizzes.size() == _regions.size(), false); + size_t index = ri - _regions.begin(); + Vizzes::iterator vi = _vizzes.begin() + index; + _show_regions_root.node()->remove_child(*vi); + _vizzes.erase(vi); + } +#endif // NDEBUG + + _regions.erase(ri); + return true; + } + + // Did not find the region to erase + return false; +} + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::do_show_regions +// Access: Protected, Virtual +// Description: The protected implementation of show_regions(). This +// assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +do_show_regions(const NodePath &render2d, const string &bin_name, + int draw_order) { + do_hide_regions(); + _show_regions = true; + _show_regions_root = render2d.attach_new_node("show_regions"); + _show_regions_root.set_bin(bin_name, draw_order); + do_update_regions(); +} +#endif // NDEBUG + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::do_hide_regions +// Access: Protected, Virtual +// Description: The protected implementation of hide_regions(). This +// assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +do_hide_regions() { + _show_regions_root.remove_node(); + _show_regions = false; + _vizzes.clear(); +} +#endif // NDEBUG + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::do_update_regions +// Access: Protected +// Description: Internally regenerates the show_regions() +// visualization. Assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +void MouseWatcherBase:: +do_update_regions() { + nassertv(_lock.debug_is_locked()); + + if (_show_regions) { + _show_regions_root.node()->remove_all_children(); + _vizzes.clear(); + _vizzes.reserve(_regions.size()); + + Regions::const_iterator ri; + for (ri = _regions.begin(); ri != _regions.end(); ++ri) { + _vizzes.push_back(make_viz_region(*ri)); + } + } +} +#endif // NDEBUG + + +#ifndef NDEBUG +//////////////////////////////////////////////////////////////////// +// Function: MouseWatcherBase::make_viz_region +// Access: Private +// Description: Creates a node to represent the indicated region, and +// attaches it to the _show_regions_root. Does not add +// it to _vizzes. Assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +PandaNode *MouseWatcherBase:: +make_viz_region(MouseWatcherRegion *region) { + nassertr(_lock.debug_is_locked(), NULL); + + LineSegs ls("show_regions"); + ls.set_color(_color); + + const LVecBase4 &f = region->get_frame(); + + ls.move_to(LVector3::rfu(f[0], 0.0f, f[2])); + ls.draw_to(LVector3::rfu(f[1], 0.0f, f[2])); + ls.draw_to(LVector3::rfu(f[1], 0.0f, f[3])); + ls.draw_to(LVector3::rfu(f[0], 0.0f, f[3])); + ls.draw_to(LVector3::rfu(f[0], 0.0f, f[2])); + + PT(PandaNode) node = ls.create(); + _show_regions_root.attach_new_node(node); + + return node; +} +#endif // NDEBUG diff --git a/panda/src/tform/mouseWatcherBase.h b/panda/src/tform/mouseWatcherBase.h new file mode 100644 index 0000000000..c99ac726d1 --- /dev/null +++ b/panda/src/tform/mouseWatcherBase.h @@ -0,0 +1,113 @@ +// Filename: mouseWatcherBase.h +// Created by: rdb (13Jan14) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef MOUSEWATCHERBASE_H +#define MOUSEWATCHERBASE_H + +#include "pandabase.h" +#include "mouseWatcherRegion.h" + +#include "pointerTo.h" +#include "pvector.h" +#include "nodePath.h" +#include "lightMutex.h" + +//////////////////////////////////////////////////////////////////// +// Class : MouseWatcherBase +// Description : This represents a collection of MouseWatcherRegions +// that may be managed as a group. This is the base +// class for both MouseWatcherGroup and MouseWatcher, +// and exists so that we don't have to make MouseWatcher +// inherit from ReferenceCount more than once. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_TFORM MouseWatcherBase { +public: + MouseWatcherBase(); + virtual ~MouseWatcherBase(); + +PUBLISHED: + void add_region(MouseWatcherRegion *region); + bool has_region(MouseWatcherRegion *region) const; + bool remove_region(MouseWatcherRegion *region); + MouseWatcherRegion *find_region(const string &name) const; + void clear_regions(); + + void sort_regions(); + bool is_sorted() const; + + int get_num_regions() const; + MouseWatcherRegion *get_region(int n) const; + MAKE_SEQ(get_regions, get_num_regions, get_region); + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +#ifndef NDEBUG + void show_regions(const NodePath &render2d, + const string &bin_name, int draw_order); + void set_color(const LColor &color); + void hide_regions(); + + void update_regions(); +#endif // NDEBUG + +protected: + void do_sort_regions(); + bool do_remove_region(MouseWatcherRegion *region); + +#ifndef NDEBUG + virtual void do_show_regions(const NodePath &render2d, + const string &bin_name, int draw_order); + virtual void do_hide_regions(); + void do_update_regions(); +#endif // NDEBUG + +protected: + typedef pvector< PT(MouseWatcherRegion) > Regions; + Regions _regions; + bool _sorted; + + // This mutex protects the above list of regions, as well as the + // below list of vizzes. It is also referenced directly by + // MouseWatcher, a derived class. + LightMutex _lock; + +private: +#ifndef NDEBUG + PandaNode *make_viz_region(MouseWatcherRegion *region); + + typedef pvector< PT(PandaNode) > Vizzes; + Vizzes _vizzes; + + bool _show_regions; + NodePath _show_regions_root; + LColor _color; +#endif // NDEBUG + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + register_type(_type_handle, "MouseWatcherBase"); + } + +private: + static TypeHandle _type_handle; + + friend class MouseWatcher; + friend class BlobWatcher; +}; + +#endif diff --git a/panda/src/tform/mouseWatcherGroup.cxx b/panda/src/tform/mouseWatcherGroup.cxx index 414820b24d..60629bb1f1 100644 --- a/panda/src/tform/mouseWatcherGroup.cxx +++ b/panda/src/tform/mouseWatcherGroup.cxx @@ -13,432 +13,5 @@ //////////////////////////////////////////////////////////////////// #include "mouseWatcherGroup.h" -#include "lineSegs.h" -#include "indent.h" -#include "lightMutexHolder.h" TypeHandle MouseWatcherGroup::_type_handle; - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::Constructor -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -MouseWatcherGroup:: -MouseWatcherGroup() : - _lock("MouseWatcherGroup") -{ - _sorted = true; -#ifndef NDEBUG - _show_regions = false; - _color.set(0.4, 0.6f, 1.0f, 1.0f); -#endif // NDEBUG -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::Destructor -// Access: Public, Virtual -// Description: -//////////////////////////////////////////////////////////////////// -MouseWatcherGroup:: -~MouseWatcherGroup() { -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::add_region -// Access: Published -// Description: Adds the indicated region to the set of regions in -// the group. It is an error to add the same region to -// the set more than once. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -add_region(MouseWatcherRegion *region) { - PT(MouseWatcherRegion) pt = region; - - LightMutexHolder holder(_lock); - - // We will only bother to check for duplicates in the region list if - // we are building a development Panda. The overhead for doing this - // may be too high if we have many regions. -#ifdef _DEBUG - // See if the region is in the set/vector already - Regions::const_iterator ri = - find(_regions.begin(), _regions.end(), pt); - nassertv(ri == _regions.end()); -#endif // _DEBUG - -#ifndef NDEBUG - // Also add it to the vizzes if we have them. - if (_show_regions) { - nassertv(_vizzes.size() == _regions.size()); - _vizzes.push_back(make_viz_region(pt)); - } -#endif // NDEBUG - - _regions.push_back(pt); - _sorted = false; -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::has_region -// Access: Published -// Description: Returns true if the indicated region has already been -// added to the MouseWatcherGroup, false otherwise. -//////////////////////////////////////////////////////////////////// -bool MouseWatcherGroup:: -has_region(MouseWatcherRegion *region) const { - LightMutexHolder holder(_lock); - - PT(MouseWatcherRegion) ptr = region; - - if (_sorted) { - // If the vector is already sorted, we can do this the quick way. - Regions::const_iterator ri = lower_bound(_regions.begin(), _regions.end(), ptr); - return (ri != _regions.end() && (*ri) == ptr); - } - - // If the vector isn't sorted, do a linear scan. - Regions::const_iterator ri = find(_regions.begin(), _regions.end(), ptr); - return (ri != _regions.end()); -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::remove_region -// Access: Published -// Description: Removes the indicated region from the group. -// Returns true if it was successfully removed, or false -// if it wasn't there in the first place. -//////////////////////////////////////////////////////////////////// -bool MouseWatcherGroup:: -remove_region(MouseWatcherRegion *region) { - LightMutexHolder holder(_lock); - return do_remove_region(region); -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::find_region -// Access: Published -// Description: Returns a pointer to the first region found with the -// indicated name. If multiple regions share the same -// name, the one that is returned is indeterminate. -//////////////////////////////////////////////////////////////////// -MouseWatcherRegion *MouseWatcherGroup:: -find_region(const string &name) const { - LightMutexHolder holder(_lock); - - Regions::const_iterator ri; - for (ri = _regions.begin(); ri != _regions.end(); ++ri) { - MouseWatcherRegion *region = (*ri); - if (region->get_name() == name) { - return region; - } - } - - return (MouseWatcherRegion *)NULL; -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::clear_regions -// Access: Published -// Description: Removes all the regions from the group. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -clear_regions() { - LightMutexHolder holder(_lock); - - _regions.clear(); - _sorted = true; - -#ifndef NDEBUG - if (_show_regions) { - _show_regions_root.node()->remove_all_children(); - _vizzes.clear(); - } -#endif // NDEBUG -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::sort_regions -// Access: Published -// Description: Sorts all the regions in this group into pointer -// order. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -sort_regions() { - LightMutexHolder holder(_lock); - do_sort_regions(); -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::is_sorted -// Access: Published -// Description: Returns true if the group has already been sorted, -// false otherwise. -//////////////////////////////////////////////////////////////////// -bool MouseWatcherGroup:: -is_sorted() const { - LightMutexHolder holder(_lock); - - return _sorted; -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::get_num_regions -// Access: Published -// Description: Returns the number of regions in the group. -//////////////////////////////////////////////////////////////////// -int MouseWatcherGroup:: -get_num_regions() const { - LightMutexHolder holder(_lock); - - return _regions.size(); -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::get_region -// Access: Published -// Description: Returns the nth region of the group; returns NULL if -// there is no nth region. Note that this is not -// thread-safe; another thread might have removed the -// nth region before you called this method. -//////////////////////////////////////////////////////////////////// -MouseWatcherRegion *MouseWatcherGroup:: -get_region(int n) const { - LightMutexHolder holder(_lock); - if (n >= 0 && n < (int)_regions.size()) { - return _regions[n]; - } - return NULL; -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::output -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -output(ostream &out) const { - out << "MouseWatcherGroup (" << _regions.size() << " regions)"; -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::write -// Access: Published -// Description: -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -write(ostream &out, int indent_level) const { - LightMutexHolder holder(_lock); - - Regions::const_iterator ri; - for (ri = _regions.begin(); ri != _regions.end(); ++ri) { - MouseWatcherRegion *region = (*ri); - region->write(out, indent_level); - } -} - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::show_regions -// Access: Published -// Description: Enables the visualization of all of the regions -// handled by this MouseWatcherGroup. The supplied -// NodePath should be the root of the 2-d scene graph -// for the window. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -show_regions(const NodePath &render2d, const string &bin_name, int draw_order) { - LightMutexHolder holder(_lock); - do_show_regions(render2d, bin_name, draw_order); -} -#endif // NDEBUG - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::set_color -// Access: Published -// Description: Specifies the color used to draw the region -// rectangles for the regions visualized by -// show_regions(). -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -set_color(const LColor &color) { - LightMutexHolder holder(_lock); - - _color = color; - do_update_regions(); -} -#endif // NDEBUG - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::hide_regions -// Access: Published -// Description: Stops the visualization created by a previous call to -// show_regions(). -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -hide_regions() { - LightMutexHolder holder(_lock); - do_hide_regions(); -} -#endif // NDEBUG - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::update_regions -// Access: Published -// Description: Refreshes the visualization created by -// show_regions(). -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -update_regions() { - LightMutexHolder holder(_lock); - do_update_regions(); -} -#endif // NDEBUG - - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::do_sort_regions -// Access: Protected -// Description: Sorts all the regions in this group into pointer -// order. Assumes the lock is already held. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -do_sort_regions() { - if (!_sorted) { - sort(_regions.begin(), _regions.end()); - _sorted = true; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::do_remove_region -// Access: Protected -// Description: The internal implementation of remove_region(); -// assumes the lock is already held. -//////////////////////////////////////////////////////////////////// -bool MouseWatcherGroup:: -do_remove_region(MouseWatcherRegion *region) { - // See if the region is in the vector. - PT(MouseWatcherRegion) ptr = region; - Regions::iterator ri; - - if (_sorted) { - // Faster, binary search - ri = lower_bound(_regions.begin(), _regions.end(), ptr); - } else { - // Unsorted, so use slower linear scan - ri = find(_regions.begin(), _regions.end(), ptr); - } - - if (ri != _regions.end() && (*ri) == ptr) { - // Found it, now erase it -#ifndef NDEBUG - // Also remove it from the vizzes. - if (_show_regions) { - nassertr(_vizzes.size() == _regions.size(), false); - size_t index = ri - _regions.begin(); - Vizzes::iterator vi = _vizzes.begin() + index; - _show_regions_root.node()->remove_child(*vi); - _vizzes.erase(vi); - } -#endif // NDEBUG - - _regions.erase(ri); - return true; - } - - // Did not find the region to erase - return false; -} - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::do_show_regions -// Access: Protected, Virtual -// Description: The protected implementation of show_regions(). This -// assumes the lock is already held. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -do_show_regions(const NodePath &render2d, const string &bin_name, - int draw_order) { - do_hide_regions(); - _show_regions = true; - _show_regions_root = render2d.attach_new_node("show_regions"); - _show_regions_root.set_bin(bin_name, draw_order); - do_update_regions(); -} -#endif // NDEBUG - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::do_hide_regions -// Access: Protected, Virtual -// Description: The protected implementation of hide_regions(). This -// assumes the lock is already held. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -do_hide_regions() { - _show_regions_root.remove_node(); - _show_regions = false; - _vizzes.clear(); -} -#endif // NDEBUG - - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::do_update_regions -// Access: Protected -// Description: Internally regenerates the show_regions() -// visualization. Assumes the lock is already held. -//////////////////////////////////////////////////////////////////// -void MouseWatcherGroup:: -do_update_regions() { - nassertv(_lock.debug_is_locked()); - - if (_show_regions) { - _show_regions_root.node()->remove_all_children(); - _vizzes.clear(); - _vizzes.reserve(_regions.size()); - - Regions::const_iterator ri; - for (ri = _regions.begin(); ri != _regions.end(); ++ri) { - _vizzes.push_back(make_viz_region(*ri)); - } - } -} -#endif // NDEBUG - - -#ifndef NDEBUG -//////////////////////////////////////////////////////////////////// -// Function: MouseWatcherGroup::make_viz_region -// Access: Private -// Description: Creates a node to represent the indicated region, and -// attaches it to the _show_regions_root. Does not add -// it to _vizzes. Assumes the lock is already held. -//////////////////////////////////////////////////////////////////// -PandaNode *MouseWatcherGroup:: -make_viz_region(MouseWatcherRegion *region) { - nassertr(_lock.debug_is_locked(), NULL); - - LineSegs ls("show_regions"); - ls.set_color(_color); - - const LVecBase4 &f = region->get_frame(); - - ls.move_to(LVector3::rfu(f[0], 0.0f, f[2])); - ls.draw_to(LVector3::rfu(f[1], 0.0f, f[2])); - ls.draw_to(LVector3::rfu(f[1], 0.0f, f[3])); - ls.draw_to(LVector3::rfu(f[0], 0.0f, f[3])); - ls.draw_to(LVector3::rfu(f[0], 0.0f, f[2])); - - PT(PandaNode) node = ls.create(); - _show_regions_root.attach_new_node(node); - - return node; -} -#endif // NDEBUG diff --git a/panda/src/tform/mouseWatcherGroup.h b/panda/src/tform/mouseWatcherGroup.h index 30b4f4d419..d07994581d 100644 --- a/panda/src/tform/mouseWatcherGroup.h +++ b/panda/src/tform/mouseWatcherGroup.h @@ -16,82 +16,20 @@ #define MOUSEWATCHERGROUP_H #include "pandabase.h" -#include "mouseWatcherRegion.h" - -#include "pointerTo.h" +#include "mouseWatcherBase.h" #include "referenceCount.h" -#include "pvector.h" -#include "nodePath.h" -#include "lightMutex.h" //////////////////////////////////////////////////////////////////// // Class : MouseWatcherGroup // Description : This represents a collection of MouseWatcherRegions -// that may be managed as a group. +// that may be managed as a group. The implementation +// for this is in MouseWatcherBase; this class exists +// so that we can inherit from ReferenceCount. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_TFORM MouseWatcherGroup : virtual public ReferenceCount { +class EXPCL_PANDA_TFORM MouseWatcherGroup : public MouseWatcherBase, + public ReferenceCount { public: - MouseWatcherGroup(); - virtual ~MouseWatcherGroup(); - -PUBLISHED: - void add_region(MouseWatcherRegion *region); - bool has_region(MouseWatcherRegion *region) const; - bool remove_region(MouseWatcherRegion *region); - MouseWatcherRegion *find_region(const string &name) const; - void clear_regions(); - - void sort_regions(); - bool is_sorted() const; - - int get_num_regions() const; - MouseWatcherRegion *get_region(int n) const; - MAKE_SEQ(get_regions, get_num_regions, get_region); - - void output(ostream &out) const; - void write(ostream &out, int indent_level = 0) const; - -#ifndef NDEBUG - void show_regions(const NodePath &render2d, - const string &bin_name, int draw_order); - void set_color(const LColor &color); - void hide_regions(); - - void update_regions(); -#endif // NDEBUG - -protected: - void do_sort_regions(); - bool do_remove_region(MouseWatcherRegion *region); - -#ifndef NDEBUG - virtual void do_show_regions(const NodePath &render2d, - const string &bin_name, int draw_order); - virtual void do_hide_regions(); - void do_update_regions(); -#endif // NDEBUG - -protected: - typedef pvector< PT(MouseWatcherRegion) > Regions; - Regions _regions; - bool _sorted; - - // This mutex protects the above list of regions, as well as the - // below list of vizzes. It is also referenced directly by - // MouseWatcher, a derived class. - LightMutex _lock; - -private: -#ifndef NDEBUG - PandaNode *make_viz_region(MouseWatcherRegion *region); - - typedef pvector< PT(PandaNode) > Vizzes; - Vizzes _vizzes; - - bool _show_regions; - NodePath _show_regions_root; - LColor _color; -#endif // NDEBUG + INLINE MouseWatcherGroup() {}; public: static TypeHandle get_class_type() { @@ -105,9 +43,6 @@ public: private: static TypeHandle _type_handle; - - friend class MouseWatcher; - friend class BlobWatcher; }; #endif diff --git a/panda/src/tform/p3tform_composite2.cxx b/panda/src/tform/p3tform_composite2.cxx index 03ea6280c7..862c698071 100644 --- a/panda/src/tform/p3tform_composite2.cxx +++ b/panda/src/tform/p3tform_composite2.cxx @@ -1,4 +1,5 @@ #include "mouseWatcher.cxx" +#include "mouseWatcherBase.cxx" #include "mouseWatcherGroup.cxx" #include "mouseWatcherParameter.cxx" #include "mouseWatcherRegion.cxx"