Browse Source

robustify layer-ordering interface

David Rose 22 years ago
parent
commit
9e196097ad

+ 88 - 56
panda/src/display/graphicsChannel.cxx

@@ -100,91 +100,102 @@ GraphicsChannel::
 //     Function: GraphicsChannel::make_layer
 //     Function: GraphicsChannel::make_layer
 //       Access: Published
 //       Access: Published
 //  Description: Creates a new GraphicsLayer, associated with the
 //  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::
 GraphicsLayer *GraphicsChannel::
-make_layer(int index) {
+make_layer(int sort) {
   MutexHolder holder(_lock);
   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;
   return layer;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsChannel::get_num_layers
+//     Function: GraphicsChannel::remove_layer
 //       Access: Published
 //       Access: Published
-//  Description: Returns the number of layers currently associated
-//               with the channel.
+//  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.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-int GraphicsChannel::
-get_num_layers() const {
+bool GraphicsChannel::
+remove_layer(GraphicsLayer *layer) {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  return _layers.size();
+  GraphicsLayers::iterator li = find_layer(layer);
+
+  if (li == _layers.end()) {
+    return false;
+  }
+
+  _layers.erase(li); 
+  win_display_regions_changed();
+  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsChannel::get_layer
+//     Function: GraphicsChannel::move_layer
 //       Access: Published
 //       Access: Published
-//  Description: Returns the nth layer associated with the channel.
+//  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.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GraphicsLayer *GraphicsChannel::
-get_layer(int index) const {
+bool GraphicsChannel::
+move_layer(GraphicsLayer *layer, int sort) {
   MutexHolder holder(_lock);
   MutexHolder holder(_lock);
-  if (index >= 0 && index < (int)_layers.size()) {
-    return _layers[index];
+
+  GraphicsLayers::iterator li = find_layer(layer);
+  if (li == _layers.end()) {
+    return false;
   }
   }
-  return NULL;
+
+  PT(GraphicsLayer) hold_layer = layer;
+  _layers.erase(li);
+  layer->_sort = sort;
+  _layers.insert(layer);
+
+  win_display_regions_changed();
+  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsChannel::move_layer
+//     Function: GraphicsChannel::get_num_layers
 //       Access: Published
 //       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.
+//  Description: Returns the number of layers currently associated
+//               with the channel.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void GraphicsChannel::
-move_layer(int from_index, int to_index) {
+int GraphicsChannel::
+get_num_layers() const {
   MutexHolder holder(_lock);
   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);
-  }
+  return _layers.size();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsChannel::remove_layer
+//     Function: GraphicsChannel::get_layer
 //       Access: Published
 //       Access: Published
-//  Description: Removes the nth layer.  This changes the numbers of
-//               all subsequent layers.
+//  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.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void GraphicsChannel::
-remove_layer(int index) {
+GraphicsLayer *GraphicsChannel::
+get_layer(int index) const {
   MutexHolder holder(_lock);
   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();
     _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;
+}

+ 10 - 5
panda/src/display/graphicsChannel.h

@@ -23,7 +23,8 @@
 #include "typedReferenceCount.h"
 #include "typedReferenceCount.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "pmutex.h"
 #include "pmutex.h"
-#include "pvector.h"
+#include "ordered_vector.h"
+#include "indirectLess.h"
 
 
 class GraphicsChannel;
 class GraphicsChannel;
 class GraphicsPipe;
 class GraphicsPipe;
@@ -51,11 +52,12 @@ private:
 
 
 PUBLISHED:
 PUBLISHED:
   virtual ~GraphicsChannel();
   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;
   int get_num_layers() const;
   GraphicsLayer *get_layer(int index) 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;
   GraphicsWindow *get_window() const;
   GraphicsPipe *get_pipe() const;
   GraphicsPipe *get_pipe() const;
@@ -74,9 +76,12 @@ protected:
   GraphicsWindow *_window;
   GraphicsWindow *_window;
   bool _is_active;
   bool _is_active;
 
 
-  typedef pvector< PT(GraphicsLayer) > GraphicsLayers;
+  typedef ov_multiset< PT(GraphicsLayer), IndirectLess<GraphicsLayer> > GraphicsLayers;
   GraphicsLayers _layers;
   GraphicsLayers _layers;
 
 
+private:
+  GraphicsLayers::iterator find_layer(GraphicsLayer *layer);
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 22 - 0
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
 //     Function: GraphicsLayer::is_active
 //       Access: Published
 //       Access: Published
@@ -26,3 +36,15 @@ INLINE bool GraphicsLayer::
 is_active() const {
 is_active() const {
   return _is_active;
   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;
+}

+ 22 - 2
panda/src/display/graphicsLayer.cxx

@@ -37,6 +37,7 @@ TypeHandle GraphicsLayer::_type_handle;
 GraphicsLayer::
 GraphicsLayer::
 GraphicsLayer() {
 GraphicsLayer() {
   _channel = NULL;
   _channel = NULL;
+  _sort = 0;
   _is_active = true;
   _is_active = true;
 }
 }
 
 
@@ -47,8 +48,9 @@ GraphicsLayer() {
 //               layer.
 //               layer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GraphicsLayer::
 GraphicsLayer::
-GraphicsLayer(GraphicsChannel *channel)
-  : _channel(channel)
+GraphicsLayer(GraphicsChannel *channel, int sort) :
+  _channel(channel),
+  _sort(sort)
 {
 {
   _is_active = true;
   _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
 //     Function: GraphicsLayer::channel_resized
 //       Access: Public
 //       Access: Public

+ 8 - 1
panda/src/display/graphicsLayer.h

@@ -45,12 +45,15 @@ class CullHandler;
 class EXPCL_PANDA GraphicsLayer : public TypedReferenceCount {
 class EXPCL_PANDA GraphicsLayer : public TypedReferenceCount {
 private:
 private:
   GraphicsLayer();
   GraphicsLayer();
-  GraphicsLayer(GraphicsChannel *channel);
+  GraphicsLayer(GraphicsChannel *channel, int sort);
 
 
 private:
 private:
   GraphicsLayer(const GraphicsLayer &copy);
   GraphicsLayer(const GraphicsLayer &copy);
   void operator = (const GraphicsLayer &copy);
   void operator = (const GraphicsLayer &copy);
 
 
+public:
+  INLINE bool operator < (const GraphicsLayer &other) const;
+
 PUBLISHED:
 PUBLISHED:
   virtual ~GraphicsLayer();
   virtual ~GraphicsLayer();
 
 
@@ -70,6 +73,9 @@ PUBLISHED:
   void set_active(bool active);
   void set_active(bool active);
   INLINE bool is_active() const;
   INLINE bool is_active() const;
 
 
+  void set_sort(int sort);
+  INLINE int get_sort() const;
+
 public:
 public:
   void channel_resized(int x, int y);
   void channel_resized(int x, int y);
 
 
@@ -79,6 +85,7 @@ private:
   Mutex _lock;
   Mutex _lock;
   GraphicsChannel *_channel;
   GraphicsChannel *_channel;
   bool _is_active;
   bool _is_active;
+  int _sort;
 
 
   typedef pvector< PT(DisplayRegion) > DisplayRegions;
   typedef pvector< PT(DisplayRegion) > DisplayRegions;
   DisplayRegions _display_regions;
   DisplayRegions _display_regions;