Fix MouseRecorder & let PandaNode inherit from TypedWritableReferenceCount

This commit is contained in:
rdb 2015-01-24 12:52:40 +01:00
parent 0dc0bbdf0c
commit 0a64bdb33b
23 changed files with 854 additions and 718 deletions

View File

@ -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)

View File

@ -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);
}

View File

@ -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 &copy);

View File

@ -142,8 +142,7 @@ PandaNode::
////////////////////////////////////////////////////////////////////
PandaNode::
PandaNode(const PandaNode &copy) :
ReferenceCount(copy),
TypedWritable(copy),
TypedWritableReferenceCount(copy),
Namable(copy),
_paths_lock("PandaNode::_paths_lock"),
_dirty_prev_transform(false)
@ -209,17 +208,6 @@ operator = (const PandaNode &copy) {
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

View File

@ -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 &copy);
public:
virtual ReferenceCount *as_reference_count();
virtual PandaNode *dupe_for_flatten() const;
virtual bool safe_to_flatten() const;

View File

@ -30,10 +30,12 @@ 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());
@ -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

View File

@ -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 &params);
static RecorderBase *make_recorder(const FactoryParams &params);
@ -106,4 +111,3 @@ private:
};
#endif

View File

@ -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);
@ -90,9 +100,9 @@ private:
static TypeHandle _type_handle;
friend class RecorderController;
friend class RecorderTable;
};
#include "recorderBase.I"
#endif

View File

@ -93,13 +93,7 @@ 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()
<< "Recording session to " << _filename << "\n";
@ -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();
@ -300,14 +282,7 @@ 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);
@ -315,12 +290,7 @@ play_frame() {
// 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;

View File

@ -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);
@ -78,13 +71,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
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);
}
////////////////////////////////////////////////////////////////////

View File

@ -29,10 +29,8 @@ RecorderTable() {
// Description:
////////////////////////////////////////////////////////////////////
INLINE RecorderTable::
RecorderTable(const RecorderTable &copy) :
_recorders(copy._recorders),
_error(copy._error)
{
RecorderTable(const RecorderTable &copy) {
*this = copy;
}
////////////////////////////////////////////////////////////////////
@ -44,13 +42,62 @@ INLINE void RecorderTable::
operator = (const RecorderTable &copy) {
_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<Recorders::iterator, bool> 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;
}

View File

@ -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,7 +60,11 @@ 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()
@ -71,45 +88,67 @@ 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;
}
////////////////////////////////////////////////////////////////////
@ -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);

View File

@ -37,18 +37,25 @@ public:
INLINE RecorderTable();
INLINE RecorderTable(const RecorderTable &copy);
INLINE void operator = (const RecorderTable &copy);
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<string, PT(RecorderBase) > 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<string, RecorderBase*> Recorders;
Recorders _recorders;
bool _error;

View File

@ -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 &params);
void fillin_recorder(DatagramIterator &scan, BamReader *manager);

View File

@ -16,7 +16,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 \
@ -29,8 +29,10 @@
mouseInterfaceNode.cxx \
mouseSubregion.cxx \
mouseWatcher.cxx \
mouseWatcherBase.cxx \
mouseWatcherGroup.cxx \
mouseWatcherParameter.cxx mouseWatcherRegion.cxx \
mouseWatcherParameter.cxx
mouseWatcherRegion.cxx \
trackball.cxx \
transform2sg.cxx
@ -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 \

View File

@ -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();

View File

@ -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
@ -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()) {
@ -817,7 +817,7 @@ clear_current_regions() {
void MouseWatcher::
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;

View File

@ -65,7 +65,7 @@ class DisplayRegion;
// 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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,5 @@
#include "mouseWatcher.cxx"
#include "mouseWatcherBase.cxx"
#include "mouseWatcherGroup.cxx"
#include "mouseWatcherParameter.cxx"
#include "mouseWatcherRegion.cxx"