From 9e196097ad58d2e4c7d17852e6ed34c7835bd598 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 23 Dec 2003 19:27:01 +0000 Subject: [PATCH] robustify layer-ordering interface --- panda/src/display/graphicsChannel.cxx | 150 ++++++++++++++++---------- panda/src/display/graphicsChannel.h | 15 ++- panda/src/display/graphicsLayer.I | 22 ++++ panda/src/display/graphicsLayer.cxx | 24 ++++- panda/src/display/graphicsLayer.h | 9 +- 5 files changed, 153 insertions(+), 67 deletions(-) diff --git a/panda/src/display/graphicsChannel.cxx b/panda/src/display/graphicsChannel.cxx index 5b87d231ad..ce3f647cf3 100644 --- a/panda/src/display/graphicsChannel.cxx +++ b/panda/src/display/graphicsChannel.cxx @@ -100,24 +100,75 @@ GraphicsChannel:: // Function: GraphicsChannel::make_layer // Access: Published // Description: Creates a new GraphicsLayer, associated with the -// window, at the indicated index position. If the -// index position negative or past the end of the array, -// the end of the array is assumed. The layers will be -// rendered on top of each other, in increasing order by -// index, from back to front. +// window, with the indicated sort value. The sort +// value is an arbitrary integer, and may be zero or +// negative. The graphics layers are rendered in order +// from lower sort value to higher sort value; within +// layers of the same sort value, they are ordered in +// sequence from the first added to the last added. //////////////////////////////////////////////////////////////////// GraphicsLayer *GraphicsChannel:: -make_layer(int index) { +make_layer(int sort) { MutexHolder holder(_lock); - PT(GraphicsLayer) layer = new GraphicsLayer(this); - if (index < 0 || index >= (int)_layers.size()) { - _layers.push_back(layer); - } else { - _layers.insert(_layers.begin() + index, layer); - } + PT(GraphicsLayer) layer = new GraphicsLayer(this, sort); + _layers.insert(layer); + return layer; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsChannel::remove_layer +// Access: Published +// Description: Removes the indicated GraphicsLayer. Returns true if +// it was successfully removed, false if it was not a +// member of the channel in the first place. +//////////////////////////////////////////////////////////////////// +bool GraphicsChannel:: +remove_layer(GraphicsLayer *layer) { + MutexHolder holder(_lock); + GraphicsLayers::iterator li = find_layer(layer); + + if (li == _layers.end()) { + return false; + } + + _layers.erase(li); + win_display_regions_changed(); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsChannel::move_layer +// Access: Published +// Description: Reinserts the indicated layer into the list with the +// indicated sort value. The layer will be rendered +// last among all of the previously-added layers with +// the same sort value. If the new sort value is the +// same as the previous sort value, the layer will be +// moved to the end of the list of layers with this sort +// value. +// +// Returns true if the layer is successfully moved, +// false if it is not a member of this channel. +//////////////////////////////////////////////////////////////////// +bool GraphicsChannel:: +move_layer(GraphicsLayer *layer, int sort) { + MutexHolder holder(_lock); + + GraphicsLayers::iterator li = find_layer(layer); + if (li == _layers.end()) { + return false; + } + + PT(GraphicsLayer) hold_layer = layer; + _layers.erase(li); + layer->_sort = sort; + _layers.insert(layer); + + win_display_regions_changed(); + return true; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsChannel::get_num_layers // Access: Published @@ -134,57 +185,17 @@ get_num_layers() const { // Function: GraphicsChannel::get_layer // Access: Published // Description: Returns the nth layer associated with the channel. +// Walking through this list from 0 to (get_num_layers() +// - 1) will retrieve all of the layers in the order in +// which they will be rendered. It is therefore invalid +// to call make_layer(), remove_layer(), or move_layer() +// while traversing this list. //////////////////////////////////////////////////////////////////// GraphicsLayer *GraphicsChannel:: get_layer(int index) const { MutexHolder holder(_lock); - if (index >= 0 && index < (int)_layers.size()) { - return _layers[index]; - } - return NULL; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsChannel::move_layer -// Access: Published -// Description: Changes the ordering of the layers so that the -// indicated layer will move to the indicated position. -// If to_index is negative or past the end of the array, -// the end of the array is assumed. -//////////////////////////////////////////////////////////////////// -void GraphicsChannel:: -move_layer(int from_index, int to_index) { - MutexHolder holder(_lock); - nassertv(from_index >= 0 && from_index < (int)_layers.size()); - PT(GraphicsLayer) layer = _layers[from_index]; - - if (to_index < 0 || to_index >= (int)_layers.size()) { - _layers.erase(_layers.begin() + from_index); - _layers.push_back(layer); - - } else if (to_index > from_index) { - // Move the layer later in the list. - _layers.insert(_layers.begin() + to_index, layer); - _layers.erase(_layers.begin() + from_index); - - } else if (to_index < from_index) { - // Move the layer earlier in the list. - _layers.erase(_layers.begin() + from_index); - _layers.insert(_layers.begin() + to_index, layer); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsChannel::remove_layer -// Access: Published -// Description: Removes the nth layer. This changes the numbers of -// all subsequent layers. -//////////////////////////////////////////////////////////////////// -void GraphicsChannel:: -remove_layer(int index) { - MutexHolder holder(_lock); - nassertv(index >= 0 && index < (int)_layers.size()); - _layers.erase(_layers.begin() + index); + nassertr(index >= 0 && index < (int)_layers.size(), NULL); + return _layers[index]; } //////////////////////////////////////////////////////////////////// @@ -267,3 +278,24 @@ win_display_regions_changed() { _window->win_display_regions_changed(); } } + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsChannel::find_layer +// Access: Private +// Description: Returns the iterator corresponding to the indicated +// layer, or _layers.end() if the layer is not part of +// this channel. +//////////////////////////////////////////////////////////////////// +GraphicsChannel::GraphicsLayers::iterator GraphicsChannel:: +find_layer(GraphicsLayer *layer) { + GraphicsLayers::iterator li = _layers.lower_bound(layer); + while (li != _layers.end() && (*li) != layer) { + if (*layer < *(*li)) { + // The layer was not found. + return _layers.end(); + } + ++li; + } + + return li; +} diff --git a/panda/src/display/graphicsChannel.h b/panda/src/display/graphicsChannel.h index 0c82a8640c..c49af5c7f6 100644 --- a/panda/src/display/graphicsChannel.h +++ b/panda/src/display/graphicsChannel.h @@ -23,7 +23,8 @@ #include "typedReferenceCount.h" #include "pointerTo.h" #include "pmutex.h" -#include "pvector.h" +#include "ordered_vector.h" +#include "indirectLess.h" class GraphicsChannel; class GraphicsPipe; @@ -51,11 +52,12 @@ private: PUBLISHED: virtual ~GraphicsChannel(); - GraphicsLayer *make_layer(int index = -1); + GraphicsLayer *make_layer(int sort = 0); + bool remove_layer(GraphicsLayer *layer); + bool move_layer(GraphicsLayer *layer, int sort); + int get_num_layers() const; GraphicsLayer *get_layer(int index) const; - void move_layer(int from_index, int to_index); - void remove_layer(int index); GraphicsWindow *get_window() const; GraphicsPipe *get_pipe() const; @@ -74,9 +76,12 @@ protected: GraphicsWindow *_window; bool _is_active; - typedef pvector< PT(GraphicsLayer) > GraphicsLayers; + typedef ov_multiset< PT(GraphicsLayer), IndirectLess > GraphicsLayers; GraphicsLayers _layers; +private: + GraphicsLayers::iterator find_layer(GraphicsLayer *layer); + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/display/graphicsLayer.I b/panda/src/display/graphicsLayer.I index cac2714f0a..1ca799b54c 100644 --- a/panda/src/display/graphicsLayer.I +++ b/panda/src/display/graphicsLayer.I @@ -17,6 +17,16 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: GraphicsLayer::Comparison operator +// Access: Published +// Description: Sorts the layers in order by sort parameter only. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsLayer:: +operator < (const GraphicsLayer &other) const { + return _sort < other._sort; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsLayer::is_active // Access: Published @@ -26,3 +36,15 @@ INLINE bool GraphicsLayer:: is_active() const { return _is_active; } + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsLayer::get_sort +// Access: Published +// Description: Returns the sort parameter associated with the layer. +// This defines the order in which this layer is +// rendered relative to the other layers on the channel. +//////////////////////////////////////////////////////////////////// +INLINE int GraphicsLayer:: +get_sort() const { + return _sort; +} diff --git a/panda/src/display/graphicsLayer.cxx b/panda/src/display/graphicsLayer.cxx index 6c2c010c2d..e5a8e9c3e6 100644 --- a/panda/src/display/graphicsLayer.cxx +++ b/panda/src/display/graphicsLayer.cxx @@ -37,6 +37,7 @@ TypeHandle GraphicsLayer::_type_handle; GraphicsLayer:: GraphicsLayer() { _channel = NULL; + _sort = 0; _is_active = true; } @@ -47,8 +48,9 @@ GraphicsLayer() { // layer. //////////////////////////////////////////////////////////////////// GraphicsLayer:: -GraphicsLayer(GraphicsChannel *channel) - : _channel(channel) +GraphicsLayer(GraphicsChannel *channel, int sort) : + _channel(channel), + _sort(sort) { _is_active = true; } @@ -258,6 +260,24 @@ set_active(bool active) { } } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsLayer::set_sort +// Access: Published +// Description: Changes the sort parameter on the layer. If the sort +// parameter is changed, the layer will be reordered +// among the other layers on the same channel. If the +// sort parameter is not changed, the layer will remain +// in the same sort position. (This is different from +// GraphicsChannel::move_layer(), which will reorder the +// layer even if the sort parameter does not change.) +//////////////////////////////////////////////////////////////////// +void GraphicsLayer:: +set_sort(int sort) { + if (sort != _sort) { + _channel->move_layer(this, sort); + } +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsLayer::channel_resized // Access: Public diff --git a/panda/src/display/graphicsLayer.h b/panda/src/display/graphicsLayer.h index e4cc6ac5e5..d49aac7c11 100644 --- a/panda/src/display/graphicsLayer.h +++ b/panda/src/display/graphicsLayer.h @@ -45,12 +45,15 @@ class CullHandler; class EXPCL_PANDA GraphicsLayer : public TypedReferenceCount { private: GraphicsLayer(); - GraphicsLayer(GraphicsChannel *channel); + GraphicsLayer(GraphicsChannel *channel, int sort); private: GraphicsLayer(const GraphicsLayer ©); void operator = (const GraphicsLayer ©); +public: + INLINE bool operator < (const GraphicsLayer &other) const; + PUBLISHED: virtual ~GraphicsLayer(); @@ -70,6 +73,9 @@ PUBLISHED: void set_active(bool active); INLINE bool is_active() const; + void set_sort(int sort); + INLINE int get_sort() const; + public: void channel_resized(int x, int y); @@ -79,6 +85,7 @@ private: Mutex _lock; GraphicsChannel *_channel; bool _is_active; + int _sort; typedef pvector< PT(DisplayRegion) > DisplayRegions; DisplayRegions _display_regions;