Panda3D
nodePathCollection.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file nodePathCollection.cxx
10  * @author drose
11  * @date 2002-03-06
12  */
13 
14 #include "nodePathCollection.h"
15 #include "findApproxPath.h"
16 #include "findApproxLevelEntry.h"
17 #include "textureAttrib.h"
18 #include "colorScaleAttrib.h"
19 #include "colorAttrib.h"
20 #include "indent.h"
21 
22 using std::max;
23 using std::min;
24 
25 /**
26  * Adds a new NodePath to the collection.
27  */
29 add_path(const NodePath &node_path) {
30  // If the pointer to our internal array is shared by any other
31  // NodePathCollections, we have to copy the array now so we won't
32  // inadvertently modify any of our brethren NodePathCollection objects.
33 
34  if (_node_paths.get_ref_count() > 1) {
35  NodePaths old_node_paths = _node_paths;
36  _node_paths = NodePaths::empty_array(0);
37  _node_paths.v() = old_node_paths.v();
38  }
39 
40  _node_paths.push_back(node_path);
41 }
42 
43 /**
44  * Removes the indicated NodePath from the collection. Returns true if the
45  * path was removed, false if it was not a member of the collection.
46  */
48 remove_path(const NodePath &node_path) {
49  int path_index = -1;
50  for (int i = 0; path_index == -1 && i < (int)_node_paths.size(); i++) {
51  if (_node_paths[i] == node_path) {
52  path_index = i;
53  }
54  }
55 
56  if (path_index == -1) {
57  // The indicated path was not a member of the collection.
58  return false;
59  }
60 
61  // If the pointer to our internal array is shared by any other
62  // NodePathCollections, we have to copy the array now so we won't
63  // inadvertently modify any of our brethren NodePathCollection objects.
64 
65  if (_node_paths.get_ref_count() > 1) {
66  NodePaths old_node_paths = _node_paths;
67  _node_paths = NodePaths::empty_array(0);
68  _node_paths.v() = old_node_paths.v();
69  }
70 
71  _node_paths.erase(_node_paths.begin() + path_index);
72  return true;
73 }
74 
75 /**
76  * Adds all the NodePaths indicated in the other collection to this path. The
77  * other paths are simply appended to the end of the paths in this list;
78  * duplicates are not automatically removed.
79  */
82  int other_num_paths = other.get_num_paths();
83  for (int i = 0; i < other_num_paths; i++) {
84  add_path(other.get_path(i));
85  }
86 }
87 
88 
89 /**
90  * Removes from this collection all of the NodePaths listed in the other
91  * collection.
92  */
95  NodePaths new_paths;
96  int num_paths = get_num_paths();
97  for (int i = 0; i < num_paths; i++) {
98  NodePath path = get_path(i);
99  if (!other.has_path(path)) {
100  new_paths.push_back(path);
101  }
102  }
103  _node_paths = new_paths;
104 }
105 
106 /**
107  * Removes any duplicate entries of the same NodePaths on this collection. If
108  * a NodePath appears multiple times, the first appearance is retained;
109  * subsequent appearances are removed.
110  */
113  NodePaths new_paths;
114 
115  int num_paths = get_num_paths();
116  for (int i = 0; i < num_paths; i++) {
117  NodePath path = get_path(i);
118  bool duplicated = false;
119 
120  for (int j = 0; j < i && !duplicated; j++) {
121  duplicated = (path == get_path(j));
122  }
123 
124  if (!duplicated) {
125  new_paths.push_back(path);
126  }
127  }
128 
129  _node_paths = new_paths;
130 }
131 
132 /**
133  * Returns true if the indicated NodePath appears in this collection, false
134  * otherwise.
135  */
137 has_path(const NodePath &path) const {
138  for (int i = 0; i < get_num_paths(); i++) {
139  if (path == get_path(i)) {
140  return true;
141  }
142  }
143  return false;
144 }
145 
146 /**
147  * Removes all NodePaths from the collection.
148  */
150 clear() {
151  _node_paths.clear();
152 }
153 
154 /**
155  * This is a hint to Panda to allocate enough memory to hold the given number
156  * of NodePaths, if you know ahead of time how many you will be adding.
157  */
159 reserve(size_t num) {
160  _node_paths.reserve(num);
161 }
162 
163 /**
164  * Returns true if there are no NodePaths in the collection, false otherwise.
165  */
167 is_empty() const {
168  return _node_paths.empty();
169 }
170 
171 /**
172  * Returns the number of NodePaths in the collection.
173  */
174 int NodePathCollection::
175 get_num_paths() const {
176  return _node_paths.size();
177 }
178 
179 /**
180  * Returns the nth NodePath in the collection.
181  */
183 get_path(int index) const {
184  nassertr(index >= 0 && index < (int)_node_paths.size(), NodePath());
185 
186  return _node_paths[index];
187 }
188 
189 /**
190  * Returns the nth NodePath in the collection. This is the same as
191  * get_path(), but it may be a more convenient way to access it.
192  */
194 operator [] (size_t index) const {
195  nassertr(index < _node_paths.size(), NodePath());
196 
197  return _node_paths[index];
198 }
199 
200 /**
201  * Returns the number of paths in the collection. This is the same thing as
202  * get_num_paths().
203  */
205 size() const {
206  return _node_paths.size();
207 }
208 
209 /**
210  * Lists all the nodes at and below each node in the collection
211  * hierarchically.
212  */
214 ls(std::ostream &out, int indent_level) const {
215  for (int i = 0; i < get_num_paths(); i++) {
216  NodePath path = get_path(i);
217  indent(out, indent_level) << path << "\n";
218  path.ls(out, indent_level + 2);
219  out << "\n";
220  }
221 }
222 
223 /**
224  * Returns the complete set of all NodePaths that begin with any NodePath in
225  * this collection and can be extended by path. The shortest paths will be
226  * listed first.
227  */
229 find_all_matches(const std::string &path) const {
230  NodePathCollection result;
231 
232  FindApproxPath approx_path;
233  if (approx_path.add_string(path)) {
234  if (!is_empty()) {
235  FindApproxLevelEntry *level = nullptr;
236  for (int i = 0; i < get_num_paths(); i++) {
237  FindApproxLevelEntry *start =
238  new FindApproxLevelEntry(get_path(i), approx_path);
239  start->_next = level;
240  level = start;
241  }
242  get_path(0).find_matches(result, level, -1);
243  }
244  }
245 
246  return result;
247 }
248 
249 /**
250  * Reparents all the NodePaths in the collection to the indicated node.
251  */
253 reparent_to(const NodePath &other) {
254  for (int i = 0; i < get_num_paths(); i++) {
255  get_path(i).reparent_to(other);
256  }
257 }
258 
259 /**
260  * Reparents all the NodePaths in the collection to the indicated node,
261  * adjusting each transform so as not to move in world coordinates.
262  */
264 wrt_reparent_to(const NodePath &other) {
265  for (int i = 0; i < get_num_paths(); i++) {
266  get_path(i).wrt_reparent_to(other);
267  }
268 }
269 
270 /**
271  * Shows all NodePaths in the collection.
272  */
274 show() {
275  for (int i = 0; i < get_num_paths(); i++) {
276  get_path(i).show();
277  }
278 }
279 
280 /**
281  * Hides all NodePaths in the collection.
282  */
284 hide() {
285  for (int i = 0; i < get_num_paths(); i++) {
286  get_path(i).hide();
287  }
288 }
289 
290 /**
291  * Stashes all NodePaths in the collection.
292  */
294 stash() {
295  for (int i = 0; i < get_num_paths(); i++) {
296  get_path(i).stash();
297  }
298 }
299 
300 /**
301  * Unstashes all NodePaths in the collection.
302  */
305  for (int i = 0; i < get_num_paths(); i++) {
306  get_path(i).unstash();
307  }
308 }
309 
310 /**
311  * Detaches all NodePaths in the collection.
312  */
315  for (int i = 0; i < get_num_paths(); i++) {
316  get_path(i).detach_node();
317  }
318 }
319 
320 /**
321  * Returns the union of all of the into_collide_masks for nodes at this level
322  * and below. This is the same thing as node()->get_net_collide_mask().
323  *
324  * If you want to return what the into_collide_mask of this node itself is,
325  * without regard to its children, use node()->get_into_collide_mask().
326  */
329  CollideMask collide_mask;
330  for (int i = 0; i < get_num_paths(); i++) {
331  collide_mask |= get_path(i).get_collide_mask();
332  }
333  return collide_mask;
334 }
335 
336 /**
337  * Recursively applies the indicated CollideMask to the into_collide_masks for
338  * all nodes at this level and below.
339  *
340  * The default is to change all bits, but if bits_to_change is not all bits
341  * on, then only the bits that are set in bits_to_change are modified,
342  * allowing this call to change only a subset of the bits in the subgraph.
343  */
345 set_collide_mask(CollideMask new_mask, CollideMask bits_to_change,
346  TypeHandle node_type) {
347  for (int i = 0; i < get_num_paths(); i++) {
348  get_path(i).set_collide_mask(new_mask, bits_to_change, node_type);
349  }
350 }
351 
352 /**
353  * Calculates the minimum and maximum vertices of all Geoms at these
354  * NodePath's bottom nodes and below This is a tight bounding box; it will
355  * generally be tighter than the bounding volume returned by get_bounds() (but
356  * it is more expensive to compute).
357  *
358  * The return value is true if any points are within the bounding volume, or
359  * false if none are.
360  */
362 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point) const {
363  bool have_bounds = false;
364 
365  for (int i = 0; i < get_num_paths(); i++) {
366  LPoint3 tmp_min;
367  LPoint3 tmp_max;
368 
369  if (get_path(i).is_empty()) {
370  continue;
371  }
372 
373  if (get_path(i).calc_tight_bounds(tmp_min, tmp_max)) {
374  if (!have_bounds) {
375  min_point = tmp_min;
376  max_point = tmp_max;
377  have_bounds = true;
378  } else {
379  min_point.set(min(min_point._v(0), tmp_min._v(0)),
380  min(min_point._v(1), tmp_min._v(1)),
381  min(min_point._v(2), tmp_min._v(2)));
382  max_point.set(max(max_point._v(0), tmp_max._v(0)),
383  max(max_point._v(1), tmp_max._v(1)),
384  max(max_point._v(2), tmp_max._v(2)));
385  }
386  }
387  }
388 
389  return have_bounds;
390 }
391 
392 /**
393  * Adds the indicated texture to the list of textures that will be rendered on
394  * the default texture stage.
395  *
396  * This is the deprecated single-texture variant of this method; it is now
397  * superceded by set_texture() that accepts a stage and texture. However,
398  * this method may be used in the presence of multitexture if you just want to
399  * adjust the default stage.
400  */
402 set_texture(Texture *tex, int priority) {
403  PT(TextureStage) stage = TextureStage::get_default();
404  set_texture(stage, tex, priority);
405 }
406 
407 /**
408  * Adds the indicated texture to the list of textures that will be rendered on
409  * the indicated multitexture stage. If there are multiple texture stages
410  * specified (possibly on multiple different nodes at different levels), they
411  * will all be applied to geometry together, according to the stage
412  * specification set up in the TextureStage object.
413  */
415 set_texture(TextureStage *stage, Texture *tex, int priority) {
416  StateMap state_map;
417 
418  NodePaths::iterator npi;
419  for (npi = _node_paths.begin(); npi != _node_paths.end(); ++npi) {
420  NodePath &np = (*npi);
421  CPT(RenderState) orig_state = np.get_state();
422  StateMap::iterator smi = state_map.find(orig_state);
423  if (smi != state_map.end()) {
424  // This RenderState has already been encountered; reuse it.
425  np.set_state((*smi).second);
426  } else {
427  // This RenderState has not yet been encountered; apply the attrib to
428  // it.
429  np.set_texture(stage, tex, priority);
430  state_map[orig_state] = np.get_state();
431  }
432  }
433 }
434 
435 /**
436  * Sets the geometry at this level and below to render using no texture, on
437  * any stage. This is different from not specifying a texture; rather, this
438  * specifically contradicts set_texture() at a higher node level (or, with a
439  * priority, overrides a set_texture() at a lower level).
440  */
442 set_texture_off(int priority) {
443  nassertv_always(!is_empty());
444  set_attrib(TextureAttrib::make_all_off(), priority);
445 }
446 
447 /**
448  * Sets the geometry at this level and below to render using no texture, on
449  * the indicated stage. This is different from not specifying a texture;
450  * rather, this specifically contradicts set_texture() at a higher node level
451  * (or, with a priority, overrides a set_texture() at a lower level).
452  */
454 set_texture_off(TextureStage *stage, int priority) {
455  StateMap state_map;
456 
457  NodePaths::iterator npi;
458  for (npi = _node_paths.begin(); npi != _node_paths.end(); ++npi) {
459  NodePath &np = (*npi);
460  CPT(RenderState) orig_state = np.get_state();
461  StateMap::iterator smi = state_map.find(orig_state);
462  if (smi != state_map.end()) {
463  // This RenderState has already been encountered; reuse it.
464  np.set_state((*smi).second);
465  } else {
466  // This RenderState has not yet been encountered; apply the attrib to
467  // it.
468  np.set_texture_off(stage, priority);
469  state_map[orig_state] = np.get_state();
470  }
471  }
472 }
473 
474 /**
475  * Colors all NodePaths in the collection
476  */
478 set_color(const LColor &color, int priority) {
479  set_attrib(ColorAttrib::make_flat(color), priority);
480 }
481 
482 /**
483  * Applies color scales to all NodePaths in the collection. The existing
484  * color scale is replaced.
485  */
487 set_color_scale(const LVecBase4 &scale, int priority) {
488  StateMap state_map;
489 
490  NodePaths::iterator npi;
491  for (npi = _node_paths.begin(); npi != _node_paths.end(); ++npi) {
492  NodePath &np = (*npi);
493  CPT(RenderState) orig_state = np.get_state();
494  StateMap::iterator smi = state_map.find(orig_state);
495  if (smi != state_map.end()) {
496  // This RenderState has already been encountered; reuse it.
497  np.set_state((*smi).second);
498  } else {
499  // This RenderState has not yet been encountered; apply the attrib to
500  // it.
501  np.set_color_scale(scale, priority);
502  state_map[orig_state] = np.get_state();
503  }
504  }
505 }
506 
507 /**
508  * Applies color scales to all NodePaths in the collection. The existing
509  * color scale, if any, is multiplied by the specified color scale.
510  */
512 compose_color_scale(const LVecBase4 &scale, int priority) {
513  StateMap state_map;
514 
515  NodePaths::iterator npi;
516  for (npi = _node_paths.begin(); npi != _node_paths.end(); ++npi) {
517  NodePath &np = (*npi);
518  CPT(RenderState) orig_state = np.get_state();
519  StateMap::iterator smi = state_map.find(orig_state);
520  if (smi != state_map.end()) {
521  // This RenderState has already been encountered; reuse it.
522  np.set_state((*smi).second);
523  } else {
524  // This RenderState has not yet been encountered; apply the attrib to
525  // it.
526  np.compose_color_scale(scale, priority);
527  state_map[orig_state] = np.get_state();
528  }
529  }
530 }
531 
532 /**
533  * Applies the indicated RenderAttrib to all NodePaths in the collection. An
534  * effort is made to apply the attrib to many NodePaths as quickly as
535  * possible; redundant RenderState compositions are not duplicated.
536  */
538 set_attrib(const RenderAttrib *attrib, int priority) {
539  StateMap state_map;
540 
541  NodePaths::iterator npi;
542  for (npi = _node_paths.begin(); npi != _node_paths.end(); ++npi) {
543  NodePath &np = (*npi);
544  CPT(RenderState) orig_state = np.get_state();
545  StateMap::iterator smi = state_map.find(orig_state);
546  if (smi != state_map.end()) {
547  // This RenderState has already been encountered; reuse it.
548  np.set_state((*smi).second);
549  } else {
550  // This RenderState has not yet been encountered; apply the attrib to
551  // it.
552  np.set_attrib(attrib, priority);
553  state_map[orig_state] = np.get_state();
554  }
555  }
556 }
557 
558 /**
559  * Writes a brief one-line description of the NodePathCollection to the
560  * indicated output stream.
561  */
563 output(std::ostream &out) const {
564  if (get_num_paths() == 1) {
565  out << "1 NodePath";
566  } else {
567  out << get_num_paths() << " NodePaths";
568  }
569 }
570 
571 /**
572  * Writes a complete multi-line description of the NodePathCollection to the
573  * indicated output stream.
574  */
576 write(std::ostream &out, int indent_level) const {
577  for (int i = 0; i < get_num_paths(); i++) {
578  indent(out, indent_level) << get_path(i) << "\n";
579  }
580 }
void ls() const
Lists all the nodes at and below each node in the collection hierarchically.
bool remove_path(const NodePath &node_path)
Removes the indicated NodePath from the collection.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
void set_collide_mask(CollideMask new_mask, CollideMask bits_to_change=CollideMask::all_on(), TypeHandle node_type=TypeHandle::none())
Recursively applies the indicated CollideMask to the into_collide_masks for all nodes at this level a...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:51
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is local to this package only; it doesn't get exported.
NodePathCollection find_all_matches(const std::string &path) const
Returns the complete set of all NodePaths that begin with any NodePath in this collection and can be ...
void unstash()
Unstashes all NodePaths in the collection.
void clear()
Removes all NodePaths from the collection.
bool is_empty() const
Returns true if there are no NodePaths in the collection, false otherwise.
void add_paths_from(const NodePathCollection &other)
Adds all the NodePaths indicated in the other collection to this path.
void remove_paths_from(const NodePathCollection &other)
Removes from this collection all of the NodePaths listed in the other collection.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
This class is local to this package only; it doesn't get exported.
void wrt_reparent_to(const NodePath &other)
Reparents all the NodePaths in the collection to the indicated node, adjusting each transform so as n...
void compose_color_scale(const LVecBase4 &scale, int priority=0)
multiplies the color scale component of the transform, with previous color scale leaving translation ...
Definition: nodePath.cxx:2050
void show()
Shows all NodePaths in the collection.
void hide()
Hides all NodePaths in the collection.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool add_string(const std::string &str_path)
Adds a sequence of components separated by slashes, followed optionally by a semicolon and a sequence...
void set_texture(Texture *tex, int priority=0)
Adds the indicated texture to the list of textures that will be rendered on the default texture stage...
Definition: nodePath.cxx:2871
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void stash()
Stashes all NodePaths in the collection.
void compose_color_scale(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0, int priority=0)
Applies color scales to all NodePaths in the collection.
void set_color_scale(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0, int priority=0)
Applies color scales to all NodePaths in the collection.
bool has_path(const NodePath &path) const
Returns true if the indicated NodePath appears in this collection, false otherwise.
size_t size() const
Returns the number of paths in the collection.
void set_attrib(const RenderAttrib *attrib, int priority=0)
Applies the indicated RenderAttrib to all NodePaths in the collection.
void detach()
Detaches all NodePaths in the collection.
void output(std::ostream &out) const
Writes a brief one-line description of the NodePathCollection to the indicated output stream.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
get_path
Returns the nth NodePath in the collection.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_texture(Texture *tex, int priority=0)
Adds the indicated texture to the list of textures that will be rendered on the default texture stage...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write(std::ostream &out, int indent_level=0) const
Writes a complete multi-line description of the NodePathCollection to the indicated output stream.
void set_texture_off(int priority=0)
Sets the geometry at this level and below to render using no texture, on any stage.
Definition: nodePath.cxx:2961
void set_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a=1.0, int priority=0)
Colors all NodePaths in the collection.
void reserve(size_t num)
This is a hint to Panda to allocate enough memory to hold the given number of NodePaths,...
get_num_paths
Returns the number of NodePaths in the collection.
bool calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point) const
Calculates the minimum and maximum vertices of all Geoms at these NodePath's bottom nodes and below T...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void set_texture_off(int priority=0)
Sets the geometry at this level and below to render using no texture, on any stage.
void ls() const
Lists the hierarchy at and below the referenced node.
Definition: nodePath.I:399
Defines the properties of a named stage of the multitexture pipeline.
Definition: textureStage.h:35
void remove_duplicate_paths()
Removes any duplicate entries of the same NodePaths on this collection.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
void set_state(const RenderState *state, Thread *current_thread=Thread::get_current_thread())
Changes the complete state object on this node.
Definition: nodePath.I:427
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_color_scale(const LVecBase4 &scale, int priority=0)
Sets the color scale component of the transform, leaving translation and rotation untouched.
Definition: nodePath.cxx:2080
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CollideMask get_collide_mask() const
Returns the union of all of the into_collide_masks for nodes at this level and below.
void reparent_to(const NodePath &other)
Reparents all the NodePaths in the collection to the indicated node.
const RenderState * get_state(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete state object set on this node.
Definition: nodePath.cxx:686
NodePath operator [](size_t index) const
Returns the nth NodePath in the collection.
This is a set of zero or more NodePaths.