/** * 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." * * @file nodePath.I * @author drose * @date 2002-02-25 */ /** * This constructs an empty NodePath with no nodes. */ INLINE NodePath:: NodePath() : _error_type(ET_ok), _backup_key(0) { } /** * This constructs a new NodePath with a single node. An ordinary, unattached * PandaNode is created with the indicated name. */ INLINE NodePath:: NodePath(const std::string &top_node_name, Thread *current_thread) : _error_type(ET_ok) { PandaNode *top_node = new PandaNode(top_node_name); int pipeline_stage = current_thread->get_pipeline_stage(); _head = top_node->get_generic_component(false, pipeline_stage, current_thread); _backup_key = 0; } /** * This constructs a NodePath for the indicated node. If the node does not * have any parents, this creates a singleton NodePath; otherwise, it * automatically finds the path from the node to the root. If the node has * multiple paths to the root, one path is chosen arbitrarily and a warning * message is printed (but see also NodePath::any_path(), below). */ INLINE NodePath:: NodePath(PandaNode *node, Thread *current_thread) : _error_type(ET_ok) { if (node != nullptr) { int pipeline_stage = current_thread->get_pipeline_stage(); _head = node->get_generic_component(false, pipeline_stage, current_thread); } _backup_key = 0; } /** * Returns a new NodePath that represents any arbitrary path from the root to * the indicated node. This is the same thing that would be returned by * NodePath(node), except that no warning is issued if the path is ambiguous. */ INLINE NodePath NodePath:: any_path(PandaNode *node, Thread *current_thread) { NodePath result; if (node != nullptr) { int pipeline_stage = current_thread->get_pipeline_stage(); result._head = node->get_generic_component(true, pipeline_stage, current_thread); } return result; } /** * */ INLINE NodePath:: NodePath(const NodePath ©) : _head(copy._head), _backup_key(copy._backup_key), _error_type(copy._error_type) { } /** * */ INLINE void NodePath:: operator = (const NodePath ©) { _head = copy._head; _backup_key = copy._backup_key; _error_type = copy._error_type; } /** * */ INLINE NodePath:: NodePath(NodePath &&from) noexcept : _head(std::move(from._head)), _backup_key(from._backup_key), _error_type(from._error_type) { } /** * */ INLINE void NodePath:: operator = (NodePath &&from) noexcept { _head = std::move(from._head); _backup_key = from._backup_key; _error_type = from._error_type; } /** * Sets this NodePath to the empty NodePath. It will no longer point to any * node. */ INLINE void NodePath:: clear() { _head.clear(); _backup_key = 0; _error_type = ET_ok; } /** * Creates a NodePath with the ET_not_found error type set. */ INLINE NodePath NodePath:: not_found() { NodePath result; result._error_type = ET_not_found; return result; } /** * Creates a NodePath with the ET_removed error type set. */ INLINE NodePath NodePath:: removed() { NodePath result; result._error_type = ET_removed; return result; } /** * Creates a NodePath with the ET_fail error type set. */ INLINE NodePath NodePath:: fail() { NodePath result; result._error_type = ET_fail; return result; } /** * Certain operations, such as find() or find_all_matches(), require a * traversal of the scene graph to search for the target node or nodes. This * traversal does not attempt to detect cycles, so an arbitrary cap is set on * the depth of the traversal as a poor man's cycle detection, in the event * that a cycle has inadvertently been introduced into the scene graph. * * There may be other reasons you'd want to truncate a search before the * bottom of the scene graph has been reached. In any event, this function * sets the limit on the number of levels that a traversal will continue, and * hence the maximum length of a path that may be returned by a traversal. * * This is a static method, and so changing this parameter affects all of the * NodePaths in the universe. */ INLINE void NodePath:: set_max_search_depth(int max_search_depth) { _max_search_depth = max_search_depth; } /** * Returns the current setting of the search depth limit. See * set_max_search_depth. */ INLINE int NodePath:: get_max_search_depth() { return _max_search_depth; } /** * Returns true if the NodePath contains no nodes. */ INLINE bool NodePath:: is_empty() const { return (_head == nullptr); } /** * Returns true if the NodePath contains exactly one node. */ INLINE bool NodePath:: is_singleton(Thread *current_thread) const { int pipeline_stage = current_thread->get_pipeline_stage(); return (_head != nullptr && _head->is_top_node(pipeline_stage, current_thread)); } /** * If is_empty() is true, this returns a code that represents the reason why * the NodePath is empty. */ INLINE NodePath::ErrorType NodePath:: get_error_type() const { return _error_type; } /** * Returns the top node of the path, or NULL if the path is empty. This * requires iterating through the path. */ INLINE PandaNode *NodePath:: get_top_node(Thread *current_thread) const { if (is_empty()) { return nullptr; } return get_top(current_thread).node(); } /** * Returns the referenced node of the path. */ INLINE PandaNode *NodePath:: node() const { nassertr_always(!is_empty(), nullptr); return _head->get_node(); } /** * Returns an integer that is guaranteed to be the same for all NodePaths that * represent the same node instance, and different for all NodePaths that * represent a different node instance. * * The same key will be returned for a particular instance as long as at least * one NodePath exists that represents that instance; if all NodePaths for a * particular instance destruct and a new one is later created, it may have a * different index. However, a given key will never be reused for a different * instance (unless the app has been running long enough that we overflow the * integer key value). */ INLINE int NodePath:: get_key() const { if (is_empty()) { return _backup_key; } return _head->get_key(); } /** * Adds the NodePath into the running hash. This is intended to be used by * lower-level code that computes a hash for each NodePath. It modifies the * hash value passed in by a unique adjustment for each NodePath, and returns * the modified hash. * * This is similar to the unique integer returned by get_key(), but it is not * guaranteed to remain unique beyond the lifetime of this particular * NodePath. Once this NodePath destructs, a different NodePath may be * created which shares the same hash value. */ INLINE size_t NodePath:: add_hash(size_t hash) const { return pointer_hash::add_hash(hash, _head); } /** * Returns true if the node represented by this NodePath is parented within * the same graph as that of the other NodePath. This is essentially the same * thing as asking whether get_top() of both NodePaths is the same (e.g., both * "render"). */ INLINE bool NodePath:: is_same_graph(const NodePath &other, Thread *current_thread) const { // Actually, it's possible for the top nodes to be the same, but the // NodePaths still to be considered in different graphs. But even in this // case, get_top() will be different for each one. (They'll be different // singleton NodePaths that happen to reference the same node). // This will happen if one of the top nodes is considered a different // instance--for instance, render.instance_to(NodePath()) returns a // different instance of render that appears to have the same top node. But // this is a very rare thing to do. int a_count, b_count; return (find_common_ancestor(*this, other, a_count, b_count, current_thread) != nullptr); } /** * Returns true if the node represented by this NodePath is a parent or other * ancestor of the other NodePath, or false if it is not. */ INLINE bool NodePath:: is_ancestor_of(const NodePath &other, Thread *current_thread) const { int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == nullptr) { // Not related. return false; } // They are related; now b is descended from a only if a is the common // ancestor (which is to say, a_count == 0). return (a_count == 0); } /** * Returns the lowest NodePath that both of these two NodePaths have in * common: the first ancestor that both of them share. If the two NodePaths * are unrelated, returns NodePath::not_found(). */ INLINE NodePath NodePath:: get_common_ancestor(const NodePath &other, Thread *current_thread) const { int a_count, b_count; NodePathComponent *common = find_common_ancestor(*this, other, a_count, b_count, current_thread); if (common == nullptr) { return NodePath::not_found(); } NodePath result; result._head = common; return result; } /** * Returns the number of children of the referenced node. */ INLINE int NodePath:: get_num_children(Thread *current_thread) const { nassertr_always(!is_empty(), 0); return _head->get_node()->get_num_children(current_thread); } /** * Returns a NodePath representing the nth child of the referenced node. */ INLINE NodePath NodePath:: get_child(int n, Thread *current_thread) const { nassertr_always(n >= 0 && n < get_num_children(current_thread), NodePath()); NodePath child; int pipeline_stage = current_thread->get_pipeline_stage(); child._head = PandaNode::get_component(_head, _head->get_node()->get_child(n, current_thread), pipeline_stage, current_thread); return child; } /** * Returns the number of nodes at and below this level. */ INLINE int NodePath:: count_num_descendants() const { if (is_empty()) { return 0; } return _head->get_node()->count_num_descendants(); } /** * Returns true if the referenced node has a parent; i.e. the NodePath chain * contains at least two nodes. */ INLINE bool NodePath:: has_parent(Thread *current_thread) const { return !is_empty() && !is_singleton(current_thread); } /** * Returns the NodePath to the parent of the referenced node: that is, this * NodePath, shortened by one node. The parent of a singleton NodePath is * defined to be the empty NodePath. */ INLINE NodePath NodePath:: get_parent(Thread *current_thread) const { if (!has_parent(current_thread)) { return NodePath(); } int pipeline_stage = current_thread->get_pipeline_stage(); NodePath parent; parent._head = _head->get_next(pipeline_stage, current_thread); return parent; } /** * Creates an ordinary PandaNode and attaches it below the current NodePath, * returning a new NodePath that references it. */ INLINE NodePath NodePath:: attach_new_node(const std::string &name, int sort, Thread *current_thread) const { nassertr(verify_complete(current_thread), NodePath::fail()); return attach_new_node(new PandaNode(name), sort, current_thread); } /** * Lists the hierarchy at and below the referenced node. */ INLINE void NodePath:: ls() const { ls(nout); } /** * Lists the hierarchy at and below the referenced node. */ INLINE void NodePath:: ls(std::ostream &out, int indent_level) const { if (is_empty()) { out << "(empty)\n"; } else { node()->ls(out, indent_level); } } /** * Lists the hierarchy at and above the referenced node. */ INLINE void NodePath:: reverse_ls() const { reverse_ls(nout); } /** * Changes the complete state object on this node. */ INLINE void NodePath:: set_state(const RenderState *state, Thread *current_thread) { nassertv_always(!is_empty()); node()->set_state(state, current_thread); } /** * Returns the net state on this node from the root. */ INLINE CPT(RenderState) NodePath:: get_net_state(Thread *current_thread) const { nassertr(_error_type == ET_ok, RenderState::make_empty()); return r_get_net_state(_head, current_thread); } /** * Adds the indicated render attribute to the scene graph on this node. This * attribute will now apply to this node and everything below. If there was * already an attribute of the same type, it is replaced. */ INLINE void NodePath:: set_attrib(const RenderAttrib *attrib, int priority) { nassertv_always(!is_empty()); node()->set_attrib(attrib, priority); } /** * Returns the render attribute of the indicated type, if it is defined on the * node, or NULL if it is not. This checks only what is set on this * particular node level, and has nothing to do with what render attributes * may be inherited from parent nodes. */ INLINE const RenderAttrib *NodePath:: get_attrib(TypeHandle type) const { nassertr_always(!is_empty(), nullptr); return node()->get_attrib(type); } /** * Returns true if there is a render attribute of the indicated type defined * on this node, or false if there is not. */ INLINE bool NodePath:: has_attrib(TypeHandle type) const { nassertr_always(!is_empty(), false); return node()->has_attrib(type); } /** * Removes the render attribute of the given type from this node. This node, * and the subgraph below, will now inherit the indicated render attribute * from the nodes above this one. */ INLINE void NodePath:: clear_attrib(TypeHandle type) { nassertv_always(!is_empty()); node()->clear_attrib(type); } /** * Adds the indicated render effect to the scene graph on this node. If there * was already an effect of the same type, it is replaced. */ INLINE void NodePath:: set_effect(const RenderEffect *effect) { nassertv_always(!is_empty()); node()->set_effect(effect); } /** * Returns the render effect of the indicated type, if it is defined on the * node, or NULL if it is not. */ INLINE const RenderEffect *NodePath:: get_effect(TypeHandle type) const { nassertr_always(!is_empty(), nullptr); return node()->get_effect(type); } /** * Returns true if there is a render effect of the indicated type defined on * this node, or false if there is not. */ INLINE bool NodePath:: has_effect(TypeHandle type) const { nassertr_always(!is_empty(), false); return node()->has_effect(type); } /** * Removes the render effect of the given type from this node. */ INLINE void NodePath:: clear_effect(TypeHandle type) { nassertv_always(!is_empty()); node()->clear_effect(type); } /** * Sets the complete RenderEffects that will be applied this node. This * completely replaces whatever has been set on this node via repeated calls * to set_attrib(). */ INLINE void NodePath:: set_effects(const RenderEffects *effects) { nassertv_always(!is_empty()); node()->set_effects(effects); } /** * Returns the complete RenderEffects that will be applied to this node. */ INLINE const RenderEffects *NodePath:: get_effects() const { nassertr_always(!is_empty(), RenderEffects::make_empty()); return node()->get_effects(); } /** * Resets this node to have no render effects. */ INLINE void NodePath:: clear_effects() { nassertv_always(!is_empty()); node()->clear_effects(); } /** * Sets the transform object on this node to identity. */ INLINE void NodePath:: clear_transform(Thread *current_thread) { set_transform(TransformState::make_identity(), current_thread); } /** * Changes the complete transform object on this node. */ INLINE void NodePath:: set_transform(const TransformState *transform, Thread *current_thread) { nassertv_always(!is_empty()); node()->set_transform(transform, current_thread); } /** * Sets the transform object on this node to identity, relative to the other * node. This effectively places this node at the same position as the other * node. */ INLINE void NodePath:: clear_transform(const NodePath &other, Thread *current_thread) { set_transform(other, TransformState::make_identity(), current_thread); } /** * Returns the net transform on this node from the root. */ INLINE CPT(TransformState) NodePath:: get_net_transform(Thread *current_thread) const { nassertr(_error_type == ET_ok, TransformState::make_identity()); return r_get_net_transform(_head, current_thread); } /** * Sets the transform that represents this node's "previous" position, one * frame ago, for the purposes of detecting motion for accurate collision * calculations. */ INLINE void NodePath:: set_prev_transform(const TransformState *transform, Thread *current_thread) { nassertv_always(!is_empty()); node()->set_prev_transform(transform, current_thread); } /** * Returns the net "previous" transform on this node from the root. See * set_prev_transform(). */ INLINE CPT(TransformState) NodePath:: get_net_prev_transform(Thread *current_thread) const { nassertr(_error_type == ET_ok, TransformState::make_identity()); return r_get_net_prev_transform(_head, current_thread); } /** * Sets the translation component of the transform, leaving rotation and scale * untouched. This also resets the node's "previous" position, so that the * collision system will see the node as having suddenly appeared in the new * position, without passing any points in between. */ INLINE void NodePath:: set_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { set_pos(LPoint3(x, y, z)); } /** * Sets the translation component, without changing the "previous" position, * so that the collision system will see the node as moving fluidly from its * previous position to its new position. */ INLINE void NodePath:: set_fluid_pos(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { set_fluid_pos(LPoint3(x, y, z)); } INLINE PN_stdfloat NodePath:: get_x() const { return get_pos()[0]; } INLINE PN_stdfloat NodePath:: get_y() const { return get_pos()[1]; } INLINE PN_stdfloat NodePath:: get_z() const { return get_pos()[2]; } /** * Sets the rotation component of the transform, leaving translation and scale * untouched. */ INLINE void NodePath:: set_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) { set_hpr(LVecBase3(h, p, r)); } INLINE PN_stdfloat NodePath:: get_h() const { return get_hpr()[0]; } INLINE PN_stdfloat NodePath:: get_p() const { return get_hpr()[1]; } INLINE PN_stdfloat NodePath:: get_r() const { return get_hpr()[2]; } /** * Sets the scale component of the transform, leaving translation and rotation * untouched. */ INLINE void NodePath:: set_scale(PN_stdfloat scale) { set_scale(LVecBase3(scale, scale, scale)); } INLINE void NodePath:: set_scale(PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz) { set_scale(LVecBase3(sx, sy, sz)); } INLINE PN_stdfloat NodePath:: get_sx() const { return get_scale()[0]; } INLINE PN_stdfloat NodePath:: get_sy() const { return get_scale()[1]; } INLINE PN_stdfloat NodePath:: get_sz() const { return get_scale()[2]; } /** * Sets the shear component of the transform, leaving translation, rotation, * and scale untouched. */ INLINE void NodePath:: set_shear(PN_stdfloat shxy, PN_stdfloat shxz, PN_stdfloat shyz) { set_shear(LVecBase3(shxy, shxz, shyz)); } INLINE PN_stdfloat NodePath:: get_shxy() const { return get_shear()[0]; } INLINE PN_stdfloat NodePath:: get_shxz() const { return get_shear()[1]; } INLINE PN_stdfloat NodePath:: get_shyz() const { return get_shear()[2]; } /** * Sets the translation and rotation component of the transform, leaving scale * untouched. */ INLINE void NodePath:: set_pos_hpr(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) { set_pos_hpr(LVecBase3(x, y, z), LVecBase3(h, p, r)); } /** * Sets the rotation and scale components of the transform, leaving * translation untouched. */ INLINE void NodePath:: set_hpr_scale(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz) { set_hpr_scale(LVecBase3(h, p, r), LVecBase3(sx, sy, sz)); } /** * Completely replaces the transform with new translation, rotation, and scale * components. */ INLINE void NodePath:: set_pos_hpr_scale(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz) { set_pos_hpr_scale(LVecBase3(x, y, z), LVecBase3(h, p, r), LVecBase3(sx, sy, sz)); } /** * Completely removes any transform from the referenced node. */ INLINE void NodePath:: clear_mat() { nassertv_always(!is_empty()); node()->clear_transform(); } /** * Returns true if a non-identity transform matrix has been applied to the * referenced node, false otherwise. */ INLINE bool NodePath:: has_mat() const { nassertr_always(!is_empty(), false); return !node()->get_transform()->is_identity(); } /** * Returns the transform matrix that has been applied to the referenced node, * or the identity matrix if no matrix has been applied. */ INLINE const LMatrix4 &NodePath:: get_mat() const { nassertr_always(!is_empty(), LMatrix4::ident_mat()); return node()->get_transform()->get_mat(); } /** * Sets the transform on this NodePath so that it rotates to face the * indicated point in space. This will overwrite any previously existing * scale on the node, although it will preserve any translation. */ INLINE void NodePath:: look_at(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { look_at(LPoint3(x, y, z)); } /** * Behaves like look_at(), but with a strong preference to keeping the up * vector oriented in the indicated "up" direction. */ INLINE void NodePath:: heads_up(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { heads_up(LPoint3(x, y, z)); } /** * Sets the translation component of the transform, relative to the other * node. */ INLINE void NodePath:: set_pos(const NodePath &other, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { set_pos(other, LPoint3(x, y, z)); } /** * Sets the translation component, without changing the "previous" position, * so that the collision system will see the node as moving fluidly from its * previous position to its new position. */ INLINE void NodePath:: set_fluid_pos(const NodePath &other, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { set_fluid_pos(other, LPoint3(x, y, z)); } INLINE PN_stdfloat NodePath:: get_x(const NodePath &other) const { return get_pos(other)[0]; } INLINE PN_stdfloat NodePath:: get_y(const NodePath &other) const { return get_pos(other)[1]; } INLINE PN_stdfloat NodePath:: get_z(const NodePath &other) const { return get_pos(other)[2]; } /** * Sets the rotation component of the transform, relative to the other node. */ INLINE void NodePath:: set_hpr(const NodePath &other, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) { set_hpr(other, LPoint3(h, p, r)); } INLINE PN_stdfloat NodePath:: get_h(const NodePath &other) const { return get_hpr(other)[0]; } INLINE PN_stdfloat NodePath:: get_p(const NodePath &other) const { return get_hpr(other)[1]; } INLINE PN_stdfloat NodePath:: get_r(const NodePath &other) const { return get_hpr(other)[2]; } /** * Sets the scale component of the transform, relative to the other node. */ INLINE void NodePath:: set_scale(const NodePath &other, PN_stdfloat scale) { set_scale(other, LPoint3(scale, scale, scale)); } /** * Sets the scale component of the transform, relative to the other node. */ INLINE void NodePath:: set_scale(const NodePath &other, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz) { set_scale(other, LPoint3(sx, sy, sz)); } /** * Returns the relative scale of the referenced node as seen from the other * node. */ INLINE PN_stdfloat NodePath:: get_sx(const NodePath &other) const { return get_scale(other)[0]; } INLINE PN_stdfloat NodePath:: get_sy(const NodePath &other) const { return get_scale(other)[1]; } INLINE PN_stdfloat NodePath:: get_sz(const NodePath &other) const { return get_scale(other)[2]; } /** * Sets the shear component of the transform, relative to the other node. */ INLINE void NodePath:: set_shear(const NodePath &other, PN_stdfloat shxy, PN_stdfloat shxz, PN_stdfloat shyz) { set_shear(other, LPoint3(shxy, shxz, shyz)); } /** * Returns the relative shear of the referenced node as seen from the other * node. */ INLINE PN_stdfloat NodePath:: get_shxy(const NodePath &other) const { return get_shear(other)[0]; } INLINE PN_stdfloat NodePath:: get_shxz(const NodePath &other) const { return get_shear(other)[1]; } INLINE PN_stdfloat NodePath:: get_shyz(const NodePath &other) const { return get_shear(other)[2]; } /** * Sets the translation and rotation component of the transform, relative to * the other node. */ INLINE void NodePath:: set_pos_hpr(const NodePath &other, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) { set_pos_hpr(other, LVecBase3(x, y, z), LVecBase3(h, p, r)); } /** * Sets the rotation and scale components of the transform, leaving * translation untouched. This, or set_pos_hpr_scale, is the preferred way to * update a transform when both hpr and scale are to be changed. */ INLINE void NodePath:: set_hpr_scale(const NodePath &other, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz) { set_hpr_scale(other, LVecBase3(h, p, r), LVecBase3(sx, sy, sz)); } /** * Completely replaces the transform with new translation, rotation, and scale * components, relative to the other node. */ INLINE void NodePath:: set_pos_hpr_scale(const NodePath &other, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r, PN_stdfloat sx, PN_stdfloat sy, PN_stdfloat sz) { set_pos_hpr_scale(other, LVecBase3(x, y, z), LVecBase3(h, p, r), LVecBase3(sx, sy, sz)); } /** * Sets the hpr on this NodePath so that it rotates to face the indicated * point in space, which is relative to the other NodePath. */ INLINE void NodePath:: look_at(const NodePath &other, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { look_at(other, LPoint3(x, y, z)); } /** * Behaves like look_at(), but with a strong preference to keeping the up * vector oriented in the indicated "up" direction. */ INLINE void NodePath:: heads_up(const NodePath &other, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) { heads_up(other, LPoint3(x, y, z)); } /** * Returns the straight-line distance between this referenced node's * coordinate frame's origin, and that of the other node's origin. */ INLINE PN_stdfloat NodePath:: get_distance(const NodePath &other) const { LPoint3 pos = get_pos(other); return length(LVector3(pos)); } /** * Sets the color scale component of the transform */ INLINE void NodePath:: set_color_scale(PN_stdfloat sr, PN_stdfloat sg, PN_stdfloat sb, PN_stdfloat sa, int priority) { set_color_scale(LVecBase4(sr, sg, sb, sa), priority); } /** * Sets the color scale component of the transform */ INLINE void NodePath:: compose_color_scale(PN_stdfloat sr, PN_stdfloat sg, PN_stdfloat sb, PN_stdfloat sa, int priority) { compose_color_scale(LVecBase4(sr, sg, sb, sa), priority); } /** * Sets the red scale component of the transform */ INLINE void NodePath:: set_sr(PN_stdfloat sr) { LVecBase4 new_scale = get_color_scale(); new_scale[0] = sr; set_color_scale(new_scale); } /** * Sets the alpha scale component of the transform */ INLINE void NodePath:: set_sg(PN_stdfloat sg) { LVecBase4 new_scale = get_color_scale(); new_scale[1] = sg; set_color_scale(new_scale); } /** * Sets the blue scale component of the transform */ INLINE void NodePath:: set_sb(PN_stdfloat sb) { LVecBase4 new_scale = get_color_scale(); new_scale[2] = sb; set_color_scale(new_scale); } /** * Sets the alpha scale component of the transform */ INLINE void NodePath:: set_sa(PN_stdfloat sa) { LVecBase4 new_scale = get_color_scale(); new_scale[3] = sa; set_color_scale(new_scale); } /** * Gets the red scale component of the transform */ INLINE PN_stdfloat NodePath:: get_sr() const { return get_color_scale()[0]; } /** * Gets the green scale component of the transform */ INLINE PN_stdfloat NodePath:: get_sg() const { return get_color_scale()[1]; } /** * Gets the blue scale component of the transform */ INLINE PN_stdfloat NodePath:: get_sb() const { return get_color_scale()[2]; } /** * Gets the alpha scale component of the transform */ INLINE PN_stdfloat NodePath:: get_sa() const { return get_color_scale()[3]; } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_int &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4i &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3i &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2i &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase4i &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase3i &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase2i &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) { set_shader_input(ShaderInput(std::move(id), v, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, int priority) { set_shader_input(ShaderInput(std::move(id), tex, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority) { set_shader_input(ShaderInput(std::move(id), tex, sampler, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z, int n, int priority) { set_shader_input(ShaderInput(std::move(id), tex, read, write, z, n, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority) { set_shader_input(ShaderInput(std::move(id), buf, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const NodePath &np, int priority) { set_shader_input(ShaderInput(std::move(id), np, priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, int n1, int n2, int n3, int n4, int priority) { set_shader_input(ShaderInput(std::move(id), LVecBase4i(n1, n2, n3, n4), priority)); } /** * */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, PN_stdfloat n1, PN_stdfloat n2, PN_stdfloat n3, PN_stdfloat n4, int priority) { set_shader_input(ShaderInput(std::move(id), LVecBase4(n1, n2, n3, n4), priority)); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_offset(TextureStage *stage, PN_stdfloat u, PN_stdfloat v) { set_tex_offset(stage, LVecBase2(u, v)); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_offset(TextureStage *stage, const LVecBase2 &uv) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_pos2d(uv)); } /** * Sets a texture matrix on the current node to apply the indicated rotation, * clockwise in degrees, to UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_rotate(TextureStage *stage, PN_stdfloat r) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_rotate2d(r)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UVW's for the given stage. * * This call is appropriate for 2-d or 3-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(TextureStage *stage, PN_stdfloat scale) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_scale(scale)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(TextureStage *stage, PN_stdfloat su, PN_stdfloat sv) { set_tex_scale(stage, LVecBase2(su, sv)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(TextureStage *stage, const LVecBase2 &scale) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_scale2d(scale)); } /** * Returns the offset set for the UV's for the given stage on the current * node. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE LVecBase2 NodePath:: get_tex_offset(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2::zero()); return get_tex_transform(stage)->get_pos2d(); } /** * Returns the rotation set for the UV's for the given stage on the current * node. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE PN_stdfloat NodePath:: get_tex_rotate(TextureStage *stage) const { nassertr_always(!is_empty(), 0.0f); return get_tex_transform(stage)->get_rotate2d(); } /** * Returns the scale set for the UV's for the given stage on the current node. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE LVecBase2 NodePath:: get_tex_scale(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2(1.0f, 1.0f)); return get_tex_transform(stage)->get_scale2d(); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_pos(TextureStage *stage, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) { set_tex_pos(stage, LVecBase3(u, v, w)); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_pos(TextureStage *stage, const LVecBase3 &uvw) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_pos(uvw)); } /** * Sets a texture matrix on the current node to apply the indicated rotation, * as a 3-D HPR, to UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_hpr(TextureStage *stage, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) { set_tex_hpr(stage, LVecBase3(h, p, r)); } /** * Sets a texture matrix on the current node to apply the indicated rotation, * as a 3-D HPR, to UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_hpr(TextureStage *stage, const LVecBase3 &hpr) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_hpr(hpr)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(TextureStage *stage, PN_stdfloat su, PN_stdfloat sv, PN_stdfloat sw) { set_tex_scale(stage, LVecBase3(su, sv, sw)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(TextureStage *stage, const LVecBase3 &scale) { nassertv_always(!is_empty()); set_tex_transform(stage, get_tex_transform(stage)->set_scale(scale)); } /** * Returns the offset set for the UVW's for the given stage on the current * node. * * This call is appropriate for 3-d texture coordinates. */ INLINE LVecBase3 NodePath:: get_tex_pos(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase3::zero()); return get_tex_transform(stage)->get_pos(); } /** * Returns the 3-D HPR set for the UVW's for the given stage on the current * node. * * This call is appropriate for 3-d texture coordinates. */ INLINE LVecBase3 NodePath:: get_tex_hpr(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase3::zero()); return get_tex_transform(stage)->get_hpr(); } /** * Returns the scale set for the UVW's for the given stage on the current * node. * * This call is appropriate for 3-d texture coordinates. */ INLINE LVecBase3 NodePath:: get_tex_scale_3d(TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase3(1.0f, 1.0f, 1.0f)); return get_tex_transform(stage)->get_scale(); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_offset(const NodePath &other, TextureStage *stage, PN_stdfloat u, PN_stdfloat v) { set_tex_offset(other, stage, LVecBase2(u, v)); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_offset(const NodePath &other, TextureStage *stage, const LVecBase2 &uv) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(other, stage)->set_pos2d(uv)); } /** * Sets a texture matrix on the current node to apply the indicated rotation, * clockwise in degrees, to UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_rotate(const NodePath &other, TextureStage *stage, PN_stdfloat r) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(other, stage)->set_rotate2d(r)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UV's for the given stage. * * This call is appropriate for 2-d or 3-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(const NodePath &other, TextureStage *stage, PN_stdfloat scale) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(stage)->set_scale(scale)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(const NodePath &other, TextureStage *stage, PN_stdfloat su, PN_stdfloat sv) { set_tex_scale(other, stage, LVecBase2(su, sv)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UV's for the given stage. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(const NodePath &other, TextureStage *stage, const LVecBase2 &scale) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(stage)->set_scale2d(scale)); } /** * Returns the offset set for the UV's for the given stage on the current * node. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE LVecBase2 NodePath:: get_tex_offset(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2::zero()); return get_tex_transform(other, stage)->get_pos2d(); } /** * Returns the rotation set for the UV's for the given stage on the current * node. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE PN_stdfloat NodePath:: get_tex_rotate(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), 0.0f); return get_tex_transform(other, stage)->get_rotate2d(); } /** * Returns the scale set for the UV's for the given stage on the current node. * * This call is appropriate for ordinary 2-d texture coordinates. */ INLINE LVecBase2 NodePath:: get_tex_scale(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase2(1.0f, 1.0f)); return get_tex_transform(other, stage)->get_scale2d(); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_pos(const NodePath &other, TextureStage *stage, PN_stdfloat u, PN_stdfloat v, PN_stdfloat w) { set_tex_pos(other, stage, LVecBase3(u, v, w)); } /** * Sets a texture matrix on the current node to apply the indicated offset to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_pos(const NodePath &other, TextureStage *stage, const LVecBase3 &uvw) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(stage)->set_pos(uvw)); } /** * Sets a texture matrix on the current node to apply the indicated rotation, * as a 3-D HPR, to UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_hpr(const NodePath &other, TextureStage *stage, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r) { set_tex_hpr(other, stage, LVecBase3(h, p, r)); } /** * Sets a texture matrix on the current node to apply the indicated rotation, * as a 3-D HPR, to UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_hpr(const NodePath &other, TextureStage *stage, const LVecBase3 &hpr) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(stage)->set_hpr(hpr)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(const NodePath &other, TextureStage *stage, PN_stdfloat su, PN_stdfloat sv, PN_stdfloat sw) { set_tex_scale(other, stage, LVecBase3(su, sv, sw)); } /** * Sets a texture matrix on the current node to apply the indicated scale to * UVW's for the given stage. * * This call is appropriate for 3-d texture coordinates. */ INLINE void NodePath:: set_tex_scale(const NodePath &other, TextureStage *stage, const LVecBase3 &scale) { nassertv_always(!is_empty()); set_tex_transform(other, stage, get_tex_transform(stage)->set_scale(scale)); } /** * Returns the offset set for the UVW's for the given stage on the current * node. * * This call is appropriate for 3-d texture coordinates. */ INLINE LVecBase3 NodePath:: get_tex_pos(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase3::zero()); return get_tex_transform(stage)->get_pos(); } /** * Returns the 3-D HPR set for the UVW's for the given stage on the current * node. * * This call is appropriate for 3-d texture coordinates. */ INLINE LVecBase3 NodePath:: get_tex_hpr(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase3::zero()); return get_tex_transform(stage)->get_hpr(); } /** * Returns the scale set for the UVW's for the given stage on the current * node. * * This call is appropriate for 3-d texture coordinates. */ INLINE LVecBase3 NodePath:: get_tex_scale_3d(const NodePath &other, TextureStage *stage) const { nassertr_always(!is_empty(), LVecBase3(1.0f, 1.0f, 1.0f)); return get_tex_transform(stage)->get_scale(); } /** * Undoes the effect of project_texture(). */ INLINE void NodePath:: clear_project_texture(TextureStage *stage) { clear_texture(stage); clear_tex_gen(stage); clear_tex_projector(stage); } /** * Returns true if there are at least some vertices at this node and below * that use the named texture coordinate set, false otherwise. Pass the empty * string for the default texture coordinate set. */ INLINE bool NodePath:: has_texcoord(const std::string &texcoord_name) const { return has_vertex_column(InternalName::get_texcoord_name(texcoord_name)); } /** * Puts a billboard transition on the node such that it will rotate in two * dimensions around the up axis. */ INLINE void NodePath:: set_billboard_axis(PN_stdfloat offset) { set_billboard_axis(NodePath(), offset); } /** * Puts a billboard transition on the node such that it will rotate in three * dimensions about the origin, keeping its up vector oriented to the top of * the camera. */ INLINE void NodePath:: set_billboard_point_eye(PN_stdfloat offset, bool fixed_depth) { set_billboard_point_eye(NodePath(), offset, fixed_depth); } /** * Puts a billboard transition on the node such that it will rotate in three * dimensions about the origin, keeping its up vector oriented to the sky. */ INLINE void NodePath:: set_billboard_point_world(PN_stdfloat offset) { set_billboard_point_world(NodePath(), offset); } /** * Adds the indicated adjustment amount (which may be negative) to the * priority for all transitions on the referenced node, and for all nodes in * the subgraph below. This can be used to force these nodes not to be * overridden by a high-level state change above. If the priority would drop * below zero, it is set to zero. */ INLINE void NodePath:: adjust_all_priorities(int adjustment) { nassertv_always(!is_empty()); r_adjust_all_priorities(node(), adjustment); } /** * Undoes the effect of a previous hide() on this node: makes the referenced * node (and the entire subgraph below this node) visible to all cameras. * * This will not reveal the node if a parent node has been hidden. */ INLINE void NodePath:: show() { nassertv_always(!is_empty()); node()->adjust_draw_mask(DrawMask::all_off(), DrawMask::all_off(), PandaNode::get_overall_bit()); } /** * Makes the referenced node visible just to the cameras whose camera_mask * shares the indicated bits. * * This undoes the effect of a previous hide() call. It will not reveal the * node if a parent node has been hidden. However, see show_through(). */ INLINE void NodePath:: show(DrawMask camera_mask) { nassertv_always(!is_empty()); camera_mask &= ~PandaNode::get_overall_bit(); node()->adjust_draw_mask(DrawMask::all_off(), DrawMask::all_off(), camera_mask); } /** * Makes the referenced node visible just to the cameras whose camera_mask * shares the indicated bits. * * Unlike show(), this will reveal the node even if a parent node has been * hidden, thus "showing through" a parent's hide(). */ INLINE void NodePath:: show_through() { nassertv_always(!is_empty()); node()->adjust_draw_mask(PandaNode::get_overall_bit(), DrawMask::all_off(), DrawMask::all_off()); } /** * Makes the referenced node visible just to the cameras whose camera_mask * shares the indicated bits. * * Unlike show(), this will reveal the node even if a parent node has been * hidden via the one-parameter hide() method, thus "showing through" a * parent's hide(). (However, it will not show through a parent's hide() call * if the no-parameter form of hide() was used.) */ INLINE void NodePath:: show_through(DrawMask camera_mask) { nassertv_always(!is_empty()); camera_mask &= ~PandaNode::get_overall_bit(); node()->adjust_draw_mask(camera_mask, DrawMask::all_off(), DrawMask::all_off()); } /** * Makes the referenced node (and the entire subgraph below this node) * invisible to all cameras. It remains part of the scene graph, its bounding * volume still contributes to its parent's bounding volume, and it will still * be involved in collision tests. */ INLINE void NodePath:: hide() { nassertv_always(!is_empty()); node()->adjust_draw_mask(DrawMask::all_off(), PandaNode::get_overall_bit(), DrawMask::all_off()); } /** * Makes the referenced node invisible just to the cameras whose camera_mask * shares the indicated bits. * * This will also hide any nodes below this node in the scene graph, including * those nodes for which show() has been called, but it will not hide * descendent nodes for which show_through() has been called. */ INLINE void NodePath:: hide(DrawMask camera_mask) { nassertv_always(!is_empty()); camera_mask &= ~PandaNode::get_overall_bit(); node()->adjust_draw_mask(DrawMask::all_off(), camera_mask, DrawMask::all_off()); } /** * Returns true if the referenced node is hidden from the indicated camera(s) * either directly, or because some ancestor is hidden. */ INLINE bool NodePath:: is_hidden(DrawMask camera_mask) const { return !get_hidden_ancestor(camera_mask).is_empty(); } /** * Returns true if the referenced node is stashed either directly, or because * some ancestor is stashed. */ INLINE bool NodePath:: is_stashed() const { return !get_stashed_ancestor().is_empty(); } /** * Returns the union of all of the into_collide_masks for nodes at this level * and below. This is the same thing as node()->get_net_collide_mask(). * * If you want to return what the into_collide_mask of this node itself is, * without regard to its children, use node()->get_into_collide_mask(). */ INLINE CollideMask NodePath:: get_collide_mask() const { nassertr_always(!is_empty(), CollideMask::all_off()); return node()->get_net_collide_mask(); } /** * Recursively applies the indicated CollideMask to the into_collide_masks for * all nodes at this level and below. If node_type is not TypeHandle::none(), * then only nodes matching (or inheriting from) the indicated PandaNode * subclass are modified. * * The default is to change all bits, but if bits_to_change is not all bits * on, then only the bits that are set in bits_to_change are modified, * allowing this call to change only a subset of the bits in the subgraph. */ INLINE void NodePath:: set_collide_mask(CollideMask new_mask, CollideMask bits_to_change, TypeHandle node_type) { nassertv_always(!is_empty()); if (node_type == TypeHandle::none()) { node_type = PandaNode::get_class_type(); } r_set_collide_mask(node(), ~bits_to_change, new_mask & bits_to_change, node_type); } /** * Returns true if the two paths are equivalent; that is, if they contain the * same list of nodes in the same order. */ INLINE bool NodePath:: operator == (const NodePath &other) const { return _head == other._head; } /** * Returns true if the two paths are not equivalent. */ INLINE bool NodePath:: operator != (const NodePath &other) const { return _head != other._head; } /** * Returns true if this NodePath sorts before the other one, false otherwise. * The sorting order of two nonequivalent NodePaths is consistent but * undefined, and is useful only for storing NodePaths in a sorted container * like an STL set. */ INLINE bool NodePath:: operator < (const NodePath &other) const { return _head < other._head; } /** * Returns a number less than zero if this NodePath sorts before the other * one, greater than zero if it sorts after, or zero if they are equivalent. * * Two NodePaths are considered equivalent if they consist of exactly the same * list of nodes in the same order. Otherwise, they are different; different * NodePaths will be ranked in a consistent but undefined ordering; the * ordering is useful only for placing the NodePaths in a sorted container * like an STL set. */ INLINE int NodePath:: compare_to(const NodePath &other) const { // Nowadays, the NodePathComponents at the head are pointerwise equivalent // if and only if the NodePaths are equivalent. So we only have to compare // pointers. if (_head != other._head) { return _head < other._head ? -1 : 1; } return 0; } /** * Recursively walks through the scene graph at this level and below, looking * for ModelNodes, and calls model_node->set_preserve_transform(PT_drop_node) * on each one. This allows a subsequent call to flatten_strong() to * eliminate all of the ModelNodes. * * Returns the number of ModelNodes found. */ INLINE int NodePath:: clear_model_nodes() { nassertr_always(!is_empty(), 0); return r_clear_model_nodes(node()); } /** * Associates a user-defined value with a user-defined key which is stored on * the node. This value has no meaning to Panda; but it is stored * indefinitely on the node until it is requested again. * * Each unique key stores a different string value. There is no effective * limit on the number of different keys that may be stored or on the length * of any one key's value. */ INLINE void NodePath:: set_tag(const std::string &key, const std::string &value) { nassertv_always(!is_empty()); node()->set_tag(key, value); } /** * Retrieves the user-defined value that was previously set on this node for * the particular key, if any. If no value has been previously set, returns * the empty string. See also get_net_tag(). */ INLINE std::string NodePath:: get_tag(const std::string &key) const { // An empty NodePath quietly returns no tags. This makes get_net_tag() // easier to implement. if (is_empty()) { return std::string(); } return node()->get_tag(key); } /** * Fills the given vector up with the list of tags on this PandaNode. * * It is the user's responsibility to ensure that the keys vector is empty * before making this call; otherwise, the new files will be appended to it. */ INLINE void NodePath:: get_tag_keys(vector_string &keys) const { nassertv_always(!is_empty()); node()->get_tag_keys(keys); } /** * Returns true if a value has been defined on this node for the particular * key (even if that value is the empty string), or false if no value has been * set. See also has_net_tag(). */ INLINE bool NodePath:: has_tag(const std::string &key) const { // An empty NodePath quietly has no tags. This makes has_net_tag() easier // to implement. if (is_empty()) { return false; } return node()->has_tag(key); } /** * Removes the value defined for this key on this particular node. After a * call to clear_tag(), has_tag() will return false for the indicated key. */ INLINE void NodePath:: clear_tag(const std::string &key) { nassertv_always(!is_empty()); node()->clear_tag(key); } /** * Returns the tag value that has been defined on this node, or the nearest * ancestor node, for the indicated key. If no value has been defined for the * indicated key on any ancestor node, returns the empty string. See also * get_tag(). */ INLINE std::string NodePath:: get_net_tag(const std::string &key) const { return find_net_tag(key).get_tag(key); } /** * Returns true if the indicated tag value has been defined on this node or on * any ancestor node, or false otherwise. See also has_tag(). */ INLINE bool NodePath:: has_net_tag(const std::string &key) const { return !find_net_tag(key).is_empty(); } /** * Lists the tags to the nout stream, one per line. See * PandaNode::list_tags() for a variant that allows you to specify the output * stream. */ INLINE void NodePath:: list_tags() const { nassertv_always(!is_empty()); node()->list_tags(nout); nout << "\n"; } /** * Changes the name of the referenced node. */ INLINE void NodePath:: set_name(const std::string &name) { nassertv_always(!is_empty()); node()->set_name(name); } /** * Returns the name of the referenced node. */ INLINE std::string NodePath:: get_name() const { nassertr_always(!is_empty(), std::string()); return node()->get_name(); } /** * Converts the NodePath object into a single stream of data using a * BamWriter, and returns that data as a string string. Returns empty string * on failure. This is similar to write_bam_stream(). * * This method is used by __reduce__ to handle streaming of NodePaths to a * pickle file. */ INLINE vector_uchar NodePath:: encode_to_bam_stream() const { vector_uchar data; if (!encode_to_bam_stream(data)) { data.clear(); } return data; } INLINE std::ostream &operator << (std::ostream &out, const NodePath &node_path) { node_path.output(out); return out; }