Panda3D
Loading...
Searching...
No Matches
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"
17#include "textureAttrib.h"
18#include "colorScaleAttrib.h"
19#include "colorAttrib.h"
20#include "indent.h"
21
22using std::max;
23using std::min;
24
25/**
26 * Adds a new NodePath to the collection.
27 */
29add_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 */
48remove_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 */
137has_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 */
150clear() {
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 */
159reserve(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 */
167is_empty() const {
168 return _node_paths.empty();
169}
170
171/**
172 * Returns the number of NodePaths in the collection.
173 */
175get_num_paths() const {
176 return _node_paths.size();
177}
178
179/**
180 * Returns the nth NodePath in the collection.
181 */
183get_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 */
194operator [] (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 */
205size() 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 */
214ls(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 */
229find_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 */
253reparent_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 */
264wrt_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 */
274show() {
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 */
284hide() {
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 */
294stash() {
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 */
304unstash() {
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 */
314detach() {
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 */
328get_collide_mask() const {
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 */
345set_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 */
362calc_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 */
402set_texture(Texture *tex, int priority) {
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 */
415set_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 */
442set_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 */
454set_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 */
478set_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 */
487set_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 */
512compose_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 */
538set_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 */
563output(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 */
576write(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}
This class is local to this package only; it doesn't get exported.
This class is local to this package only; it doesn't get exported.
bool add_string(const std::string &str_path)
Adds a sequence of components separated by slashes, followed optionally by a semicolon and a sequence...
This is a set of zero or more NodePaths.
NodePath operator[](size_t index) const
Returns the nth NodePath in the collection.
void reparent_to(const NodePath &other)
Reparents all the NodePaths in the collection to the indicated node.
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 unstash()
Unstashes all NodePaths in the collection.
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
void set_attrib(const RenderAttrib *attrib, int priority=0)
Applies the indicated RenderAttrib to all NodePaths in the collection.
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 add_paths_from(const NodePathCollection &other)
Adds all the NodePaths indicated in the other collection to this path.
size_t size() const
Returns the number of paths in 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...
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 ls() const
Lists all the nodes at and below each node in the collection hierarchically.
void detach()
Detaches all NodePaths in the collection.
void remove_paths_from(const NodePathCollection &other)
Removes from this collection all of the NodePaths listed in the other collection.
void set_texture_off(int priority=0)
Sets the geometry at this level and below to render using no texture, on any stage.
void remove_duplicate_paths()
Removes any duplicate entries of the same NodePaths on this collection.
void show()
Shows all NodePaths in the collection.
CollideMask get_collide_mask() const
Returns the union of all of the into_collide_masks for nodes at this level and below.
void reserve(size_t num)
This is a hint to Panda to allocate enough memory to hold the given number of NodePaths,...
bool remove_path(const NodePath &node_path)
Removes the indicated NodePath from the collection.
bool is_empty() const
Returns true if there are no NodePaths in the collection, false otherwise.
void stash()
Stashes all NodePaths in the collection.
void hide()
Hides all NodePaths in the collection.
get_num_paths
Returns the number of NodePaths in the collection.
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 output(std::ostream &out) const
Writes a brief one-line description of the NodePathCollection to the indicated output stream.
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.
void wrt_reparent_to(const NodePath &other)
Reparents all the NodePaths in the collection to the indicated node, adjusting each transform so as n...
bool has_path(const NodePath &path) const
Returns true if the indicated NodePath appears in this collection, false otherwise.
get_path
Returns the nth NodePath in the collection.
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...
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...
void clear()
Removes all NodePaths from the collection.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
void compose_color_scale(const LVecBase4 &scale, int priority=0)
multiplies the color scale component of the transform, with previous color scale leaving translation ...
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...
void ls() const
Lists the hierarchy at and below the referenced node.
Definition nodePath.I:399
void set_texture_off(int priority=0)
Sets the geometry at this level and below to render using no texture, on any stage.
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
const RenderState * get_state(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete state object set on this node.
Definition nodePath.cxx:722
void set_color_scale(const LVecBase4 &scale, int priority=0)
Sets the color scale component of the transform, leaving translation and rotation untouched.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
Defines the properties of a named stage of the multitexture pipeline.
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition texture.h:72
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
This is our own Panda specialization on the default STL map.
Definition pmap.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.